二叉树操作总结

  对于二叉树,有前序、中序、后序三种遍历方法,由于树的定义本身就是递归定义的,故采用递归方法实现三种遍历简洁易懂。若采用非递归访问,则需要使用栈来模拟递归的实现。三种遍历的非递归算法中,前序和后序较容易,而后序相对较难。

  前序遍历 递归 非递归
树的遍历 中序遍历 递归 非递归
后序遍历 递归 非递归
  层次遍历    
计算树高      
 计算结点数      

                      

 

 

 

 

 

1. 前序遍历【访问顺序:根结点-左孩子-右孩子】

  a> 前序遍历递归实现

1 void PreOrderRecursively(BinaryTreeNode *root)
2 {//递归前序遍历[根,左,右]
3     if(root != NULL)
4     {
5         cout << root->data <<" ";
6         PreOrderRecursively(root->pLeft);
7         PreOrderRecursively(root->pRight);
8     }
9 }

  b> 前序遍历非递归实现

 1 void PreOrder(BinaryTreeNode *root)
 2 {//非递归前序遍历:借助于栈,先将根入栈,只要栈不为空,就弹出一个结点,同时将其右孩子、左孩子入栈。
 3  //                   注意:右子树先入栈,以保证右子树在栈中处于左子树的下面[栈:后进先出]
 4     if(root == NULL)
 5         return;
 6     stack<BinaryTreeNode*> s;
 7     s.push(root);//根入栈
 8 
 9     BinaryTreeNode *temp;
10     while(!s.empty())//栈不为空
11     {
12         temp = s.top();//访问栈顶结点
13         cout << temp->data<<" ";
14         s.pop();//出栈
15         if(temp->pRight)
16             s.push(temp->pRight);
17         if(temp->pLeft)
18             s.push(temp->pLeft);
19     }
20 }

2. 中序遍历【访问顺序:左孩子-根结点-右孩子】

  a> 中序遍历递归实现

1 void InOrderRecursively(BinaryTreeNode *root)
2 {//递归中序遍历[左,根,右]
3     if(root != NULL)
4     {
5         InOrderRecursively(root->pLeft);
6         cout << root->data << " ";
7         InOrderRecursively(root->pRight);
8     }
9 }

  b> 中序遍历非递归实现

 1 void InOrder(BinaryTreeNode *root)
 2 {/*
 3     非递归中序遍历:
 4         对任一结点P,
 5         1)若其左孩子不为空,则将P入栈,将其左孩子置为当前P,然后对当前结点P进行相同处理;
 6         2) 若其左孩子为空,则取栈顶元素并出栈,访问该栈顶结点,然后将当前的P职位栈顶结点的右孩子
 7         3) 直到P为NULL且栈为空,则遍历结束
 8  */
 9     if(root == NULL)
10         return;
11 
12     stack<BinaryTreeNode*> s;
13     BinaryTreeNode *cur = root;
14 
15     while(cur != NULL || !s.empty())//P为NULL且栈为空时终止
16     {
17         while(cur != NULL)//直到达到最左边
18         {
19             s.push(cur);
20             cur = cur->pLeft;
21         }
22 
23         if(!s.empty())//第二种情况
24         {
25             cur = s.top();
26             cout<<cur->data<<" ";
27             s.pop();
28             cur = cur->pRight;
29         }
30     }
31 }

3. 后序遍历【访问顺序:左孩子-右孩子-根结点】

  a> 后序遍历递归实现

1 void PostOrderRecursively(BinaryTreeNode *root)
2 {//递归后序遍历[左,右,根]
3     if(root != NULL)
4     {
5         PostOrderRecursively(root->pLeft);
6         PostOrderRecursively(root->pRight);
7         cout << root->data << " ";
8     }
9 }

  b>后序遍历非递归实现

 1 void PostOrder(BinaryTreeNode *root)
 2 {/*
 3     非递归后序遍历:[难点:保证根结点在左孩子和右孩子被访问之后才能被访问]
 4         根结点入栈
 5         对任一栈顶元素P:
 6         1)若P不存在左孩子和右孩子,直接访问它;或P存在左孩子或右孩子,但其左孩子或右孩子已被访问过,
 7           同样直接访问它。然后将P出栈,pre置为P
 8         2)若并非1)中的两种情况,则将P的右孩子和左孩子依次入栈,以保证每次取栈顶元素时,左孩子在右孩子
 9           之前被访问,左孩子和右孩子都在根结点之前被访问        
10  */
11     if(root == NULL)
12         return;
13     
14     stack<BinaryTreeNode*> s;
15     BinaryTreeNode *cur;
16     BinaryTreeNode *pre = NULL;//指示上次被访问的结点
17     s.push(root);
18 
19     while(!s.empty())//栈不为空时循环
20     {
21         cur = s.top();//取栈顶元素
22 
23         //当前结点无孩子结点或孩子节点都已被访问
24         if((cur->pLeft == NULL && cur->pRight == NULL) || 
25             (pre!=NULL && (pre==cur->pLeft || pre==cur->pRight)))
26         {
27             cout << cur->data<<" ";//访问该栈顶元素
28             s.pop();//出栈
29             pre = cur;//更新pre
30         }
31         else
32         {
33             if(cur->pRight != NULL)//右孩子入栈
34                 s.push(cur->pRight);
35             if(cur->pLeft != NULL)//左孩子入栈
36                 s.push(cur->pLeft);
37         }
38     }
39 }

4.层次遍历

 1 void LevelOrder(BinaryTreeNode *root)
 2 {//层次遍历:只有非递归的方法
 3  //借助队列来实现:根结点入队,只要队列不为空,访问队首元素并出队,将其左孩子和右孩子依次入队
 4     if(root == NULL)
 5         return;
 6     queue<BinaryTreeNode *> q;
 7     q.push(root);
 8     BinaryTreeNode *cur;
 9     while(!q.empty())
10     {
11         cur = q.front();//队首元素
12         cout << cur->data << " ";
13         q.pop();//出队
14         if(cur->pLeft != NULL)
15             q.push(cur->pLeft);
16         if(cur->pRight != NULL)
17             q.push(cur->pRight);
18     }
19 }

5.计算树高和结点数

 1 int TreeHeight(BinaryTreeNode *root)//计算树高
 2 {//计算树高
 3     if(root == NULL)//空树
 4         return 0;
 5     int heightLeft = TreeHeight(root->pLeft);//左子树高度
 6     int heightRight = TreeHeight(root->pRight);//右子树高度
 7     if(heightLeft > heightRight)
 8         return ++heightLeft;
 9     else
10         return ++heightRight;
11 }
12 
13 int CountNode(BinaryTreeNode *root)
14 {//计算树的结点数
15     if(root == NULL)
16         return 0;
17     return 1+CountNode(root->pLeft)+CountNode(root->pRight);
18 }

 

【 完整代码】

  1 #include "stdafx.h"
  2 #include <iostream>
  3 #include <stack>
  4 #include <queue>
  5 using namespace std;
  6 
  7 struct BinaryTreeNode
  8 {
  9     int data;
 10     BinaryTreeNode *pLeft;//左子树
 11     BinaryTreeNode *pRight;//右子树
 12 
 13     BinaryTreeNode(int a):data(a),pLeft(NULL),pRight(NULL) {}
 14 };
 15 
 16 void CreateBinaryTree(BinaryTreeNode **root)//二级指针作为函数参数
 17 {//按先序遍历创建二叉树:操作不是很容易懂!!!
 18     char ch;//要插入的数据
 19     //cout << "input root data:";
 20     cin >> ch;
 21     if(ch == '#')//表示为空
 22         *root = NULL;
 23     else
 24     {
 25         *root = new BinaryTreeNode(ch);
 26         cout << "input left child:";//此时不接受输入cin!!!
 27         CreateBinaryTree(&((*root)->pLeft));
 28         cout << "input right child:";
 29         CreateBinaryTree(&((*root)->pRight));
 30     }
 31 }
 32 
 33 
 34 void ConnectTreeNodes(BinaryTreeNode *pRoot,BinaryTreeNode *pLeft,BinaryTreeNode *pRight)
 35 {
 36     if(pRoot != NULL)
 37     {
 38         //if(pLeft)//不是pRoot->pLeft
 39             pRoot->pLeft = pLeft;
 40         //if(pRight)
 41             pRoot->pRight = pRight;
 42     }
 43 }
 44 
 45 void PreOrderRecursively(BinaryTreeNode *root)
 46 {//递归前序遍历[根,左,右]
 47     if(root != NULL)
 48     {
 49         cout << root->data <<" ";
 50         PreOrderRecursively(root->pLeft);
 51         PreOrderRecursively(root->pRight);
 52     }
 53 }
 54 
 55 void PreOrder(BinaryTreeNode *root)
 56 {//非递归前序遍历:借助于栈,先将根入栈,只要栈不为空,就弹出一个结点,同时将其右孩子、左孩子入栈。
 57  //                   注意:右子树先入栈,以保证右子树在栈中处于左子树的下面[栈:后进先出]
 58     if(root == NULL)
 59         return;
 60     stack<BinaryTreeNode*> s;
 61     s.push(root);//根入栈
 62 
 63     BinaryTreeNode *temp;
 64     while(!s.empty())//栈不为空
 65     {
 66         temp = s.top();//访问栈顶结点
 67         cout << temp->data<<" ";
 68         s.pop();//出栈
 69         if(temp->pRight)
 70             s.push(temp->pRight);
 71         if(temp->pLeft)
 72             s.push(temp->pLeft);
 73     }
 74 }
 75 

 76 void InOrderRecursively(BinaryTreeNode *root)
 77 {//递归中序遍历[左,根,右]
 78     if(root != NULL)
 79     {
 80         InOrderRecursively(root->pLeft);
 81         cout << root->data << " ";
 82         InOrderRecursively(root->pRight);
 83     }
 84 }
 85 
 86 void InOrder(BinaryTreeNode *root)
 87 {/*
 88     非递归中序遍历:
 89         对任一结点P,
 90         1)若其左孩子不为空,则将P入栈,将其左孩子置为当前P,然后对当前结点P进行相同处理;
 91         2) 若其左孩子为空,则取栈顶元素并出栈,访问该栈顶结点,然后将当前的P职位栈顶结点的右孩子
 92         3) 直到P为NULL且栈为空,则遍历结束
 93  */
 94     if(root == NULL)
 95         return;
 96 
 97     stack<BinaryTreeNode*> s;
 98     BinaryTreeNode *cur = root;
 99 
100     while(cur != NULL || !s.empty())//P为NULL且栈为空时终止
101     {
102         while(cur != NULL)//直到达到最左边
103         {
104             s.push(cur);
105             cur = cur->pLeft;
106         }
107 
108         if(!s.empty())//第二种情况
109         {
110             cur = s.top();
111             cout<<cur->data<<" ";
112             s.pop();
113             cur = cur->pRight;
114         }
115     }
116 }
117 
118 void PostOrderRecursively(BinaryTreeNode *root)
119 {//递归后序遍历[左,右,根]
120     if(root != NULL)
121     {
122         PostOrderRecursively(root->pLeft);
123         PostOrderRecursively(root->pRight);
124         cout << root->data << " ";
125     }
126 }
127 
128 void PostOrder(BinaryTreeNode *root)
129 {/*
130     非递归后序遍历:[难点:保证根结点在左孩子和右孩子被访问之后才能被访问]
131         根结点入栈
132         对任一栈顶元素P:
133         1)若P不存在左孩子和右孩子,直接访问它;或P存在左孩子或右孩子,但其左孩子或右孩子已被访问过,
134           同样直接访问它。然后将P出栈,pre置为P
135         2)若并非1)中的两种情况,则将P的右孩子和左孩子依次入栈,以保证每次取栈顶元素时,左孩子在右孩子
136           之前被访问,左孩子和右孩子都在根结点之前被访问        
137  */
138     if(root == NULL)
139         return;
140     
141     stack<BinaryTreeNode*> s;
142     BinaryTreeNode *cur;
143     BinaryTreeNode *pre = NULL;//指示上次被访问的结点
144     s.push(root);
145 
146     while(!s.empty())//栈不为空时循环
147     {
148         cur = s.top();//取栈顶元素
149 
150         //当前结点无孩子结点或孩子节点都已被访问
151         if((cur->pLeft == NULL && cur->pRight == NULL) || 
152             (pre!=NULL && (pre==cur->pLeft || pre==cur->pRight)))
153         {
154             cout << cur->data<<" ";//访问该栈顶元素
155             s.pop();//出栈
156             pre = cur;//更新pre
157         }
158         else
159         {
160             if(cur->pRight != NULL)//右孩子入栈
161                 s.push(cur->pRight);
162             if(cur->pLeft != NULL)//左孩子入栈
163                 s.push(cur->pLeft);
164         }
165     }
166 }
167 
168 void LevelOrder(BinaryTreeNode *root)
169 {//层次遍历:只有非递归的方法
170  //借助队列来实现:根结点入队,只要队列不为空,访问队首元素并出队,将其左孩子和右孩子依次入队
171     if(root == NULL)
172         return;
173     queue<BinaryTreeNode *> q;
174     q.push(root);
175     BinaryTreeNode *cur;
176     while(!q.empty())
177     {
178         cur = q.front();//队首元素
179         cout << cur->data << " ";
180         q.pop();//出队
181         if(cur->pLeft != NULL)
182             q.push(cur->pLeft);
183         if(cur->pRight != NULL)
184             q.push(cur->pRight);
185     }
186 }
187 
188 int TreeHeight(BinaryTreeNode *root)//计算树高
189 {//计算树高
190     if(root == NULL)//空树
191         return 0;
192     int heightLeft = TreeHeight(root->pLeft);//左子树高度
193     int heightRight = TreeHeight(root->pRight);//右子树高度
194     if(heightLeft > heightRight)
195         return ++heightLeft;
196     else
197         return ++heightRight;
198 }
199 
200 int CountNode(BinaryTreeNode *root)
201 {//计算树的结点数
202     if(root == NULL)
203         return 0;
204     return 1+CountNode(root->pLeft)+CountNode(root->pRight);
205 }
206 
207 BinaryTreeNode* TestCreate()
208 {//建树的测试函数
209     /*
210         建树
211                 1
212               /   
213             2       3
214            /        
215           4   5       6       
216          /
217         7
218     */
219     BinaryTreeNode* pNodeA1 = new BinaryTreeNode(1);
220     BinaryTreeNode* pNodeA2 = new BinaryTreeNode(2);
221     BinaryTreeNode* pNodeA3 = new BinaryTreeNode(3);
222     BinaryTreeNode* pNodeA4 = new BinaryTreeNode(4);
223     BinaryTreeNode* pNodeA5 = new BinaryTreeNode(5);
224     BinaryTreeNode* pNodeA6 = new BinaryTreeNode(6);
225     BinaryTreeNode* pNodeA7 = new BinaryTreeNode(7);
226 
227     ConnectTreeNodes(pNodeA1, pNodeA2, pNodeA3);
228     ConnectTreeNodes(pNodeA2, pNodeA4, pNodeA5);
229     ConnectTreeNodes(pNodeA3, NULL, pNodeA6);
230     ConnectTreeNodes(pNodeA4, pNodeA7,NULL);
231 
232     cout << endl << "PreOrder:";
233     PreOrder(pNodeA1);//1 2 4 7 5 3 6
234     cout <<  endl << "InOrder:";
235     InOrder(pNodeA1);//7 4 2 5 1 3 6
236     cout << endl <<  "PostOrder:";
237     PostOrder(pNodeA1);//7 4 5 2 6 3 1
238     cout <<  endl << "LevelOrder:";
239     LevelOrder(pNodeA1);//1 2 3 4 5 6 7
240 
241     return pNodeA1;//因为没有delete,故返回后仍可访问
242 }
243 int main()
244 {
245     BinaryTreeNode *root = TestCreate();//定义根结点
246     
247     cout <<  endl << "LevelOrder:";
248     LevelOrder(root);//1 2 3 4 5 6 7
249     
250 }
View Code

 

 

参考:http://blog.csdn.net/xiajun07061225/article/details/12760627

     http://blog.csdn.net/hackbuteer1/article/details/6583988

原文地址:https://www.cnblogs.com/dreamrun/p/4586493.html