Morris traversal: traverse binary tree inorder with no recursion and O(1) space

参考:http://pthread.blog.163.com/blog/static/169308178201210112045787/

 

Most textbooks mention that binary tree can be traversed using recursion or , using stack without recursion. The recursive procedure is simple to write, and the stack version use extra space. 

There's also a very well designed algorithm that traverse a binary tree inorder without recursion and yet use only O(1) space -- Morris Traversal.  In this traversal, we first create links to inorder successor and print the data using these links, and finally revert the changes to restore original tree.

 

1. Initialize current as root 
2. While current is not NULL
   If current does not have left child
      a) Print current’s data
      b) Go to the right, i.e., current = current->right
   Else
      a) Make current as right child of the rightmost node in current's left subtree
      b) Go to this left child, i.e., current = current->left
The algorithm is also very easy to implementation:

template<typename T>
void morris_traversal(bst_node_t<T>* root)
{
bst_node_t<T>* current = root;
while (current) {
if (!current->left) {
std::cout << current->data << " ";
current = current->right;
} else {
bst_node_t<T>* it = current->left;
while (it->right && it->right != current) {
it = it->right;
}
if (!it->right) {
it->right = current;
current = current->left;
} else {
std::cout << current->data << " ";
it->right = NULL;
current = current->right;
}
}
}
}

 
But however, this algorithm is not so easy to understand. Why every time we encounter a node that has both right child and left child, we have to set current node as right child of the right most node of the current's left subtree? How does this algorithm restore the tree after we  temporarily change the tree structure?
 
Here we give some pictures to demonstrate this process:
 
Morris traversal: traverse binary tree inorder with no recursion and O(1) space_第1张图片
 
 At the beginning, we start from the root node of the tree as current.
 
 
 
 
 
 
 
 
 
Morris traversal: traverse binary tree inorder with no recursion and O(1) space_第2张图片
 
Second, we find that node 8(current) has both left and right child, so we set node 8 as right child of the right most node of the left subtree, that's node 7.
 

/*

    here current points to node 8,it to node 3
*/
bst_node_t<T>* it = current->left;
/*
    go to che right most child of node 3 that is node 7
*/
while (it->right && it->right != current) {
    it = it->right;
}
/*
    here it points to node 7, current to node 8
*/
if (!it->right) {
    /*
        set current(node 8) as right child of node 7, notice
        that node 8's left child pointer still points to node 3
     */
    it->right = current;
    /*
        current goes left, that is, current points to node 3
    */
    current = current->left;
}
 
Morris traversal: traverse binary tree inorder with no recursion and O(1) space_第3张图片
 

Repeat the process above, with current node 3, go left child of current node, that is node 1. Then we find that node 1 has no right child. 

 
So we set node 3 as node 1's left right child and set current as node 1.Node 1 has no left child, so we goes into this piece of code, and set current as node 3
 

if (!current->left) {
std::cout << current->data << " ";
current = current->right;
}

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Morris traversal: traverse binary tree inorder with no recursion and O(1) space_第4张图片
As node 3 goes to its left most child and find itself, which means that we visit node 3 in the second time, so here we restore the tree by set node 1's right child to NULL, and visit node 3.
 
 

/*
current => node 3
it => node 1
*/
bst_node_t<T>* it = current->left;
/*
here we find that it->right = node 3 = current
so break the loop
*/
while (it->right && it->right != current) {
it = it->right;
}
if (!it->right) {
it->right = current;
current = current->left;
} else {
/*
we visit node 3 in the second time, thus print data
*/
std::cout << current->data << " ";
/*
adjust node 1's right child pointer to null as it originally be
*/
it->right = NULL;
/*
we complete traversal left child of node 3, current goes right, that is node 5
*/
current = current->right;
}

 

 

Here we have covered each condition of Morris Traversal. The loop continues and the whole tree will be traversed and restored.

你可能感兴趣的:(binary)