Binary Tree iterator Algorithm

Source: Internet
Author: User

Binary Tree pre-order, middle-order, and subsequent traversal are basic issues in algorithms and data structures. Recursive Binary Tree traversal algorithms are even more typical applications.

Assume that the Binary Tree node is defined as follows:

 
 
  1. struct Node { 
  2.     int value; 
  3.     Node *left; 
  4.     Node *right; 

 
 
  1. void inorder_traverse(Node *node) { 
  2.     if (NULL != node->left) { 
  3.         inorder_traverse(node->left); 
  4.     } 
  5.     do_something(node); 
  6.     if (NULL != node->right) { 
  7.         inorder_traverse(node->right); 
  8.     } 
  9.  

The pre-order and post-order traversal algorithms are similar.

However, Traversal Algorithms alone are not enough. In many applications, we also need to abstract the traversal itself. If there is a sum function, we hope it can be applied to different data structures, such as linked lists, arrays, and Binary Trees. At this time, we can abstract the concept of Iterator, throughThe iterator decouples the algorithm from the data structure.So that the general algorithm can be applied to different types of data structures. We can define the sum function:

 
 
  1. int sum(Iterator it) 

As a linear structure, the linked list has a simple and intuitive implementation of its iterator, while the implementation of the Binary Tree iterator is not so easy. We cannot directly convert recursive traversal into an iterator. This is because the recursive traversal process of the binary tree is automatically performed by the compiler on the call stack. Programmers lack sufficient control over this process. In this case, if we can control the inbound and outbound stack of the entire call stack, will it achieve the purpose of control? Let's take a look at the non-recursive algorithm of binary tree traversal:

 
 
  1. Void inorder_traverse_nonrecursive (Node * node ){
  2. Stack stack;
  3. Do {
  4. // Node indicates the child tree to be processed. The left child is pushed down to the stack layer by layer, which corresponds to the left subtree recursion of the recursive algorithm.
  5. While (NULL! = Node ){
  6. Stack. push (node );
  7. Node = node-> left;
  8. }
  9. Do {
  10. Node * top = stack. top ();
  11. Stack. pop (); // The top of the pop-up stack, corresponding to the function returned by the recursive algorithm
  12. Do_something (top );
  13. If (NULL! = Top-> right ){
  14. Node = top-> right; // set the current subtree to the right child of the node that has just been traversed.
  15. Break;
  16. }
  17. }
  18. While (! Stack. empty ());
  19. }
  20. While (! Stack. empty ());
  21. }

Through the stack-based non-recursive algorithm, we have obtained control over the traversal process. How can we encapsulate it as an iterator? The key here is that the process of understanding traversal is represented by the stack state, so it is clear that the iterator should contain a stack structure, and each iteration is a stack operation. Assume that the iterator interface is:

 
 
  1. class Iterator { 
  2.     public: 
  3.         virtual Node* next() = 0; 
  4. }; 

The following is an implementation of the ordinal traversal iterator in a binary tree:

 
 
  1. class InorderIterator : public Iterator { 
  2.     public: 
  3.         InorderIterator(Node *node) { 
  4.             Node *current = node; 
  5.             while (NULL != current) { 
  6.                 mStack.push(current); 
  7.                 current = current->left; 
  8.             } 
  9.         } 
  10.         virtual Node* next() { 
  11.             if (mStack.empty()) { 
  12.                 return NULL; 
  13.             } 
  14.             Node *top = mStack.top(); 
  15.             mStack.pop(); 
  16.             if (NULL != top->right) { 
  17.                 Node *current = top->right; 
  18.                 while (NULL != current) { 
  19.                     mStack.push(current); 
  20.                     current = current->left; 
  21.                 } 
  22.             } 
  23.             return top; 
  24.          } 
  25.     private: 
  26.         std::stack<Node*> mStack; 
  27. }; 

Next, let's take a look at the time and space complexity of this iterator. Obviously, since the stack needs to store at most all nodes, the space complexity is O (n. So what is the time complexity? One next () call can also perform n stack operations at most, and the entire traversal process requires n next () calls (), so is the time complexity of the entire iterator O (n ^ 2? The answer is no! Because each node only goes into and out of the stack once, the time complexity of the entire iteration process is still O (n ). In fact, this is exactly the same as the time-space complexity of recursive traversal.

In addition to the explicit use of stacks to control the code execution sequence, there are more direct practices in languages C # And Python that support yield semantics. The following Python Implementation of sequential traversal based on yield Binary Tree:

 
 
  1. // Python 
  2. def inorder(t): 
  3.     if t: 
  4.         for x in inorder(t.left): 
  5.             yield x 
  6.         yield t.label 
  7.         for x in inorder(t.right): 
  8.             yield x 

A common explanation of the difference between yield and return is that the system retains the function call status when yield returns. The next time this function is called, it will continue to be executed from the last execution point, this is a process control semantics that is completely different from Stack semantics. We know that Python interpreters are written in C, but C does not support yield semantics. How does the interpreter support yield? With the above experience of transforming recursive traversal into iterative traversal, I believe you have guessed that the Python interpreter must have performed some transformation on the yield code. If you can implement recursion and non-recursion, try to write a Compilation Program to convert yield code to non-yield code.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.