基本概念
二叉树的遍历:指按某条搜索路径访问树中每个结点,使得每个结点均被访问一次, 而且仅被访问一次。
后序遍历:按照 左-右-根 的次序遍历。
图例
后序遍历序列: 8 9 4 10 5 2 6 7 3 1
代码
结构体定义和构建二叉树的方法与先序遍历的一样(注意:这里构建后序遍历的二叉树仍按照先序的方法去构造二叉树)传送门:二叉树的先序遍历-Doris-510
递归遍历
void postorder(BiTree T){
if(T){//这里不加非空判断,不然遇到叶子结点后就不能递归下去了
postorder(T->lchild);//遍历左子树
postorder(T->rchild);//遍历右子树
cout<<T->val<<" ";//遍历根结点
}
}
非递归遍历(重要)
//非递归法遍历
void postorder1(BiTree T){
if(!T) return;
stack<BiTNode *> st;//初始化栈
BiTNode *p=T;//用一个p指针来遍历
BiTNode *pre=NULL;//用一个前驱指针来指示上一次访问的结点
while(p||!st.empty()){//循环条件:当前结点不为空或者栈不为空(重要!!!)
if(p){//若当前结点不为空
st.push(p);//当前结点进栈
p=p->lchild ;//访问左子树结点
}
else{//当前结点为空
p=st.top();//取出栈顶元素
if(!p->rchild || pre==p->rchild ){
st.pop();//弹出栈顶元素
cout<<p->val <<" ";//访问当前结点
pre=p;//记录当前访问结点
p=NULL; //将p置空,继续往上走,即取出栈顶元素
}
else{
p=p->rchild ;//访问右子树节点
}
}
}
}
全部代码
#include<bits/stdc++.h>
using namespace std;
typedef struct BiTNode{
int val;//根结点的值
struct BiTNode *lchild,*rchild;//左孩子指针 右孩子指针
}BiTNode,*BiTree;
//二叉树构造函数
BiTree createTree(){
int val;
cin>>val;
if(val==-1) return NULL;//为叶子结点添加'-1'以唯一确定一棵二叉树
BiTNode *T=(BiTNode *)malloc(sizeof(BiTNode));
T->val =val;
T->lchild =createTree();
T->rchild =createTree();
}
//递归法遍历
void postorder(BiTree T){
if(T){//这里不加非空判断,不然遇到叶子结点后就不能递归下去了
postorder(T->lchild);//遍历左子树
postorder(T->rchild);//遍历右子树
cout<<T->val<<" ";//遍历根结点
}
}
//非递归法遍历
void postorder1(BiTree T){
if(!T) return;
stack<BiTNode *> st;//初始化栈
BiTNode *p=T;//用一个p指针来遍历
BiTNode *pre=NULL;//用一个前驱指针来指示上一次访问的结点
while(p||!st.empty()){//循环条件:当前结点不为空或者栈不为空(重要!!!)
if(p){//若当前结点不为空
st.push(p);//当前结点进栈
p=p->lchild ;//访问左子树结点
}
else{//当前结点为空
p=st.top();//取出栈顶元素
if(!p->rchild || pre==p->rchild ){//如果右子树为空或右孩子刚刚遍历过
st.pop();//弹出栈顶元素
cout<<p->val <<" ";//访问当前结点
pre=p;//记录当前访问结点
p=NULL; //将p置空,继续往上走,即取出栈顶元素
}
else{
p=p->rchild ;//访问右子树节点
}
}
}
}
int main(){
BiTree T=createTree();
cout<<"递归遍历结果:"<<endl;
postorder(T);
cout<<endl;
cout<<"非递归遍历结果:"<<endl;
postorder1(T);
return 0;
}
//二叉树后序遍历:1 2 4 8 -1 -1 9 -1 -1 5 10 -1 -1 -1 3 6 -1 -1 7 -1 -1
//递归遍历:8 9 4 10 5 2 6 7 3 1
//非递归遍历:8 9 4 10 5 2 6 7 3 1
注意
- 非递归遍历代码中需注意要在右子树为空或者已经访问完右子树的情况下才能访问当前结点,否则就先访问右子树。
- 当访问完当前结点后,首先,需要记录当前访问的结点,以便确保右孩子被访问过。然后,需要继续往上走,继续取出栈顶元素,即将指向当前结点的指针置空。