遍历是面试和笔试经常考的东西,其实也不难,但是如果不能了解透彻的话,在面试中还是会被面试官难倒。所以,下面对遍历总结一下。遍历分为三种方式分别为:前序遍历,中序遍历和后序遍历,分类的依据主要是根据二叉树的根节点和两个叶子节点访问的顺序来定的,这里的前,中,后是指根节点的访问顺序。如果根节点先被访问,然后访问左子树再访问右子树就是先序遍历,如果先访问左子树,然后访问根节点,最后访问右子树就是中序遍历,如果先访问左子树,再访问右子树,最后访问根节点则是后序遍历,这些是二叉树遍历的基本概念。
二叉树遍历一般用递归的思想比较容易理解,我们需要递归的遍历左子树和右子树,那么这三种遍历的方式的区别是输出结果的语句和访问左子树以及右子树的顺序。如果放在递归左子树和右子树的前面就是前序遍历,如果放在二者中间就是中序遍历,如果放在后面就是后序遍历。这是比较容易理解的,代码也比较好写。但是,面试官往往会让你写非递归版本,这样的话就需要对数据结构和对二叉树的遍历有比较深的理解。
二叉树的非递归版本一般都是借用栈这种数据结构来完成的,通过其先进后出的特性来完成二叉树的遍历。
首先,我们需要建立一颗二叉树,我写成了头文件
#ifndef CREATTREE_H_INCLUDED
#define CREATTREE_H_INCLUDED
#include<bits/stdc++.h>
using namespace std;
struct TreeNode{
char data;
struct TreeNode *left, *right;
};
void CreateBiTree(TreeNode *&T)
{
char ch;
cin >> ch;
if (ch == '#')
T = nullptr;
else
{
T = new TreeNode();
T -> data = ch;
CreateBiTree(T -> left);
CreateBiTree(T -> right);
}
}
#endif // CREATTREE_H_INCLUDED
这里使用递归的方法以先序遍历的方式创建的。
下面是非递归版本的遍历方式
#include<bits/stdc++.h>
#include "CreatTree.h"
using namespace std;
//前序遍历非递归
void PreOrder(TreeNode *T){
TreeNode *p = T;
stack<TreeNode*> st;
while(p || !st.empty()){
if(p != NULL){
st.push(p);
cout << p -> data << endl;
p = p -> left;
}
else{
p = st.top();
st.pop();
p = p -> right;
}
}
}
//中序遍历非递归
void MidOrder(TreeNode *T){
TreeNode *p = T;
stack<TreeNode*> st;
while(p || !st.empty()){
if(p != NULL){
st.push(p);
p = p -> left;
}
else{
p = st.top();
st.pop();
cout << p -> data << endl;
p = p -> right;
}
}
}
//后序遍历非递归
void PostOrder(TreeNode *T){
TreeNode *p = T;
TreeNode *last = NULL;
stack<TreeNode*> st;
while(p || !st.empty()){
while(p){
st.push(p);
p = p -> left;
}
p = st.top();
if(p -> right == NULL || p -> right == last){
st.pop();
cout << p -> data << endl;
last = p;
p = NULL;
}
else{
p = p -> right;
}
}
}
int main(){
TreeNode *T;
cout << "中序遍历创建树,请输入数字,叶子树以#号代替" << endl;
CreateBiTree(T);
cout << "前序遍历:" << endl;
PreOrder(T);
cout << "中序遍历:" << endl;
MidOrder(T);
cout << "后序遍历:" << endl;
PostOrder(T);
return 0;
}