I have problem with method MoveNext in my enumerator. I need iterator for binary search tree. In construcotr of my enumerator I initialize Node to root of tree.
Current is value that I ened to return for next item. This code for method moveNext return wrong values.
public bool MoveNext()
{
if (Current == null)
Current = node.Value;
else if (node.Left != null)
{
node = node.Left;
Current = node.Value;
}
else if (node.Right != null)
{
node = node.Right;
Current = node.Value;
}
else
{
node.Value = Current;
do
{
if (node.Parent == null)
return false;
node = node.Parent;
} while (node.Right == null);
Current = node.Value;
}
return true;
}
I see a few issues with that code. First, in the else-branch, you are changing the value of a node in the tree - You probably meant to write Current = node.Value; instead of node.Value = Current;.
However, that's not the main issue. Your iterator will get stuck in an infinite loop really easily. Everything looks reasonable for traversing down, you take the leftmost path down to a leaf node.
Then you backtrack up until you find an ancestor node which has a Right child and yield the value of that node. However, this value was already returned by the iterator on the way down. Also, you don't remember which path you already traversed down, so on the next step you will inevitably follow the same path down again that you took before, then you'll backtrack up again and so on, ad infinitum.
In order to fix this, don't stop at the parent node when you backtrack - take the first step down the next path already. It is true that this will always be the Right child of some node, but it is not necessarily the Right child of the first ancestor that has one, because you might already be backtracking up from that branch.
So to summarize: If you can't go down any further, backtrack up one level. Check if you are coming from the Left or the Right child node. If you came from the left one, go down the right one if it exists, and set Current to its value. If it doesn't, or if you already come from the right child, recurse upwards another level.
Your enumerator modifies the tree:
Node.Value = Current;
Enumerators shouldn't do that.
In the last else you are changing the value of the node to the same value as the current node:
node.Value = Current;
I think that you tried to put the current node in the node variable, but that's not done by putting the current value in the value of the current node, and it's not needed as the node variable already contains the current node.
As Medo42 pointed out, if you are coming from the Right node, all children of that parent has already been iterated, so you should check for that when looking for a parent to continue iterating:
} while (node.Right == null || node.Right == last);
When you have looped up the parent chain to find the right parent, you are using the parent instead of getting the child:
node = node.Right;
So:
public bool MoveNext() {
if (Current == null)
Current = node.Value;
else if (node.Left != null)
{
node = node.Left;
Current = node.Value;
}
else if (node.Right != null)
{
node = node.Right;
Current = node.Value;
}
else
{
Node last;
do
{
if (node.Parent == null)
return false;
last = node;
node = node.Parent;
} while (node.Right == null || node.Right == last);
node = node.Right;
Current = node.Value;
}
return true;
}
I posted my solution here
Binary Search Tree Iterator java
Source code
https://github.com/yan-khonski-it/bst/blob/master/bst-core/src/main/java/com/yk/training/bst/iterators/BSTIterator.java
Here is algorithm how to do so (you can implement it in any language you like then).
ArrayIterator
BSTITerator what uses an array under the hood.
Perform inorder traversal and collect visited nodes into a list.
ArrayIterator. Now it works similar to list iterator, which is easy to implement.
next() and hasNext() - have constant time complexity; however, this iterator requires memory for N elements of the tree.
StackIterator
All nodes to be returned in next() call are stored in stack. Each time, you return next node, you remove element from the stack (let's name it currentNode).
If currentNode has a right child (you have already returned left), you put the right child into the stack. Then you need to iterate left subtree of the right child and put all left elements into the stack.
Related
I was browsing the .NET Reference to see the internal workings of a LinkedList<T> and its corresponding LinkedListNode<T> elements when I noticed that I didn't quite understand how the AddLast(T item) and AddLast(LinkedListNode<T> node) methods worked. I will consider AddLast(T item) to address my confusion.
The way I see it, the method first creates a new node that refers to the current list and holds the required value to be added. Then it checks if the list is empty by looking at head, the supposed first item ever added to the list.
A) head is null
Calls a method called InternalInsertNodeToEmptyList(LinkedListNode<T> newNode) where newNode in this case will be result from the scope surrounding this method. It checks if the list is actually empty and then modifies the node to be added to link to itself in both directions, before setting it as the head of the list. Also updates the count and the version of the list.
private void InternalInsertNodeToEmptyList(LinkedListNode<T> newNode)
{
Debug.Assert( head == null && count == 0, "LinkedList must be empty when this method is called!");
newNode.next = newNode; // i.e. result.next = result
newNode.prev = newNode; // i.e. result.prev = result
head = newNode; // i.e. head = result
version++;
count++;
}
B) head is NOT null
Calls a method called InternalInsertNodeBefore(LinkedListNode<T> node, LinkedListNode<T> newNode) where node is head and newNode is result from the scope surrounding this method. First it checks if the list isn't empty, but then the actual logic of adding the new node follows:
private void InternalInsertNodeBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
newNode.next = node; // result.next = head
newNode.prev = node.prev; // result.prev = head.prev (but isn't head.prev just head?)
node.prev.next = newNode; // head.prev.next = result (so result gets added after head?)
node.prev = newNode; // head.prev = result (why does head link back to result?)
version++;
count++;
}
I really don't understand how this results in inserting a new link after the last known link of the list. Why does this not result in adding a link after head rather than after the last known link?
LinkedList<T> is a doubly-linked list: each node has references to the nodes before and after.
head is the first element in the list, but its prev member points to the last element in the list. You can see this from the Last property:
public LinkedListNode<T> Last {
get { return head == null? null: head.prev;}
}
This relationship between the last element of the list and head is two-way: head.prev is the last element in the list, and the last element in the list's next is head.
So:
// Remember that 'node' is the 'head'. I've replaced 'node' with
// 'head' to make this clearer.
// The new node's 'next' points to 'head', as it should
newNode.next = head;
// The new node's 'prev' points to the old last element in the list
// (remember that 'head.prev' is the last element in the list)
newNode.prev = head.prev;
// 'head.prev' is the old last element in the list. This is now the second-last
// element in the list, and its 'next' should be our new node. This
// is the reciprocal of 'newNode.prev = head.prev'
head.prev.next = newNode;
// head.prev now points to the new node, as it should. This is the reciprocal of
// 'newNode.next = head'
head.prev = newNode;
To attempt to draw the 'before' state:
LinkedList
|
v
oldLastNode <-- prev -- head
-- next -->
After:
LinkedList
|
v
oldLastNode <-- prev -- newNode <-- prev -- head
-- next --> -- next -->
So we want to do:
oldLastNode.next = newNode
newNode.prev = oldLastNode
newNode.next = head
head.prev = newNode
From the first diagram, we can see that oldLastNode is the old head.prev. So as long as we make changes to head.prev before we re-assign head.prev, we can write this as:
head.prev.next = newNode
newNode.prev = head.prev
newNode.next = head
head.prev = newNode
These are the same operations as in your question, but re-arranged.
I have been struggling trying to develop my own singly linked list, I cant understand how a node is inserted at the end of a Linked List?
Here's the code:
class LinkedList
{
private Node head;
public void AddLast(int value)
{
if (head == null)
{
head = new Node();
head.value = value;
head.next = null;
}
else
{
Node temp = new Node();
temp.value = value;
Node current = head;
while (current.next != null)
{
current = current.next;
}
current.next = temp;
}
}
public void PrintAll()
{
Node current = head;
while (current != null)
{
Console.WriteLine(current.value);
current = current.next;
}
}
}
Here is the main method
static void Main(string[] args)
{
LinkedList list = new LinkedList();
list.AddLast(3);
list.AddLast(5);
list.AddLast(4);
}
1) I totally get the first part list.AddLast(3). Since head is null, we create a new node head and assign values to it.
2) When list.AddLast(5) is called, head is no more null, and thus we create a new temporary node, assign values to it. NOW we create a new node current which holds values of Head, it is to be noted Head.Next was null.
Now we iterate through current and place our temp node to current.Next.
3) Now, Upon calling list.AddLast(5) shouldn't the current be again overwritten with the contents of Head? which was Head.Value = 3 and Head.Next = Null.
So shouldn't it current.Value = 3 and Current.Next = Null? And if not then why?
Node current = head;
When the above statement executes, current is assigned only the reference of head temporarily and not the value. So current only points to head at that moment. current.value will give you the value for head if executed after this statement.
while (current.next != null)
{
current = current.next;
}
Now, when the above while loop executes, it iterates through the linked list and takes the current node to the last node in the linked list which will have current.next = null.
current.next = temp;
When the above statement executes, the new node is added to the last of the linked list.
You create a new instance of LinkedList.
list.AddLast(3); --> head is null, you create a new Node and assign it to head.
list.AddLast(5); --> Create a new Node temp and assigns 5 to the value. Keep in mind that head's value = 3 and next is null. A new variable is created called current that points to head. The while then traverses the tree and if current's next is not null, then reassign current's next to that node. In this case, the while loop is not run because head's next is null, so all it does is just assign head.next to your current node. At this point we have head.value = 3, head.next = new Node(5, null);
list.AddLast(4); --> Same as above but the while loop now runs. It traverses all the way to find a Node that has no next value and assigns 4 to it. At this point we have head.value = 3, head.next = new Node(5, new Node(4, null))
There are oodles of implementations of linked lists. However for a simple singlely Linked list we think of it like thus
If i understand you correctly, this is the part you don't understand
// All this part of the method does is add the new value to the end of the list
// create node
Node temp = new Node();
// assign its value
temp.value = value;
// now we want to start with the head and follow
// the chain until we find the last node
Node current = head;
// has it got a next element
while (current.next != null)
{
// if so change current to next and look again
current = current.next;
}
// yay no more nexts, lets add temp here
current.next = temp;
// you have effectively added your new element to the end of the list
On saying that another common implementation is to save the Last/Current Node in the class (just like you did with head).
In that case, instead of iterating through the chain we can reference that Node and just add to its next and update Last reference in the class. However when we have to remove the last item, we have to remember not only to null Last in the class but null its parents Next reference as well.
The only way to do this is once again iterate the chain.
To make that easier we can implement a doubly linked list so its easier to find its parent
Update
what I don't understand is that why isn't the link to next nodes lost
when current who holds that info is updated every time with content of
Head.
In the above, think of current as just a temporary variable, its sole job in life is just like a temporary marker of the next link in the chain,
When we call this
current = current.next;
All its doing its grabbing whats in current.next and holding on to it for the loop condition again. We can call this without destroying whats in current.next
On the last time, when we have found nothing in current.next
i.e when the loop checks that current.next== null we can safely put our temp node into it current.next = temp; <== it was empty anyway
I've implemented a quadtree in C# and have come across a weird occurrence where recursion seems to perform better than iteration, despite looking like it should be the opposite.
My nodes look like this:
class QuadNode
{
private QuadNode topLeft;
private QuadNode topRight;
private QuadNode bottomRight;
private QuadNode bottomLeft;
// other fields...
}
To traverse the tree I used the following recursive method, which I invoke on the root node:
Traverse()
{
// visit 'this'
if (topLeft != null)
topLeft.Traverse();
if (topRight != null)
topRight.Traverse();
if (bottomRight != null)
bottomRight.Traverse();
if (bottomLeft != null)
bottomLeft.Traverse();
}
Mostly out of interest, I tried to create an iterative method for traversing the tree.
I added the following field to each node: private QuadNode next, and when I create the tree I perform a breadth-first traversal using a queue, linking the next field of each node to the next node in line. Essentially I created a singly-linked list from the nodes of the tree.
At this point I am able to traverse the tree with the following method:
Traverse()
{
QuadNode node = this;
while (node != null)
{
// visit node
node = node.next;
}
}
After testing the performance of each method I was very surprised to learn that the iterative version is consistently and noticeably slower than the recursive one. I've tested this on both huge trees and small trees alike and the recursive method is always faster. (I used aStopwatch for benchmarking)
I've confirmed that both methods traverse the entire tree successfully and that the iterative version only visits each node exactly once as planned, so it's not a problem with the linking between them.
It seems obvious to me that the iterative version would perform better... what could be the cause of this? Am I overlooking some obvious reason as to why the recursive version is faster?
I'm using Visual Studio 2012 and Compiled under Release, Any CPU (prefer 32 bit unchecked).
Edit:
I've opened a new project and created a simple test which also confirms my results.
Here's the full code: http://pastebin.com/SwAsTMjQ
The code isn't commented but I think it's pretty self-documenting.
Cache locality is killing speed. Try:
public void LinkNodes()
{
var queue = new Queue<QuadNode>();
LinkNodes(queue);
QuadNode curr = this;
foreach (var item in queue)
{
curr.next = item;
curr = item;
}
}
public void LinkNodes(Queue<QuadNode> queue)
{
queue.Enqueue(this);
if (topLeft != null)
topLeft.LinkNodes(queue);
if (topRight != null)
topRight.LinkNodes(queue);
if (bottomRight != null)
bottomRight.LinkNodes(queue);
if (bottomLeft != null)
bottomLeft.LinkNodes(queue);
}
Now the iterative version should be 30/40% faster than the recursive version.
The reason of the slowness is that your iterative algorithm will go Breadth First instead of Depth First. You created your elements Depth First, so they are sorted Depth First in memory. My algorithm creates the traverse list Depth First.
(note that I used a Queue in LinkNodes() to make it easier to follow, but in truth you could do it without)
public QuadNode LinkNodes(QuadNode prev = null)
{
if (prev != null)
{
prev.next = this;
}
QuadNode curr = this;
if (topLeft != null)
curr = topLeft.LinkNodes(curr);
if (topRight != null)
curr = topRight.LinkNodes(curr);
if (bottomRight != null)
curr = bottomRight.LinkNodes(curr);
if (bottomLeft != null)
curr = bottomLeft.LinkNodes(curr);
return curr;
}
Looking at your code, both methods seem to be working the same , BUT in the recursive one you visit 4 nodes in a "loop" , that means you do not "jump" between 3 tests whereas in the iterative you "jump" to the beginning of the loop each run.
I'd say if you want to see almost similar behaviour you'll have to unroll the iterative loop into something like :
Traverse(int depth)
{
QuadNode node = this;
while (node != null)
{
// visit node
node = node.next;
if (node!=null) node=node.next;
if (node!=null) node=node.next;
if (node!=null) node=node.next;
}
}
I am looking at the following code: http://netrsc.blogspot.com/2010/04/net-c-binary-tree.html
Am I right in thinking that the while (!Found) condition will iterate the tree?
protected void Insert(T item)
{
TreeNode<T> TempNode = Root;
bool Found=false;
while (!Found)
{
int ComparedValue = TempNode.Value.CompareTo(item);
if(ComparedValue<0)
{
if(TempNode.Left==null)
{
TempNode.Left=new TreeNode<T>(item,TempNode);
++NumberOfNodes;
return;
}
else
{
TempNode=TempNode.Left;
}
}
else if(ComparedValue>0)
{
if(TempNode.Right==null)
{
TempNode.Right=new TreeNode<T>(item,TempNode);
++NumberOfNodes;
return;
}
else
{
TempNode=TempNode.Right;
}
}
else
{
TempNode=TempNode.Right;
}
}
}
Also, for the find and traversal methods, how do these work? If nothing is returned from the Traversal method but from the left branch, would the loop in Find execute again? How would it know to execute down the right branch?
protected IEnumerable<TreeNode<T>> Traversal(TreeNode<T> Node)
{
if (Node.Left != null)
{
foreach (TreeNode<T> LeftNode in Traversal(Node.Left))
yield return LeftNode;
}
yield return Node;
if (Node.Right != null)
{
foreach (TreeNode<T> RightNode in Traversal(Node.Right))
yield return RightNode;
}
}
Thanks
An example of iterating the tree is in the Find command, which calls the Traversal function.
foreach (TreeNode<T> Item in Traversal(Root))
The Traversal function will iteratively return the items in the tree in a depth-first, left-to-right manner. If you look at the Traversal code, it calls itself recursively on the left side and then recursively on the right.
Traversal returns the entire tree in an iterable object, where the items are ordered depth-first, left-to-right. The Find command simply loops through each one and when it hits a match returns it breaking out of the loop. Basically, Traversal returns an ordered iterable of items, Find goes through that list looking for a match. Find really doesn't even have to know whether it's searching through a list or a tree or whatever. It just needs something to iterate through to find a match.
Not necessarily. It will only iterate through the nodes on the path of where the inserted node should be added. There are some return statements sprinkled in that loop so it will essentially stop when it find's the correct location and adds the new node. It would have been more appropriate (in the code) to set the Found variable to true instead.
The traversal methods return the nodes of both the left and right subtrees. You should note that it uses yield return and not the plain return. Using it creates an enumerator where each item that is yielded is what the numerator would return as you iterate through it. Think of it as pausing execution when it reaches a yield return statement. When iterating to the next value from the calling code, execution is continued at that point potentially returning more values.
Find will take the results of the traversal and returns the stored value if found in one of the nodes.
I have made my own single chained/linked list.
Now, if I want to delete/remove a node/item from my list, I'd have to do something like this:
public void Delete(PARAMETERS)
{
Node previousNode = null,
currentNode = f;
while (currentNode != null)
{
if (SOMECONDITION)
{
if (previousNode == null)
{
f = currentNode.Next;
}
else
{
previousNode.Next = currentNode.Next;
}
}
else
{
previousNode = currentNode;
}
currentNode = currentNode.Next;
}
}
If SOMECONDITION is true, you simply skip the currentNode and therefor effectively "deleting" the node, as nothing points to it anymore.
But, I am really wondering, why can I not do something like this:
(...)
while ()
{
if (SOMECONDITION)
{
currentNode = currentNode.Next;
}
currentNode = currentNode.Next;
}
(...)
OR perhaps:
(...)
while ()
{
if (SOMECONDITION)
{
currentNode = currentNode.Next.Next;
}
else
{
currentNode = currentNode.Next;
}
}
(...)
What fundamental understanding do I lack?
Doing:
currentNode = currentNode.Next.Next;
Is a prime candidate for a NullReferenceException
EDIT:
Here's a list implementation with some pictures that may help you understand.
http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=176
There is nothing to say you can't do Next.Next.
The only issue is what if currentNode.Next is null? Then you would get an error.
PreviousNode works because you are doing a NULL check before using it.
currentNode is just a temporary pointer variable (reference) that ceases to exist at the end of the scope (that is by the next closing brace). When you change what that reference points to, you don't change any other references; changing currentNode doesn't magically change what the previous node's Next reference points to.
currentNode = currentNode.Next // only changes the temporary reference
You have to actually reach into the linked list and change a referende inside the list, which is what you do when you change previousNode.Next - you change what node the previous node considers its next node. You basically tell it "This is your new Next node, forget about the old one".
Also, as the others have stated, you should check for null references throughout. if currentNode.Next is the last node in the list, its Next will point at nothing, and you'll get a NullReferenceException.
Perhaps if you re-write the original a bit you would see better what you are really doing to the list.
public void Delete(PARAMETERS)
{
var previous = FindPreviousNode(PARAMETERS);
if( previous == null && Matches(f, PARAMETERS)) {
f = f.Next;
} else if(previous != null ) {
previous.Next = previous.Next.Next;
} // u could add "else { throw new NodeNotFound() }" if that's appropiate
}
private Node FindPreviousNode(PARAMETERS) {
Node currentNode = f;
while (currentNode != null) {
if (Matches(currentNode.Next, PARAMETERS)) {
return currentNode;
}
currentNode = currentNode.Next;
}
return null;
}
You have asked around in the comments to understand more what's up with the list and the Next's properties, so here it goes:
Lets say the list is: 1|3|5|7, first points to 1, 1's Next property points to 3, 5's Next points to 7, and 7's Next points to null. That's all you keep track of to store the list. If you set the 5's Next property to null, you are deleting the 7. If instead you set 3's Next property to 7, you are deleting the 5 from the list. If you set first to 3, you are deleting the 1.
Its all about the first and the Next properties. That's what makes the list.
The assignments to currentNode and previousNode do not alter the structure of the linked list. They're merely used to step through the structure.
The assignment to previousNode.Next is what changes the structure. Doing currentNode = currentNode.Next.Next will skip over the next node (if currentNode.Next is not null) but it won't alter the structure of the list.
You should really sketch a picture of the linked list if you're wondering about problems like this. It's far easier to see what needs to be done to accomplish some linked list mutation, than it is to reason it out.
Honestly, I don't follow the posted code at all.
If this is a standard linked list (each node has a Next, but that's it), follow these steps to run a deletion of a single item:
Step 1: Find the target node you want to delete, but keep track of the previous node visited.
Step 2: prevNode.Next = targetNode.Next
Note: special checks for deleting the head of the list need to be done.
How do you know in both cases that currentNode.Next is not null and thus that you can apply .Next on it? You are only checking for the != null in the loop condition.