Adding node to linked list - c#

I want to implement simple Linked list and adding items and its seems that my Add function get into endless loop and i don't know why
public class IntNode
{
private int _value;
private IntNode _next;
public IntNode(int val, IntNode n)
{
_value = val;
_next = n;
}
public int getValue()
{
return _value;
}
public IntNode getNext()
{
return _next;
}
public void setValue(int v)
{
_value = v;
}
public void setNext(IntNode next)
{
_next = next;
}
public string ToString()
{
return _value.ToString();
}
}
public class IntList
{
private IntNode _head;
public static int count;
public IntList()
{
_head = null;
count = 0;
}
public IntList(IntNode node)
{
_head = node;
}
public void Add(IntNode node)
{
if (_head == null)
_head = node;
else
{
for (IntNode p = _head; p.getNext() != null; p.getNext()) { }
_head.setNext(node);
count++;
}
}
public void ToString()
{
IntNode cur = _head;
while (cur.getNext() != null)
{
Console.WriteLine(cur.ToString());
cur = cur.getNext();
}
}
}
main
static void Main(string[] args)
{
IntList list = new IntList();
list.Add(new IntNode(5, null));
list.Add(new IntNode(2, null));
list.Add(new IntNode(8, null));
list.Add(new IntNode(1, null));
list.ToString();
}

The problem is the increment step in the for loop. It needs to be p = p.getNext() not simply p.getNext(). The latter just calls the getNext function and does nothing with the return which means p is never modified and hence the loop doesn't make any progress
for (IntNode p = _head; p.getNext() != null; p = p.getNext()) { }
The next problem is you are not actually moving _head or using the p value. Hence you haven't actually found the place to insert. What you need is something like the following
IntNode p = _head;
while (p.getNext() != null) {
p = p.getNext();
}
p.setNext(node);

for (IntNode p = _head; p.getNext() != null; p.getNext()) { }
You're not using p anywhere, and not doing anything in the loop body. Can you spot your problem?

First, you don't assign the result of getNext() anywhere:
for (IntNode p = _head; p.getNext() != null; p.getNext()) { }
Second, you even don't use the last node anywhere. In fact, you even couldn't, because p doesn't exist outside of the for loop…
Advice: Keep a reference to the last node as well and make your life simpler.

Your loop never ends because p is not incremented.
It should be easier for you if you keep a reference to the last inserted item. For example :
private IntNode _lastNode;
public void Add(IntNode node)
{
if (_head == null)
_head = node;
else
{
if (_lastNode == null)
_lastNode = _head;
_lastNode.setNext(node)
_lastNode = node;
}
count++;
}
You won't have to loop through nodes each time you try to add a node.

Related

Need to generate Syntax for an Enqueue and Dequeue method, to run a Unit Test in Visual Studio

A list of instructions, and the code I have so far.
The issue I'm running into with this so far is that my Enqueue method or my Dequeue method in C# is not operating correctly, and it's not passing the UnitTest created for the assignment.
The Unit test should be able to take the Enqueue method, and the Dequeue method and put a 5 character array into the stack one at a time.
[]{10,20,30,40,50}. Then take them out in that same order (FIFO).
The code I have written is not able to pass the unit test, and the error says:
Assert.AreEqual failed. Expected<20>.Actual<10>
public int Count { get; private set; }
private Node<T> _head = null;
private Node<T> _tail = null;
public void Enqueue(T data)
{
Node<T> node = new Node<T>();
node.Data = data;
if (Count == 0)
{
_tail = node;
_head = node;
_tail.Next = node;
}
else
{
node.Next = _tail;
_tail = node.Next;
}
}
I think this block of code is my issue here, but I could be wrong. I've tried variations of these over and over with no success, and have resigned that my logic may be off or something very silly is missing.
public T Dequeue()
{
Node<T> position = _head;
if (Count == 0)
{
throw new InvalidOperationException("You've taken it all...");
}
else
{
T temp = _head.Data;
_head = position.Next;
--Count;
if (_head == null)
{
_tail = null;
}
return temp;
}
}
public void Reverse()
{
Node<T> previous, current, next;
previous = null;
current = _head;
next = _head.Next;
while (current != null)
{
next = current.Next;
current.Next = previous;
previous = current;
current = next;
}
_head = previous;
_tail = next;
}
public void EnqueueDequeueTest()
{
int[] testValues = new int[5] { 10, 20, 30, 40, 50 };
PG2Queue<int> testQueue = new PG2Queue<int>();
foreach (var testValue in testValues)
{
testQueue.Enqueue(testValue);
}
for (int i = 0; i < testValues.Length; i++)
{
int itemPopped = testQueue.Dequeue();
Assert.AreEqual(testValues[i], itemPopped);
}
}

Printing Tree and skipping certain values

here i have the following code and input that prints a tree structure. My question is how can i make it so that the nodes and leafs that have the value "Unavailable" are skipped from being printed.
namespace Tree{public class TreeNode<T>
{
private T value;
private bool hasParent;
private List<TreeNode<T>> children;
public TreeNode(T value)
{
if (value == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
this.value = value;
this.children = new List<TreeNode<T>>();
}
public T Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
public int ChildrenCount
{
get
{
return this.children.Count;
}
}
public void AddChild(TreeNode<T> child)
{
if (child == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
if (child.hasParent)
{
throw new ArgumentException("The node already has a parent");
}
child.hasParent = true;
this.children.Add(child);
}
public TreeNode<T> GetChild(int index)
{
return this.children[index];
}
}
public class Tree<T>
{
private TreeNode<T> root;
public Tree(T value)
{
if (value == null)
{
throw new ArgumentNullException("Cannot insert null value");
}
this.root = new TreeNode<T>(value);
}
public Tree(T value, params Tree<T>[] children) : this(value)
{
foreach (Tree<T> child in children)
{
this.root.AddChild(child.root);
}
}
public TreeNode<T> Root
{
get
{
return this.root;
}
}
private void PrintDFS(TreeNode<T> root, string spaces)
{
if (this.root == null)
{
return;
}
Console.WriteLine(spaces + root.Value);
TreeNode<T> child = null;
for (int i = 0; i < root.ChildrenCount; i++)
{
child = root.GetChild(i);
PrintDFS(child, spaces + " ");
}
}
public void TraverseDFS()
{
this.PrintDFS(this.root, string.Empty);
}
}
public static class TreeExample
{
static void Main()
{
Tree<string> tree =
new Tree<string>("John",
new Tree<string>("Jasmine",
new Tree<string>("Jay"),
new Tree<string>("Unavailable")),
new Tree<string>("Unavailable",
new Tree<string>("Jack"),
new Tree<string>("Jeremy")),
new Tree<string>("Johanna")
);
tree.TraverseDFS();
}
}}
right now it prints :(John, (Jasmine, (Jay), (Unavailable)), (Unavailable, (Jack, (Jeremy))), (Johanna))
I need it to print :(John, (Jasmine, (Jay)), (Johanna))
So basically skip every leaf with the value "Unavailable" and every node with the value "Unavailable" and all children from that node
Thanks !
This should work:
private void PrintDFS(TreeNode<T> root, string spaces)
{
if (this.root == null
|| "Unavailable" == root.Value.ToString())
{
return;
}
...
The accepted answer is a literally correct answer to the question, but it bakes in logic about what to do with the tree into the tree itself. A tree is a kind of collection or data structure, and you don't often see a List or Dictionary that is able to print itself. Instead the collection provides the right methods to get or change its contents so that you can do what you want.
In your case, you could do something like the following:
public enum TreeVisitorResult {
SkipNode,
Continue
}
// the following two methods inside Tree<T>:
public void VisitNodes(Func<TreeNode<T>, int, TreeVisitorResult> visitor) {
VisitNodes(0, this.root, visitor);
}
private void VisitNodes(int depth, TreeNode<T> node,
Func<TreeNode<T>, int, TreeVisitorResult> visitor) {
if (node == null) {
return;
}
var shouldSkip = visitor(node, depth);
if (shouldSkip == TreeVisitorResult.SkipNode) {
return;
}
TreeNode<T> child = null;
for (int i = 0; i < node.ChildrenCount; i++) {
child = node.GetChild(i);
VisitNodes(depth + 1, child, visitor);
}
}
If you had this method, you could write the Print method outside of the Tree classes, as:
tree.VisitNodes((treeNode, depth) => { // <- this lambda will be called for every node
if (treeNode.Value == "Unavailable") { // <- no need to ToString or cast here, since
// we know that T is string here
return TreeVisitorResult.SkipNode;
} else {
var spaces = new string(' ', depth * 3);
Console.WriteLine(spaces + treeNode.Value);
}
});

Need help to figure out the error in this search program

I have this linked list c# codes. I couldn't figure out the error for not printing any output. I have an error message saying that LinkedList.LinkedList doesn't contain a definition for PrintNodes. Can anyone pointed out why I am getting that error, and where I am doing mistake.
public class Node
{
public object data;
public Node next;
public Node(object data)
{
this.data = data;
}
}
public class LinkedList
{
Node head;
Node current;
public Node Head
{
get { return head; }
}
public void Add(Node n)
{
if (head == null)
{
head = n;
current = head;
}
else
{
current.next = n;
current = current.next;
}
}
public void MergeSortedList(Node first, Node second)
{
if (Convert.ToInt32(first.next.data.ToString())
> Convert.ToInt32(second.data.ToString()))
{
Node t = first;
first = second;
second = t;
}
head = first;
while ((first.next != null) && (second != null))
{
if (Convert.ToInt32(first.next.data.ToString())
< Convert.ToInt32(second.data.ToString()))
{
first = first.next;
}
else
{
Node n = first.next;
Node t = second.next;
first.next = second;
second.next = n;
first = first.next;
second = t;
}
}
if (first.next == null)
first.next = second;
}
static void Main()
{
LinkedList l1 = new LinkedList();
l1.Add(new Node("2"));
l1.Add(new Node("3"));
l1.Add(new Node("4"));
l1.Add(new Node("5"));
l1.Add(new Node("8"));
l1.Add(new Node("100"));
l1.Add(new Node("120"));
LinkedList l2 = new LinkedList();
l2.Add(new Node("10"));
l2.Add(new Node("30"));
l2.Add(new Node("34"));
LinkedList list = new LinkedList();
list.MergeSortedList(l1.Head, l2.Head);
list.PrintNodes();
Console.ReadLine();
}
}
}
In Main you call list.PrintNodes() but your LinkedList class has no such method defined, hence the exception, exactly as it says so:
LinkedList.LinkedList doesn't contain a definition for PrintNodes

How would one bind a SortedSet in WPF?

I am building a WPF Application which contains three ListBox elements bound to either an ISet, SortedSet or custom class (not sure). I came to this conclusion based on former Java experience and because I require the following constraints:
Needs to sort on add, keeping performance in mind
No duplicates should be included
After visiting MSDN to see which interfaces ObservableCollection uses, I figured I would do something like this:
public class ObservableSortedSet<T> : SortedSet<T>, INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public override bool Add(T item)
{
bool result = base.Add(item);
OnCollectionChanged(NotifyCollectionChangedAction.Add);
return true;
}
private void OnCollectionChanged(NotifyCollectionChangedAction action)
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(action));
}
}
The ObservableCollection class in .NET inspired me to make an ObservableSortedSet, but apparently in C# you use virtual, override, and new keywords, so since SortedSet doesn't have a virtual add method, I cannot do it like above. So my question now is how would I make a SortedSet or what .NET class would provide the features I need? I suppose I could create my own SortedSet class, but that seems like something that should be in the .NET framework.
UPDATE
If anyone wants something like I described above, I went ahead and made one. I have been using it in my project for a while and it seems quite stable. I took a linked list implementation I made a long time ago and tailored it to work as a sorted set. This allows me to preform sorts fast.
Here's the code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
namespace Conquest.Collections {
public class OrderedSet<T> : IEnumerable<T>, INotifyCollectionChanged where T : IComparable<T> {
private Node<T> head;
private Node<T> tail;
public OrderedSet() {
Count = 0;
}
public OrderedSet(IEnumerable<T> enumerable) {
Count = 0;
foreach (T element in enumerable)
Add(element);
}
public T First {
get { return (head == null) ? default(T) : head.Datum; }
}
public T Last {
get { return (tail == null) ? default(T) : tail.Datum; }
}
public int Count { get; private set; }
public IEnumerator<T> GetEnumerator() {
return new OrderedSetEnumerator<T>(this);
}
IEnumerator IEnumerable.GetEnumerator() {
return new OrderedSetEnumerator<T>(this);
}
private void InsertNodeBefore(Node<T> insertingNode, Node<T> here) {
insertingNode.Next = here;
insertingNode.Previous = here.Previous;
if (here == head)
head = insertingNode;
else
here.Previous.Next = insertingNode;
here.Previous = insertingNode;
insertingNode.Index = here.Index;
for (Node<T> n = here; n != null; n = n.Next)
n.Index++;
}
private void InsertNodeAfter(Node<T> insertNode, Node<T> here) {
insertNode.Previous = here;
insertNode.Next = here.Next;
if (here == tail)
tail = insertNode;
else
here.Next.Previous = insertNode;
here.Next = insertNode;
insertNode.Index = here.Index + 1;
for (Node<T> n = insertNode.Next; n != null; n = n.Next)
n.Index++;
}
private bool IsNodeSorted(Node<T> node) {
if (Count == 1)
return true;
return (node == head && node.Next.Datum.CompareTo(node.Datum) > 0) ||
(node == tail && node.Previous.Datum.CompareTo(node.Datum) < 0) ||
(node != tail && node != head && node.Next.Datum.CompareTo(node.Datum) > 0 &&
node.Previous.Datum.CompareTo(node.Datum) < 0);
}
private void RemoveNode(Node<T> node) {
if (node == head)
head = node.Next;
else
node.Previous.Next = node.Next;
if (node == tail)
tail = node.Previous;
else
node.Next.Previous = node.Previous;
for (Node<T> n = node.Next; n != null; n = n.Next)
n.Index--;
Count--;
}
private void SortNodeLeft(Node<T> node) {
// Unlink
RemoveNode(node);
Count++;
for (Node<T> currentNode = node.Previous; currentNode != null; currentNode = currentNode.Previous) {
int compareResult = currentNode.Datum.CompareTo(node.Datum);
if (compareResult < 0) {
// Link
InsertNodeAfter(node, currentNode);
return;
}
}
InsertNodeBefore(node, head);
}
private void SortNodeRight(Node<T> node) {
// Unlink
RemoveNode(node);
Count++;
for (Node<T> currentNode = node.Next; currentNode != null; currentNode = currentNode.Next) {
int compareResult = currentNode.Datum.CompareTo(node.Datum);
if (compareResult > 0) {
// Link
InsertNodeBefore(node, currentNode);
return;
}
}
InsertNodeAfter(node, tail);
}
public bool Add(T item) {
var node = new Node<T>(item);
int index = 0;
if (head == null) {
head = node;
tail = head;
}
else {
for (Node<T> currentNode = head; currentNode != null; currentNode = currentNode.Next, index++) {
int compareResult = currentNode.Datum.CompareTo(item);
if (compareResult == 0)
return false;
else if (compareResult > 0) {
InsertNodeBefore(node, currentNode);
break;
}
// if so, make node the new tail
else if (currentNode == tail) {
InsertNodeAfter(node, tail);
index++;
break;
}
}
}
Count++;
NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
node.Index = index;
node.PropertyChanged += Sort;
return true;
}
/// <summary>
/// If the nodes datum changes state, this function ensures
/// the set remains sorted.
/// </summary>
/// <param name="sender">The node</param>
/// <param name="e">The property that changed</param>
private void Sort(object sender, PropertyChangedEventArgs e) {
var node = (Node<T>) sender;
int index = node.Index;
// Check if node is still in correct spot
if (IsNodeSorted(node))
return;
if (node.Previous == null || (node.Previous.Datum.CompareTo(node.Datum) < 0))
SortNodeRight(node);
else
SortNodeLeft(node);
NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Move, node.Datum,
node.Index, index));
}
public bool Remove(T item) {
if (head == null)
return false;
for (Node<T> node = head; node != null; node = node.Next) {
if (node.Datum.CompareTo(item) == 0) {
RemoveNode(node);
NotifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,
item, node.Index));
return true;
}
}
return false;
}
#region INotifyCollectionChanged
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs args) {
if (CollectionChanged != null)
CollectionChanged(this, args);
}
#endregion
#region Enumerator
private class OrderedSetEnumerator<U> : IEnumerator<U> where U : IComparable<U> {
private readonly OrderedSet<U> set;
private OrderedSet<U>.Node<U> current;
public OrderedSetEnumerator(OrderedSet<U> set) {
this.set = set;
current = null;
}
public U Current {
get { return (current == null) ? default(U) : current.Datum; }
}
Object IEnumerator.Current {
get { return (current == null) ? null : (Object) current.Datum; }
}
public bool MoveNext() {
current = current == null ? set.head : current.Next;
return (current != null);
}
public void Reset() {
current = null;
}
public void Dispose() {
current = null;
}
}
#endregion
private class Node<U> : INotifyPropertyChanged {
public Node(U datum) {
Datum = datum;
var flagObserveChanges = datum as INotifyPropertyChanged;
if (flagObserveChanges != null)
flagObserveChanges.PropertyChanged += NotifySet;
}
public Node<U> Next { get; set; }
public Node<U> Previous { get; set; }
public int Index { get; set; }
public U Datum { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifySet(object sender, PropertyChangedEventArgs e) {
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
}
}
And of course I made some test cases, simple ones, so you might want to expand :)
using System.Linq;
using Conquest.Collections;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.ComponentModel;
using System;
namespace Conquest.Test.Collections
{
[TestClass]
public class OrderedSetTest
{
private class Department : INotifyPropertyChanged, IComparable<Department> {
private string name;
public string Name {
get { return name; }
set {
name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public int CompareTo(Department other) {
return String.Compare(this.Name, other.Name, StringComparison.OrdinalIgnoreCase);
}
}
[TestMethod]
public void TestAddSingleItem()
{
var set = new OrderedSet<int> {1};
Assert.AreEqual(set.First, 1, "Head points to correct location");
Assert.AreEqual(set.Count, 1, "Correct Size");
Assert.AreEqual(set.Last, 1, "Tail points to correct location");
}
[TestMethod]
public void TestAddHead()
{
var set = new OrderedSet<int> {2, 1};
Assert.AreEqual(set.First, 1, "Head points to correct value");
}
[TestMethod]
public void TestAddTail()
{
var set = new OrderedSet<int> {1, 2};
Assert.AreEqual(set.Last, 2, "Tail points to correct value");
Assert.AreEqual(set.Count, 2, "Correct Size");
}
[TestMethod]
public void TestAddDuplicationItems()
{
var set = new OrderedSet<int> {1, 1};
Assert.IsTrue(1 == set.Count);
}
[TestMethod]
public void TestAddMultipleItems()
{
var set = new OrderedSet<int> {3, 2, 4, 1, 5};
int expected = 1;
bool worked = true;
foreach (int i in set)
{
if (i != expected)
{
worked = false;
break;
}
expected++;
}
Assert.IsTrue(worked, "Multiple Items");
}
[TestMethod]
public void TestRemoveSingleItem()
{
var set = new OrderedSet<int> {1};
set.Remove(1);
Assert.AreEqual(set.Count, 0, "Removed single item");
Assert.AreEqual(set.First, 0, "Head does not point to anything");
Assert.AreEqual(set.Last, 0, "Tail does not point to anything");
}
[TestMethod]
public void TestRemoveHead()
{
var set = new OrderedSet<int> {1, 2};
set.Remove(1);
Assert.AreEqual(set.Count, 1, "Removed head with more than one item in set");
Assert.AreEqual(set.First, 2, "Head points to the next value in set");
}
[TestMethod]
public void TestRemoveTail()
{
var set = new OrderedSet<int> {1, 2};
set.Remove(2);
Assert.AreEqual(set.Count, 1, "Removed tail with more than one item in set");
Assert.AreEqual(set.Last, 1, "Tail points to the previous value in set");
}
[TestMethod]
public void TestRemoveItem()
{
var set = new OrderedSet<int> {1, 2, 3};
Assert.IsTrue(set.Remove(2), "Remove correct value");
Assert.IsTrue(set.Count == 2, "Removed item");
int sum = set.Sum();
Assert.AreEqual(4, sum, "Remove correctly relinked adjacent nodes");
}
[TestMethod]
public void TestSortOnAdd()
{
var test = new Queue<int>();
for (int i = 0; i < 10; i++)
test.Enqueue(i);
var set = new OrderedSet<int> {5, 4, 3, 7, 2, 8, 1, 9, 0, 6};
var worked = set.All(i => i == test.Dequeue());
Assert.IsTrue(worked, "Sorted on Add");
}
[TestMethod]
public void TestSortOnEdit()
{
var dep1 = new Department
{
Name = "Test"
};
var dep2 = new Department
{
Name = "Test2"
};
var set = new OrderedSet<Department> {dep1, dep2};
dep2.Name = "Hello";
var e = set.GetEnumerator();
e.MoveNext();
Assert.AreEqual("Hello", e.Current.Name, "Swaped tail to head on edit");
dep1.Name = "Abc";
e = set.GetEnumerator();
e.MoveNext();
Assert.AreEqual("Abc", e.Current.Name, "Verified integrity of node linkage");
var dep3 = new Department
{
Name = "Test3"
};
set.Add(dep3);
dep3.Name = "Cat";
e = set.GetEnumerator();
e.MoveNext();
bool correctOrder = e.Current.Name == "Abc";
e.MoveNext();
correctOrder = correctOrder && e.Current.Name == "Cat";
Assert.IsTrue(correctOrder, "Moved item to the left");
dep1.Name = "Dad";
e = set.GetEnumerator();
e.MoveNext();
correctOrder = e.Current.Name == "Cat";
e.MoveNext();
correctOrder = correctOrder && e.Current.Name == "Dad";
Assert.IsTrue(correctOrder, "Moved item to the right");
}
}
}
You can change your class to have this declaration...
public class ObservableSortedSet<T> : INotifyCollectionChanged, ISet<T>
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
private readonly SortedSet<T> _sortedSet;
public ObservableSortedSet()
{
_sortedSet = new SortedSet<T>();
}
public bool Add(T item)
{
bool result = _sortedSet.Add(item);
OnCollectionChanged(NotifyCollectionChangedAction.Add);
return true;
}
private void OnCollectionChanged(NotifyCollectionChangedAction action)
{
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(action));
}
// all the rest of ISet implementation goes here...
}
This approach, although more verbose and arguably overkill, will give the behaviour you are after. The coding drill should take about 20 minutes.

What is the reason behind this huge Performance difference in .Net 4

I was just doing some research on RedBlack Tree. I knew that SortedSet class in .Net 4.0 uses RedBlack tree. So I took that part out as is using Reflector and created a RedBlackTree class. Now I am running some perf test on this RedBlackTree and SortedSet inserting 40000 sequential integral values (starting from 0 to 39999), I am astonished to see that there is huge perf difference as follows:
RBTree took 9.27208 sec to insert 40000 values
SortedSet took 0.0253097 sec to insert 40000 values
What is the reason behind it? BTW I ran the test in Release configuration only and here is the small test code
var stopWatch = new Stopwatch();
var rbT = new RedBlackTree<int>();
stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < 40000; i++) {
rbT.Add(i);
}
stopWatch.Stop();
Console.WriteLine(stopWatch.Elapsed);
var ss = new SortedSet<int>();
stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < 40000; i++) {
ss.Add(i);
}
stopWatch.Stop();
Console.WriteLine(stopWatch.Elapsed);
Edit
I would like to share the code also for RBTree what I've extracted so that you also can run the diagnostics
public class Node<T>
{
public Node(){}
public Node(T value)
{
Item = value;
}
public Node(T value, bool isRed)
{
Item = value;
IsRed = isRed;
}
public T Item;
public Node<T> Left;
public Node<T> Right;
public Node<T> Parent;
public bool IsRed;
}
public class RedBlackTree<T>
{
public RedBlackTree(){}
public Node<T> root;
int count, version;
Comparer<T> comparer = Comparer<T>.Default;
public void Add(T item)
{
if (this.root == null)
{
this.root = new Node<T>(item, false);
this.count = 1;
this.version++;
return;
}
Node<T> root = this.root;
Node<T> node = null;
Node<T> grandParent = null;
Node<T> greatGrandParent = null;
this.version++;
int num = 0;
while (root != null)
{
num = this.comparer.Compare(item, root.Item);
if (num == 0)
{
this.root.IsRed = false;
return;
}
if (Is4Node(root))
{
Split4Node(root);
if (IsRed(node))
{
this.InsertionBalance(root, ref node, grandParent, greatGrandParent);
}
}
greatGrandParent = grandParent;
grandParent = node;
node = root;
root = (num < 0) ? root.Left : root.Right;
}
Node<T> current = new Node<T>(item);
if (num > 0)
{
node.Right = current;
}
else
{
node.Left = current;
}
if (node.IsRed)
{
this.InsertionBalance(current, ref node, grandParent, greatGrandParent);
}
this.root.IsRed = false;
this.count++;
}
private static bool IsRed(Node<T> node)
{
return ((node != null) && node.IsRed);
}
private static bool Is4Node(Node<T> node)
{
return (IsRed(node.Left) && IsRed(node.Right));
}
private static void Split4Node(Node<T> node)
{
node.IsRed = true;
node.Left.IsRed = false;
node.Right.IsRed = false;
}
private void InsertionBalance(Node<T> current, ref Node<T> parent, Node<T> grandParent, Node<T> greatGrandParent)
{
Node<T> node;
bool flag = grandParent.Right == parent;
bool flag2 = parent.Right == current;
if (flag == flag2)
{
node = flag2 ? RotateLeft(grandParent) : RotateRight(grandParent);
}
else
{
node = flag2 ? RotateLeftRight(grandParent) : RotateRightLeft(grandParent);
parent = greatGrandParent;
}
grandParent.IsRed = true;
node.IsRed = false;
ReplaceChildOfNodeOrRoot(greatGrandParent, grandParent, node);
}
private static Node<T> RotateLeft(Node<T> node)
{
Node<T> right = node.Right;
node.Right = right.Left;
right.Left = node;
return right;
}
private static Node<T> RotateRight(Node<T> node)
{
Node<T> left = node.Left;
node.Left = left.Right;
left.Right = node;
return left;
}
private static Node<T> RotateLeftRight(Node<T> node)
{
Node<T> left = node.Left;
Node<T> right = left.Right;
node.Left = right.Right;
right.Right = node;
left.Right = right.Left;
right.Left = left;
return right;
}
private static Node<T> RotateRightLeft(Node<T> node)
{
Node<T> right = node.Right;
Node<T> left = right.Left;
node.Right = left.Left;
left.Left = node;
right.Left = left.Right;
left.Right = right;
return left;
}
private void ReplaceChildOfNodeOrRoot(Node<T> parent, Node<T> child, Node<T> newChild)
{
if (parent != null)
{
if (parent.Left == child)
{
parent.Left = newChild;
}
else
{
parent.Right = newChild;
}
}
else
{
this.root = newChild;
}
}
}
Edit
I ran the same diagnostic on some other data structure (some created by me*, some from .net framework**) and here is the interesting results
*AATree 00:00:00.0309294
*AVLTree 00:00:00.0129743
**SortedDictionary 00:00:00.0313571
*RBTree 00:00:09.2414156
**SortedSet 00:00:00.0241973
RBTree is the same as above (stripped out from SortedSet class). I tried with 400000 values also, but RBTree seems taking FOREVER, I really don't know why.
You have a bug in your Node<T> class. When you call the constructor that only takes a single value argument you should be setting IsRed to true.
I suppose that the fixed Node<T> class should look something like this:
public sealed class Node<T>
{
public T Item { get; private set; }
public bool IsRed { get; set; }
public Node<T> Left { get; set; }
public Node<T> Right { get; set; }
public Node(T value)
{
Item = value;
IsRed = true;
}
public Node(T value, bool isRed)
{
Item = value;
IsRed = isRed;
}
}
Another option -- my preference -- would be to omit that constructor altogether and always require IsRed to be set explicitly when you instantiate a new node:
public sealed class Node<T>
{
public T Item { get; private set; }
public bool IsRed { get; set; }
public Node<T> Left { get; set; }
public Node<T> Right { get; set; }
public Node(T value, bool isRed)
{
Item = value;
IsRed = isRed;
}
}
And then replace this line in your Add method...
Node<T> current = new Node<T>(item);
...with this...
Node<T> current = new Node<T>(item, true);
reverse the order of the tests and repeat the measurement.
randomize your data. Sorted sets behave strangely when you insert pre-sorted data.
SortedSet includes a TargetedPatchingOptOut attribute, did your copied version include that?
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public bool Add(T item)
{
return this.AddIfNotPresent(item);
}
If the difference wasn't that big I would suggest that the cause is that the .NET assemblies are NGen-ed and so they are already translated to native code. In the case of your class the time to compile the IL code into native code is amortized over the time of your test. How does increasing the number of loop iterations affect the times?

Categories