[基本算法] 二叉树遍历方法

二叉树的遍历包括前序、中序、后序、层次遍历。实现方式一般为递归和循环两种。

接下来给出遍历算法代码,均使用C++编写。


 

二叉树结点

使用leetcode常见的TreeNode

1 struct TreeNode {
2     int val;
3     TreeNode *left;
4     TreeNode *right;
5     TreeNode() : val(0), left(nullptr), right(nullptr) {}
6     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
7     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
8 };

 

先序遍历

先访问根节点,然后访问左子树,最后访问右子树。

递归版本

1 void preOrder(TreeNode *root){
2     if(root!=nullptr){
3         cout<<root->val<<endl;
4         preOrder(root->left);
5         preOrder(root->right);
6     }
7 }

非递归版本一,将左右子节点压入栈中,下一次弹出栈顶进行遍历:

 1 void preOrderLoop(TreeNode *root){
 2     stack<TreeNode*> stk;
 3     stk.push(root);
 4 
 5     TreeNode *p;
 6     while(!stk.empty()){
 7         p=stk.top();
 8         stk.pop();
 9 
10         if(p==nullptr)
11             continue;
12 
13         cout<<p->val<<endl;
14         stk.push(p->right);
15         stk.push(p->left);
16     }
17 }

非递归版本二,遍历左节点之前将子节点压入栈中,当碰到nullptr时弹出栈顶,从其右子节点开始遍历:

(栈中保存的是可能还没访问右子节点的节点)

 1 void preOrderLoop2(TreeNode *root){
 2     stack<TreeNode*> stk;
 3     TreeNode *p=root;
 4 
 5     while(p!=nullptr || !stk.empty()){
 6         while(p!=nullptr){
 7             cout<<p->val<<endl;
 8             // 将根节点压入栈中,便于之后遍历右子树
 9             stk.push(p);
10             p=p->left;
11         }
12         // 若p为null,则从栈中取出节点访问其右节点
13         if(!stk.empty()){
14             p=stk.top();
15             stk.pop();
16             p=p->right;
17         }
18     }
19 }

 

中序遍历

 先访问左子树,然后访问根节点,最后访问右子树

递归版本

1 void inOrder(TreeNode *root){
2     if(root!=nullptr){
3         inOrder(root->left);
4         cout<<root->val<<endl;
5         inOrder(root->right);
6     }
7 }

非递归版本,遍历节点时不先访问值,而是将节点存入栈中,然后继续访问左节点。

当遍历的节点为空时,从栈中弹出节点,访问值并继续访问右节点。

 1 void inOrderLoop(TreeNode *root){
 2     stack<TreeNode*> stk;
 3     TreeNode *p=root;
 4     while(p!=nullptr || !stk.empty()){
 5         while(p!=nullptr){
 6             stk.push(p);
 7             p=p->left;
 8         }
 9         // 当p==nullptr,则左子树已完全访问,应访问根节点和右子树
10         if(!stk.empty()){
11             p=stk.top();
12             stk.pop();
13             cout<<p->val<<endl;
14             p=p->right;
15         }
16     }
17

上面的代码有循环嵌套,可以进行简化:

 1 void inOrderLoop2(TreeNode *root){
 2     stack<TreeNode*> stk;
 3     TreeNode *p=root;
 4     while(p!=nullptr || !stk.empty()){
 5         if(p!=nullptr){
 6             stk.push(p);
 7             p=p->left;
 8         }
 9         else{
10             p=stk.top();
11             stk.pop();
12             cout<<p->val<<endl;
13             p=p->right;
14         }
15     }
16 }

 

 

后序遍历

先访问左子树,然后访问右子树,最后访问根节点

递归版本

1 void postOrder(TreeNode *root){
2     if(root!=nullptr){
3         postOrder(root->left);
4         postOrder(root->right);
5         cout<<root->val<<endl;
6     }
7 }

非递归版本,使用lastVisit保存上次访问的右节点,若从栈中弹出的节点右节点为空或为上次访问的节点,则访值:

 1 void postOrderLoop(TreeNode *root){
 2     stack<TreeNode*> stk;
 3     TreeNode *p=root;
 4     TreeNode *lastVisit=p;
 5 
 6     while(p!=nullptr || !stk.empty()){
 7         while(p!=nullptr){
 8             stk.push(p);
 9             p=p->left;
10         }
11         //左子树访问完毕,出栈访问右子树
12         p=stk.top();
13         //检查是否右子树为空或者已被访问
14         if(p->right==nullptr || p->right==lastVisit){
15             cout<<p->val<<endl;
16             stk.pop();
17             lastVisit=p;
18             p=nullptr;
19         }
20         else{
21             p=p->right;
22         }
23     }
24 }

 

层次遍历

按照二叉树的层次进行遍历,一般是非递归版本:

 1 void levelOrder(TreeNode *root){
 2     vector<TreeNode*> vec;
 3     TreeNode *p;
 4     vec.push_back(root);
 5 
 6     while(vec.size()>0){
 7         vector<TreeNode*> temp;
 8         for(TreeNode* v:vec){
 9             cout<<v->val<<endl;
10             if(v->left!=nullptr) temp.push_back(v->left);
11             if(v->right!=nullptr) temp.push_back(v->right);
12         }
13         swap(vec,temp);
14     }
15 }
posted @ 2021-09-07 17:34  Cheung-10  阅读(2)  评论(0)    收藏  举报