Binary tree preface, for, through non-recursive wording book a thorough analysis

Source: Internet
Author: User

Preface

The first two articles in the two fork tree and the two-fork search tree already involve three traversal of the two-fork tree. Recursive notation, just to understand the idea, a few lines of code. But the non-recursive wording is very not easy. Here is a special summary of their non-recursive interpretation of the wording. Of The non-recursive syntax of the middle sequence traversal is the simplest, and the most difficult to traverse. Our discussion is based on this:

Binary Tree nodetypedef struct node{int data;struct node* lchild;  Left child struct node* rchild;  Right child}btnode;

First of all. One thing is clear: non-recursive writing is bound to use the stack, this should not be too much explanation. We first fancy the sequential traversal:

Middle Sequence TraversalAnalysis

Recursive definition of the middle sequence traversal: first left subtree. After the root node, and then the right subtree. How do you write non-recursive code? Bottom line: Let the code follow the thought . What is our thinking? Thinking is the path of the middle sequence traversal. If you have a binary tree in front of you, you are now asked to write down its sequence of middle sequence traversal.

If you have a thorough understanding of the middle order traversal, you must first find the bottom node of Zuozi.

Then the following code is taken for granted:

middle Order Code Snippet (i)    
btnode* p = root;  P point to root stack<btnode*> s;  The stack in the STL//is traversed to the bottom of the Zuozi, the side traverses the edge to save the root node to the stack while (p) {S.push (p);p = P->lchild;}

The reason to save the root node is: the need for the middle sequence traversal. After traversing the left dial hand tree, you need to enter the right subtree with the root node. The code goes here, the pointer p is empty, at this time there are only two cases:


Description

    1. Only the necessary nodes and edges are given, and the other edges and nodes are irrelevant to the discussion and do not have to be drawn.
    2. You may think that the recent save node in figure A must not be the root node. Suppose you look at the tree, the Binary Tree Foundation, and use the concept of an extended binary tree to explain it.

      In short, there is no point in this nonsense.

    3. The entire binary tree has only one root node where it can be drawn to figure A.
Think carefully, the left sub-tree of the binary tree, the bottom is not two kinds of situation? In any case, the stack will be out at this point. and visit the node. This node is the first node in the sequence of the middle order.

According to our thinking, the code should look like this:

p = s.top (); S.pop (); cout << p->data;

our thinking goes on, and the two images differ from each other:1. An interview in Figure A is a left child. Follow the order of the in-sequence traversal, and you should then visit its root node. There is also a node in figure A. Happily, it has been saved in the stack. We just need this code and the same code as in the previous step:
p = s.top (); S.pop (); cout << p->data;
The left child and Root were interviewed. And then there's the right kid. Next, just a code:p=p->rchild; in the right subtree, and a new round of code snippets (i), Code Snippets (ii) ... Until the stack is empty and p is empty.


2. Look at figure B again. Because there is no left child, the root node is the first in the sequence, and then directly into the right subtree:p=p->rchild; In the right sub-tree. A new round of code snippet (i), code snippet (ii)... until the stack is empty and p is empty. Thinking here, it seems very unclear, really want to distinguish it? The following code snippet (ii) is based on figure A:

p = s.top (); S.pop (); cout << p->data;p = S.top (); S.pop (); cout << p->data;p = p->rchild;

according to Figure B. This is also the code snippet (ii):
p = s.top (); S.pop (); cout << p->data;p = p->rchild;

We can summarize: the traversal process is a loop. And the loop body is formed by code snippet (i), code snippet (ii). Loop until the stack is empty and p is empty.

Different processing methods are very maddening, can be unified processing it? really is able to! Recall that the expansion of the binary tree, is not every node can be regarded as the root node it? So, the code just needs to be uniformly written in this form of Figure B.

That is, the code snippet (ii) Unification is this: the middle Sequence Code snippet (ii)

p = s.top (); S.pop (); cout << p->data;p = p->rchild;

accreditations, the past theoretical test. The code snippet for figure A (ii) can also be written in Figure B for the reason that P is definitely empty since it is a leaf node,p=-=p->rchild;.

is empty, do you still have to go through a new round of code snippets (i)? Obviously not needed.

(because the loop condition is not met) then go directly to the code snippet (ii). See!

It's the same at the end.

Or two consecutive times out of the stack.

See here. Think about it carefully. I'm sure you'll make it clear.
It is not difficult to write the traversal loop body at this time:     

btnode* p = root;stack<btnode*> s;while (!s.empty () | | p) {//code snippet (i) has been traversed to the bottom of the Zuozi, the side traversed the edge to save the root node to the stack while (p) {S.push (p);p = P->lchild;} Code Snippet (ii) When P is empty, the description has reached the bottom of the Zuozi, then the stack is required if (!s.empty ()) {p = s.top (); S.pop (); cout << SETW (4) << p->data;// Enter the right subtree and start a new round of left subtree traversal (this is recursive self-realization) P = P->rchild;}}

think carefully, the above code is based on the direction of our thinking and write it? Coupled with the detection of boundary conditions, the sequence traversal of the complete code in a non-recursive form is this:Middle Sequence traversal code one        
Middle sequence traversal void InOrderWithoutRecursion1 (btnode* root) {///empty tree if (root = null) return;//tree non-empty btnode* p = root;stack<btnode* > S;while (!s.empty () | | p) {//has been traversed to the bottom of Zuozi, the side traversed the edge to save the root node to the stack while (p) {S.push (p);p = P->lchild;} When P is empty, the description has reached the bottom of the Zuozi, then the stack is required if (!s.empty ()) {p = s.top (); S.pop () cout << SETW (4) << p->data;//into the right subtree, Start a new round of left subtree traversal (this is recursive self-implementation) P = P->rchild;}}}

Congratulations to you. You're done. The middle sequence iterates through non-recursive forms of code. Is it difficult to recall? The next piece of code is essentially the same, and I'm sure I don't have to explain it. You can read it, too.

Middle Sequence Traversal code two    

Middle sequence traversal void InOrderWithoutRecursion2 (btnode* root) {///empty tree if (root = null) return;//tree non-empty btnode* p = root;stack<btnode* > S;while (!s.empty () | | p) {if (p) {S.push (p);p = P->lchild;} Else{p = S.top (); S.pop () cout << SETW (4) << p->data;p = P->rchild;}}

Pre-sequence traversalAnalysisRecursive definition of a pre-order traversal: the root node first. After the left subtree, and then right sub-tree.

With the basis of the middle sequence traversal, it is not necessary for me to guide it like a sequential traversal.

First of all. We traverse the left sub-tree, Edge-traversing edge printing, and the root node into the stack, the next need to use these nodes into the right subtree to open a new round of cycle. Also have to repeat: all nodes can be regarded as the root node.

According to the direction of thinking, write code snippet (i): Pre-order code snippet (i)

Edge traversal edge printing, and stored in the stack, you need to use these root nodes (do not doubt that OH) into the right subtree while (p) {cout << setw (4) << P->data;s.push (p);p = p-> Lchild;}

Next is: Out of the stack, according to the top node into the right sub-tree. Pre-order code snippet (ii)   
When P is empty, the root and left subtrees are traversed, and the right subtree is entered if (!s.empty ()) {p = s.top (); S.pop ();p = P->rchild;}

The same way. The code snippet (i) (ii) forms a complete loop body.

So far. It is not difficult to write a complete pre-sequence traversal of the non-recursive notation. Pre-sequence traversal code one    

void PreOrderWithoutRecursion1 (btnode* root) {if (root = NULL) return; btnode* p = root;stack<btnode*> s;while (!s.empty () | | p) {//edge traversing edge printing. and deposited in the stack, you need to use these root nodes (do not doubt that OH) into the right subtree while (p) {cout << setw (4) << P->data;s.push (p);p = P->lchild;} When P is empty, it indicates that both the root and the left subtree are traversed, and that the right subtree is entered if (!s.empty ()) {p = s.top (); S.pop ();p = P->rchild;}} cout << Endl;}

The following is the essence of the same code:Pre-sequence traversal code two    
Pre-order traversal void PreOrderWithoutRecursion2 (btnode* root) {if (root = NULL) return; btnode* p = root;stack<btnode*> s;while (!s.empty () | | p) {if (p) {cout << setw (4) << P->data;s.push (p) ;p = P->lchild;} Else{p = S.top (); S.pop ();p = P->rchild;}} cout << Endl;}

The use of this notation in a binary tree is slightly different and essentially the same:Pre-sequence traversal code three 

void PreOrderWithoutRecursion3 (btnode* root) {if (root = = NULL) return;stack<btnode*> s; btnode* p = root;s.push (root), while (!s.empty ())  //Loop End condition is not the same as the first two {//This sentence indicates that P is always non-empty in the loop cout << SETW (4) << P- >data;/* Stack features: Advanced after the first access to the root node of the right subtree after being interviewed */if (P->rchild) s.push (p->rchild); if (p->lchild) p = p->lchild;else {//Left dial Hand tree interview is over. Access right subtree P = s.top (); S.pop ();}} cout << Endl;}

finally enter the most difficult post-traversal:Post-post traversalAnalysispost-sequential traversal recursive definition: first left subtree, then right subtree, then root node. The difficulty of the post-sequential traversal is that the last visited node is located in the left subtree. or the right subtree. If it is located in the left subtree. You need to skip the root node. Go to the right subtree first, then go back to the root node, or if you are in the right subtree, visit the root node directly. Look directly at the code, the code has a specific gaze. Post- traversal code one   
Post-post traversal void postorderwithoutrecursion (btnode* root) {if (root = NULL) return;stack<btnode*> s;//pcur: Current Access node, Plastvisit: Last visited node btnode* pcur, *plastvisit;//pcur = root;pcur = Root;plastvisit = null;//First move pcur to Zuozi bottom while (pCur) { S.push (pcur);p cur = pcur->lchild;} while (!s.empty ()) {//goes here, Pcur is empty and has traversed to the bottom of the left subtree (as an extended binary tree). Plastvisit) {cout << setw (4) << pcur->data;//Change recently visited node plastvisit = pcur;} /* The Else statement here can be replaced with conditional else if:else if (pcur->lchild = = plastvisit)//Joz just been interviewed, you need to go to the right subtree first (the root node needs to be re-entered the stack) Because: the above conditions do not pass, it must be the following conditions to meet.

Think carefully! */else{//root node again into the stack s.push (pcur);//Enter the right subtree. And it is certain that the right subtree must not be empty pcur = Pcur->rchild;while (pcur) {s.push (pcur);p cur = Pcur->lchild;}}} cout << Endl;}


Here's another idea of the code.

The idea is to attach a tag (left,right) to each node. Assuming that the left subtree of the node has been visited, the flag is set to "right", and if it has been visited, then it is marked as true.

Obviously, only if the node's mark bit is right, you can access the node, otherwise you must first enter its subtree.

See the gaze in the code for specifics. Post- traversal code two

Define enum Type: Tagenum tag{left,right};//define the new type yourself. Encapsulates a two-fork tree node and tag together with a TypeDef struct{btnode* node; tag tag;} Tagnode;    Post-post traversal of  void PostOrderWithoutRecursion2 (btnode* root) {if (root = NULL) return;stack<tagnode> s; Tagnode Tagnode; btnode* p = root;while (!s.empty () | | p) {while (p) {tagnode.node = p;//the node Zuozi was interviewed Tagnode.tag = Tag::left;s.push (Tagnode); p = p->lchild;} Tagnode = S.top (); S.pop ();//Zuozi was interviewed. You also need to go to the right subtree if (Tagnode.tag = = Tag::left) {//displace tag Tagnode.tag = tag::right;//again into the stack s.push (tagnode);p = tagnode.node;//into right subtree p = P->rchild;} else//the right subtree has been interviewed, you can access the current node {cout << SETW (4) << (tagnode.node)->data;//empty. Again out of the stack (this step is to understand the difficulty) P = NULL;}} cout << Endl;} <span style= "font-family: ' Courier New '; "> </span>
SummaryThere is always a huge gap between thinking and code.

Generally thinking is correct, clear, but it is not easy to write the correct code.

If we want to get over this chasm, just try and learn from it, there is no other way.

The following points are key to understanding the above code:

    1. All nodes can be considered as parent nodes (leaf nodes can be considered as two child-free parent nodes).
    2. Compare the code of the same algorithm.

      The nature of the algorithm can often be seen in differences.

    3. Try to change the code according to your own understanding.

      Write your own understanding of the code.

      It's written. That's the real master.


Reprint Please indicate the source, this article address: http://blog.csdn.net/zhangxiangdavaid/article/details/37115355

Columns folder:

    • Data structure and algorithm folders
    • C pointer



Copyright notice: This article blog original articles, reproduced, reproduced please indicate the source.

Binary tree preface, for, through non-recursive wording book a thorough analysis

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.