Traversing two trees together? - algorithm

I am looking a lot of interview problems where the question requires traversing two trees together, I am not sure exactly how to go about doing this.
e.g.
Given references to roots of two binary trees, how do you determine
whether the sequence of the leaf elements equal but you must
implement short circuiting return when the first node violates the
rule.

Is your question asking to find out whether:
"the sequence created by visiting all the leaf nodes of 2 trees is same"
with a constraint that when found a mismatch of leaf values, then we must quit immediately.
If so, I propose following solution:
insert (root of tree1) in stack1
insert (root of tree2) in stack2
temp1 = (root of tree1) -> left child
temp2 = (root of tree2) -> left child
while(stack1 and stack2 arent empty)
{
found = false
while(found == false) {
if (temp1 is leaf node)
child1 = value of temp1
found = true
pop element from stack1
set temp1 to its right child
if (temp1 has left child)
put temp1 in stack1
set temp1 to its left child
}
found = false
while(found == false) {
if (temp2 is leaf node)
child2 = value of temp2
found = true
pop element from stack2
set temp2 to its right child
if (temp2 has left child)
put temp2 in stack2
set temp2 to its left child
}
if(child1 != child2)
return
}

One possible solution:
I have created a tree class which has a method GetNextLeafNode(). This is responsible for returning the next immediate leaf node of a tree.
With the tree class I am keeping a stack to maintain the traversed elements
In the GetNextLeafNode() method, I am doing iterative tree traversal (Pre order).
Whenever I encounter a node(stack.Pop()) which is leaf I am just returning it. Otherwise I am pushing left and right pointers to the stack. Initially root node is pushed. At any time state of stack is proper.
Here is the code in C#:
public TreeNode GetNextLeafNode()
{
TreeNode leaf = null;
while (s.Count != 0)
{
TreeNode n = s.Pop();
if ((n.Left == null) && (n.Right == null))
{
leaf = n;
return leaf;
}
else
{
if (n.Right != null)
s.Push(n.Right);
if (n.Left != null)
s.Push(n.Left);
}
}
return leaf;
}
Now, we can create two different trees say, t1 and t2.
We can do the comparision as follows:
int data1 = t1.GetNextLeafNode().Data;
int data2 = t2.GetNextLeafNode().Data;
while (data1 == data2)
{
//both the leaf nodes are same.
data1 = t1.GetNextLeafNode().Data;
data2 = t2.GetNextLeafNode().Data;
}

In pseudo-code:
Go down to the first leaf (let's say left-most) in each tree.
Compare.
If not equal RETURN error.
Step to the next leaf in each tree (intuitively -- go up until you see a way to step to the right child, then take only left children on your way till you reach a leaf).
If one of the trees has a leaf but another returned to root RETURN error.
If both trees returned to root RETURN success.
Go to step 2.

A simple python solution.
Though this is not space optimal as we are storing leaves that can be O(N+M). This is not iterating both the trees together.
Time complexity - O(N+M).
You can also think of a solution where space is O(max(N,M)) in a similar fashion.
def binaryTreeLeafs(root1, root2):
# The order in which we see leaves will
# be maintained as it is inorder traversal.
def dfs(node, leaves):
if not node:
return
if not node.left and not node.right:
leaves.append(node.val)
return
dfs(node.left, leaves)
dfs(node.right, leaves)
leaves1 = []
leaves2 = []
dfs(root1, leaves1)
dfs(root2, leaves2)
return leaves1 == leaves2
# O(h1+h2) space
def binaryTreeLeaves2(root1, root2):
def isLeaf(node):
return not node or node.left == node.right == None
if not root1 and not root2:
return True
if (not root1) ^ (not root2):
return False
stack1 = [root1]
stack2 = [root2]
while stack1 or stack2:
if (not stack1) ^ (not stack2):
return False
tmp1 = stack1.pop()
while not isLeaf(tmp1):
if tmp1.right:
stack1.append(tmp1.right)
if tmp1.left:
stack1.append(tmp1.left)
tmp1 = stack1.pop()
tmp2 = stack2.pop()
while not isLeaf(tmp2):
if tmp2.right:
stack2.append(tmp2.right)
if tmp2.left:
stack2.append(tmp2.left)
tmp2 = stack2.pop()
if ((not tmp1) ^ (not tmp2)) or (tmp1 and tmp2 and tmp1.val != tmp2.val):
return False
return True

Related

Balanced tree with constant-time successor and predecessor given node pointers?

I was asked this question, which I personally find hard:
Create a data structure that can:
Insert elements,
Remove elements,
Search Elements,
In time O(log n)
In addition,
It should have the following two functions which work in time O(1):
next(x):
given a pointer to the node of value x, return a pointer to the node with the smallest bigger value than x.
previous(x)
given a pointer to the node of value x, return a pointer to the node with the biggest smallest value than x.
If each node contains a pointer to its successor and a pointer to its predecessor, or equivalently - if you maintain both a doublely linked list and a tree, where each node in the tree points to its equivalent node in the list and vice versa - you'll get want you want. Updating the list on insert/delete is O(1) (after locating the closest node in the tree). Searching is performed on the tree. Succesor / predecessor are performed on the list.
#RogerLindsjö's idea from the comments is a good one. Essentially, keep a regular, balanced BST, then thread a doubly-linked list through the nodes keeping them in sorted order. That way, given a pointer to a node in the tree, you can find the largest value smaller than it or the smallest value greater than it simply by following the next or previous pointers in each node.
You can maintain this list through insertions and deletions without changing the overall runtime of an insert or delete. For example, here's how you might do an insertion of an element x:
Do a standard BST successor query to find the smallest value larger than x in the tree, and a standard BST predecessor query to find the largest value smaller than x in the tree. Each search takes time O(log n) to complete.
Do a regular BST insertion to insert x. Then, set its next and previous pointers to the two elements you found in the previous step, and update those nodes to point to your new node x. This also takes time O(log n).
The total time for the insertion is then O(log n), matching what a balanced tree can provide.
I'll leave it to you to figure out deletion, which can similarly maintain the linked list pointers without changing the overall cost of the operation.
Like most self-balancing trees, a B+ tree provides Insert, Remove, and Search operations with O(log n) time complexity.
In a B+ tree, a leaf node hosts multiple keys in an array, so the concept of "pointer to node with value x" does not really exist, but we could define it as the tuple (pointer, index), where the pointer is to the node, and index is the slot in which x is stored.
In a B+ tree the nodes at the bottom level contain all the keys, and these nodes are often linked, usually only in forward direction (i.e. to the right), but it is quite possible to also maintain a link in the opposite direction, without increasing the time complexity of the above operations.
With those two remarks in mind, prev-next operations can clearly be executed in O(1) time.
If your elements are integers you can use y-fast trie that supports all mentioned operations in O(log log m). Also, almost any search tree will allow doing these operations in O(log n) time by just going first up and then down (it will require a lot of concentration to not mess up with the order, though)
You can use two pointers in the node of the balanced tree, namely pred - predecessor and succ - successor. While inserting a node into the tree or deleting a node from the tree you just have to do some pointer manipulations, equivalent to those in doubly linked list.
The time complexity will be O(1) in each case.
I have provided my implementation for the insertion and deletion in case of AVL Tree below. The complete implementation is available here.
Structure of node
template<typename T>
struct node {
T key;
int freq;
node<T> *left;
node<T> *right;
node<T> *pred;
node<T> *succ;
int height;
node(T key): key(key), freq(1),
left(nullptr),
right(nullptr),
height(1),
pred(nullptr),
succ(nullptr) {}
};
insert function
node<T> *insert(node<T> *root, T key) {
if(root == nullptr)
return new node<T>(key);
if(!comp(key, root->key) && !comp(root->key, key)) {
++root->freq;
} else if(comp(key, root->key)) {
if(root->left == nullptr) {
node<T> *new_node = new node<T>(key);
/* set the pred and succ ptrs*/
new_node->succ = root;
new_node->pred = root->pred;
if(root->pred != nullptr)
root->pred->succ = new_node;
root->pred = new_node;
root->left = new_node;
} else {
root->left = insert(root->left, key);
}
} else {
if(root->right == nullptr) {
node<T> *new_node = new node<T>(key);
/* set the pred and succ ptrs*/
new_node->pred = root;
new_node->succ = root->succ;
if(root->succ != nullptr)
root->succ->pred = new_node;
root->succ = new_node;
root->right = new_node;
} else {
root->right = insert(root->right, key);
}
}
root->height = max(height(root->left), height(root->right)) + 1;
int bf = balance_factor(root);
node<T> *left = root->left;
node<T> *right = root->right;
if(bf > 1 && left != nullptr && comp(key, left->key)) {
/*
node was inserted at left subtree of left child
fix - right rotate root
*/
root = rotate_right(root);
} else if(bf > 1 && left != nullptr && comp(left->key, key)) {
/*
node was inserted at right subtree of left child
fix - left rotate left child
- right rotate root
*/
root->left = rotate_left(root->left);
root = rotate_right(root);
} else if(bf < -1 && right != nullptr && comp(right->key, key)) {
/*
node was inserted at right subtree of right child
fix - left rotate root
*/
root = rotate_left(root);
} else if(bf < -1 && right != nullptr && comp(key, right->key)) {
/*
node was inserted at left subtree of right child
fix - right rotate right child
- left roatate root
*/
root->right = rotate_right(root->right);
root = rotate_left(root);
}
return root;
}
erase function
node<T> *erase(node<T> *root, T key) {
if(root == nullptr)
return nullptr;
if(comp(key, root->key)) {
root->left = erase(root->left, key);
} else if(comp(root->key, key)) {
root->right = erase(root->right, key);
} else {
if(root->left == nullptr || root->right == nullptr) {
/* update pred and succ ptrs */
if(root->succ != nullptr)
root->succ->pred = root->pred;
if(root->pred != nullptr)
root->pred->succ = root->succ;
if(root->right == nullptr) {
node<T> *temp = root->left;
delete root;
root = temp;
} else {
node<T> *temp = root->right;
delete root;
root = temp;
}
} else {
// node<T> *succ = minVal(root->right);
root->key = root->succ->key;
root->freq = root->succ->freq;
root->right = erase(root->right, root->succ->key);
}
}
if(root != nullptr) {
root->height = max(height(root->left), height(root->right)) + 1;
int bf_root = balance_factor(root);
if(bf_root > 1) {
/*
case R
*/
int bf_left = balance_factor(root->left);
if(bf_left >= 0) {
/*
case R0 and R1
*/
root = rotate_right(root);
} else {
/*
case R -1
*/
root->left = rotate_left(root->left);
root = rotate_right(root);
}
} else if(bf_root < -1) {
/*
Case L
*/
int bf_right = balance_factor(root->right);
if(bf_right <= 0) {
/*
case L0 and L -1
*/
root = rotate_left(root);
} else {
/*
case L1
*/
root->right = rotate_right(root->right);
root = rotate_left(root);
}
}
}
return root;
}

is wikipedia iterative postorder tree traversal pseudo code wrong?

Here is the pseudo code that wikipedia gives for iterative postorder tree traversal.
iterativePostorder(node)
parentStack = empty stack
lastnodevisited = null
while (not parentStack.isEmpty() or node ≠ null)
if (node ≠ null)
parentStack.push(node)
node = node.left
else
peeknode = parentStack.peek()
if (peeknode.right ≠ null and lastnodevisited ≠ peeknode.right)
/* if right child exists AND traversing node from left child, move right */
node = peeknode.right
else
visit(peeknode)
lastnodevisited = parentStack.pop()
It is pretty straight forward, and I have implemented it in Java. But it does not work, the problem is that every time it visits the most left leaf and return to its parent, it will add that left leaf again into the stack in next iteration. This causes an infinite loop. Is my method incorrect or the wikipedia version is wrong?
public static List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) return res;
Stack<TreeNode> s = new Stack<TreeNode>();
TreeNode lastVisitedNode = null;
TreeNode curr = root;
int i = 0;
while (curr != null || !s.isEmpty()) {
if (curr != null) {
System.out.println("push " + curr.val);
s.push(curr);
curr = curr.left;
} else {
curr = s.peek();
if (curr.right != null && lastVisitedNode != curr.right) {
curr = curr.right;
} else {
res.add(curr.val);
System.out.println("pop " + curr.val);
lastVisitedNode = s.pop();
}
}
System.out.println(s);
System.out.println(res);
if (i>8) break;
else i++;
}
return res;
}
The wikipedia version is wrong for the exact same reason as you've explained it.
Here is a probably better pseudo-code, from geeksforgeeks
1.1 Create an empty stack
2.1 Do following while root is not NULL
a) Push root's right child and then root to stack.
b) Set root as root's left child.
2.2 Pop an item from stack and set it as root.
a) If the popped item has a right child and the right child
is at top of stack, then remove the right child from stack,
push the root back and set root as root's right child.
b) Else print root's data and set root as NULL.
2.3 Repeat steps 2.1 and 2.2 while stack is not empty.
You will have to add extra code to check if the node right child is null in 2.1.a though.
The wikipedia pseudocode is not wrong. They use two different variables: node and peekNode, while you only use curr for both. Node == null refers to the case when there is no more of a left branch left to explore, so we can stop pushing and instead investigate the next element in the stack. You can either revert to using two different variables, or you make the following fix in your code:
Since you reassign curr to a non-null value everytime you investigate the stack, you need to reset curr to null after you visit your node. (Because the state that still no more left branch left to explore is still unchanged).
The wikipedia pseudocode doesn't have to do this because their node value remains null.
Here is my code which gives a perfect answer:
var currentNode = this.root()
var previousNode = null
while(!nodeStack.isEmpty() || currentNode) {
// If there is a node on which the recursive call is made, we have a subtree to explore. If this is null, we have to backtrack and do a callback.
if (currentNode) {
nodeStack.push(currentNode)
previousNode = currentNode
currentNode = currentNode.leftChild
} else {
currentNode = nodeStack.peek()
if (currentNode.rightChild && previousNode != currentNode.rightChild) {
currentNode = currentNode.rightChild
} else {
callback(currentNode)
currentNode = null
previousNode = nodeStack.pop()
}
}
}

BST to LinkList and back to same BST

Since I could not find anything useful so I am here to ask my question:
How can we convert the BST to a In-order linklist, and back to "same" BST, without using any extra space.
What I have tried so far (still doing though): I tried Morris Traversal to link up to the next in-order successor,
but it is not able to connect for all the nodes, only working for the left subtree, and right subtree, not for the actual root of the tree.
Please suggest how can I convert Tree to Linked List and back to Same tree...
To store a tree in lists - you need at least two lists: one for pre-order traversal, and the other for in-order traversal.
Luckily - since the tree is a BST, the in-order traversal is just the sorted list.
So, you can store the pre-order traversal (You can try doing it in-place) and by sorting the elements in re-construction, you can get the in-order traversal.
This post discusses how to reconstruct a tree from the inorder and pre-order traversals of it.
Binary Search Tree to List:
subTreeToList(node)
if (node.hasLeft()) then subTreeToList(node.left, list)
list.add(node.Value)
if (node.hasRight()) subTreeToList(node.right, list)
end if
subTreeToList end
treeToList(tree)
subTreeToList(tree.root)
treeToList end
list <- new List()
treeToList(tree)
You need to implement the idea above into your solution, if you are working with object-oriented technologies, then list and trees should be data members, otherwise they should be passed to the functions as references.
You can build back your tree knowing that insertion in the tree looks like this:
Insert(tree, value)
if (tree.root is null) then
tree.createRoot(value)
else
node <- tree.root
while (((node.value < value) and (node.hasRight())) or ((node.value > value) and (node.hasLeft())))
if ((node.value < value) and (node.hasRight())) then node <- node.right()
else node <- node.left()
end if
while end
if (node.value > value) then node.createLeft(value)
else node.createRight(value)
end if
end if
insert end
You just have to traverse your list sequentially and call the function implemented based on my pseudo-code above. Good luck with your homework.
I think I found the solution myself: below is the complete Java implementation
The logic + pseudo Code is as below
[1] Find the left most node in the tree, that will be the head of the LinkList, store it in the class
Node HeadOfList = null;
findTheHeadOfInorderList (Node root)
{
Node curr = root;
while(curr.left != null)
curr = curr.left;
HeadOfList = curr; // Curr will hold the head of the list
}
[2] Do the reverse - inorder traversal of the tree to convert it to a LL on right pointer, and make sure the left pointer is always pointing to the parent of the node.
updateInorderSuccessor(Node root, Node inorderNext, Node parent)
{
if(root != null)
//Recursively call with the right child
updateInorderSuccessor(root.right, inorderNext, root);
// Update the in-order successor in right pointer
root.right = inorderNext;
inorderNext = root;
//Recursively call with the left child
updateInorderSuccessor(root.left, inorderNext, root);
// Update the parent in left pointer
root.left = parent;
}
}
[3] To convert it back :
Traverse the list and find the node with left pointer as null,
Make it the root, break the link of this root in the linklist and also from its children...
Now the link list is broken into two parts one for left Subtree and one for right subtree,
recursively find the roots in these two list and make them the left and right child, Please refer the function restoreBST()
Node restoreBST(Node head)
{
if(head == null || (head.left == null && head.right == null)) return root;
Node prev, root, right, curr;
curr = head;
// Traverse the list and find the node with left as null
while(curr != null)
{
if(curr.left == null)
{
// Found the root of this tree
root = curr;
// Save the head of the right list
right = curr.right;
// Detach the children of the root just found, these will be updated later as a part of the recursive solution
detachChildren(curr, head);
break;
}
prev = curr;
curr = curr.right;
}
// By now the root is found and the children of the root are detached from it.
// Now disconnect the right pointer based connection in the list for the root node, so that list is broken in to two list, one for left subtree and one for right subtree
prev.right = null;
root.right = null;
// Recursively call for left and right subtree
root.left = restoreBST(head);
root.right = restoreBST(right);
//now root points to its proper children, lets return the root
return root;
}
Logic to detach the children is simple : Iterate through the list and look for the nodes with left pointer equal to root.
private void detachChildren(AvlNode root, AvlNode head) {
AvlNode curr = head;
while(curr != null)
{
if(curr.left == root)
{
curr.left = null;
}
curr = curr.right;
}
}
Here is a recursive solution for BST to LL, hope you find it useful.
Node BSTtoLL(BST root) {
if(null == root) return null;
Node l = BSTtoLL(root.left);
Node r = BSTtoLL(root.right);
Node l1 = null;
if(null != l) {
l1 = l;
while(null != l.left) { l = l.left; }
l.left = root;
l.right = null;
}
if(null != r) {
root.left = r;
root.right = null;
}
if(null != l1) return l1;
return root;
}

find inorder successor in BST without using any extra space

I am looking a way to find out inorder successor of a node in BST withut using extra space.
To get the inorder successor of a given node N we use the following rules:
If N has a right child R then the
inorderSuccessor(N) is the leftmost
decedent of R.
Else inorderSuccessor(N) is the closest
ancestor, M, of N (if it exists)
such that N is descended from the
left child of M. If there is no such ancestor, inorderSucessor does not exist.
Consider a sample tree:
A
/ \
B C
/ \
D E
/
F
Whose inorder traversal gives: D B F E A C
inorderSuccessor(A) = C as C is the leftmost decedent of the right child of A.
inorderSuccessor(B) = F as F is the leftmost decedent of the right child of B.
inorderSuccessor(C) = Does not exist.
inorderSuccessor(D) = B as B is the left child of D.
inorderSuccessor(E) = A. E does not have a right child so we have scenario 2. We go to parent of E which is B, but E is right decedent of B, so we move to parent of B which is A and B is left decedent of A so A is the answer.
inorderSuccessor(F) = E as F is the left child of E.
Procedure:
treeNodePtr inorderSucessor(treeNodePtr N) {
if(N) {
treeNodePtr tmp;
// CASE 1: right child of N exists.
if(N->right) {
tmp = N->right;
// find leftmost node.
while(tmp->left) {
tmp = tmp->left;
}
// CASE 2: No right child.
} else {
// keep climbing till you find a parent such that
// node is the left decedent of it.
while((tmp = N->parent)) {
if(tmp->left == N) {
break;
}
N = tmp;
}
}
return tmp;
}
// No IOS.
return NULL;
}
Code In Action
The following method helps you determine the inorder successor WITHOUT ANY PARENT NODE OR EXTRA SPACE NON-RECURSIVELY
struct node * inOrderSuccessor(struct node *root, struct node *n)
{
//*If the node has a right child, return the smallest value of the right sub tree*
if( n->right != NULL )
return minValue(n->right);
//*Return the first ancestor in whose left subtree, node n lies*
struct node *succ=NULL;
while(root)
{
if(n->datadata < root->data)
{
succ=root; root=root->left;
}
else if(n->data > root->data)
root=root->right;
else break;
}
return succ;
}
I'm quite certain this is right. Do correct me if I am wrong. Thanks.
If the given node has a right child - go to it, and then follow iteratively the left children until you reach a node N with no left children. Return N.
Otherwise, follow the parents until you first find a parent where the node is a left child. Return this parent.
Node InOrderSuccessor(Node node) {
if (node.right() != null) {
node = node.right()
while (node.left() != null)
node = node.left()
return node
} else {
parent = node.getParent();
while (parent != null && parent.right() == node) {
node = parent
parent = node.getParent()
}
return parent
}
}
If you can access the root of a node, then it's just a matter of moving pointers around, so no extra space. See this lecture.

given a tree structure, how do you use recursion to make it into a simple linked list in-place?

Given a binary tree (with left and right child only), how do you write a recursive function to make it into a simple linked list in-place? (no new data structure should be created. Pseudo code is ok). Suppose each node has an integer value, like 123, or 2, or 3. The final link list should have all the nodes in the tree. The order is not important.
Update: needs to be in-place. no new data structure should be created.
There are always different ways to iterate over a tree, as there are:
InOrder
PreOrder
PostOrder
You can choose either of them to form your list...
For example (pseudocode, PreOrder):
function treeToList(LinkedList l, Tree t)
if(t not nil)
l.add(t.element)
treeToList(l, t.Left)
treeToList(l, t.Right)
endif
end function
Remenber: If you perfomed an InOrder on a binary search tree you would get the elements in sorted order.
Not to be rude, but this sounds a bit like homework. Let me give a description as an answer:
You create an empty linked list for the result.
Make a help function which takes a linked list and a node.
The helper function should add the child nodes (if any) to the list and call itself recursively on the child nodes (if any).
Add the root node to the result list.
Call the helper function on the root node and the result list.
Return the result list to the caller.
There are of course a lot about this on Wikipedia: binary trees and tree traversal.
Edit: or look at the pseudo-code posted by Kevin :-)
Since you've tagged it as homework, I'll reply without source code or pseudo code, but with a more all-round description.
Since your tree will contain all the values you want to contain in the linked list, we have to make sure we reach them all.
To do that, we'll have to make sure we process every leaf node.
To do that, we need to make sure we process every left and right child of every node.
Let's start with the root node, which is generally the one you have a reference to when you're talking about a binary tree.
I'm assuming you know how to produce a linked list by sequentially appending items to it.
So to process the root node, we do this:
If the root contains a value: Append the value to the list
That takes care of the single value that can optionally be stored in the root node. Some binary trees only store values in leaf nodes (nodes without children), most store values also in internal nodes (nodes with children).
But that will of course get us nowhere, since we only add one item, and we don't even know where in all the values this specific value is, so it could be the first, or the last, or any in between.
But, we know that if the root node has children in the left "direction", then any values we might find in all those nodes will come before the node in the root node.
And we also know that if the root node has children in the right "direction", those values will come after it.
So what we can do is this:
Process all nodes in the left sub-tree
Append the value in the node
Process all nodes in the right sub-tree
This approach assumes that:
Node values are ordered (ie. left sub-tree comes before the value of the node itself, etc.)
You want the values in their ordered sequence
If you define the above approach as a method, you'll have something like this:
to process a node, do this:
first process the left-child sub-node, if present
then append the value of the node, if any
then process the right-child sub-node, if present
In the above pseudo-code, where you see the word "process", you apply the same process to those nodes as described above.
Here's the C# code to process a simple binary tree and append the result to a given linked list:
public void AppendTreeToLinkedList<T>(Node<T> node, LinkedList<T> list)
{
if (node.LeftChild != null)
AppendTreeToLinkedList(node.LeftChild, list);
list.Append(node.Value);
if (node.RightChild != null)
AppendTreeToLinkedList(node.RightChild, list);
}
To get a doubly-liked list that is sorted in the same way as the original tree, C# code:
function Listify(Node n, out Node First, out Node Last)
{
if ( Node.Left != null )
{
Node Tmp;
Listify(Node.Left, out First, out Tmp);
Node.Left = Tmp;
}
else
{
First = Node;
}
if ( Node.Right != null )
{
Node Tmp;
Listify(Node.Right, out Tmp, out Last);
Node.Right = Tmp;
}
else
{
Last = Node;
}
}
You are really asking how do I walk a binary tree. The answer can be found in any book on algorithms and data structures.
/* bst.c: sort the input numbers and print them forward and backward with no duplicates */
#include <stdio.h>
#include <stdlib.h>
struct node {
int key;
struct node *left;
struct node *right;
};
static struct node **bst_find(struct node **root, int key) {
struct node **n;
n = root;
while (*n != NULL && (*n)->key != key) {
if (key < (*n)->key) {
n = &(*n)->left;
} else {
n = &(*n)->right;
}
}
return n;
}
static void bst_insert(struct node **root, int key) {
struct node **n;
n = bst_find(root, key);
if (*n == NULL) {
*n = malloc(sizeof (**n));
(*n)->key = key;
(*n)->left = NULL;
(*n)->right = NULL;
}
}
/* massage the tree rooted at "root" to be a doubly-linked list
* return the leftmost and rightmost nodes via the parameters "leftend" and "rightend"
* bst_flatten() is invoked 2N+1 times, where N is the number of tree elements
*/
static long Flatten_count = 0;
static void bst_flatten(struct node **leftend, struct node **rightend, struct node *root) {
Flatten_count++;
if (root != NULL) {
/* flatten the left side of the tree */
*leftend = root;
bst_flatten(leftend, &root->left, root->left);
/* if necessary, splice "root" onto the right end */
if (root->left != NULL) {
root->left->right = root;
}
/* flatten the right side of the tree */
*rightend = root;
bst_flatten(&root->right, rightend, root->right);
/* if necessary, splice "root" onto the left end */
if (root->right != NULL) {
root->right->left = root;
}
}
}
int main(void) {
int key;
long N = 0;
struct node *root = NULL;
struct node *leftend = NULL;
struct node *rightend = NULL;
struct node *n;
/* read the input into a bst */
while (scanf("%d", &key) == 1) {
N++;
bst_insert(&root, key);
}
/* make a list */
bst_flatten(&leftend, &rightend, root);
/* traverse the list forward */
for (n = leftend; n != NULL; n = n->right) {
printf("%d\n", n->key);
}
/* traverse the list backward */
for (n = rightend; n != NULL; n = n->left) {
printf("%d\n", n->key);
}
fprintf(stderr, "%ld items input, %ld invocations of bst_flatten()\n", N, Flatten_count);
return 0;
}
Assume the tree has nodes containing pointers to nodes called left and right. We'll end up with a list using only the right node pointers.
listify( node )
if node has no children
return
else if node.left == null
listify(node.right)
else if node.right == null
listify(node.left)
mode.right = node.left
else
listify(node.left)
listify(node.right)
temp = node.left
while temp.right != null
temp = temp.right
temp.right = node.right
node.right = node.left
In Scheme, using memoized recursion, an in-order algorithm would be:
(define (tree->list tree)
(define empty-set (list))
(define (copy-to-list tree result-list)
(if (null? tree)
result-list
(copy-to-list (left-branch tree)
(cons (entry tree)
(copy-to-list (right-branch tree)
result-list)))))
(copy-to-list tree empty-set))
This assumes that a tree structure is represented as:
(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
(list entry left right))
N.B. I could have used the literal '() for the empty-set but SO messes up the color coding of the block quoted code.
You can "walk a tree" in many orders, the main ones being pre-, post-, and in-order. Here's some pseudocode for in-order, for example:
def in_walk(tree, doit):
if tree is null: return
in_walk(tree.left, doit)
doit(tree.root)
in_walk(tree.right, doit)
I hope the assumptions in this pseudocode are obvious: a tree has left and right links, which can be null meaning "nothing more to walk here", and a root node; you can pass a function or closure that does the right think (append to a linked list or whatever) given a node argument.

Resources