二叉树的三种遍历
对如图二叉树我们分别用前序,中序,后续三种遍历
递归表示
前序
首先访问根,再先序遍历左(右)子树,最后先序遍历右(左)子树
代码实现如下
void PreOrderTraversal(BinTree *BT)
{
if(BT)
{
printf("%d",BT->Data);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
根据路径,第一次遇见的节点输出
那么此时根据递归的思想,输出的节点应该是
A B D E H C F I G
中序
首先中序遍历左(右)子树,再访问根,最后中序遍历右(左)子树
void PreOrderTraversal(BinTree *BT)
{
if(BT)
{
PreOrderTraversal(BT->Left);
printf("%d",BT->Data);
PreOrderTraversal(BT->Right);
}
}
根据路径,第二次遇见的节点输出
输出的节点是
D B H E A F I C G
同时你会发现表达方式也就是printf 的位置换了下
后序
首先后序遍历左(右)子树,再后序遍历右(左)子树,最后访问根
根据前序和中序,后序是不是很容易出来了
void PreOrderTraversal(BinTree *BT)
{
if(BT)
{
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
printf("%d",BT->Data);
}
}
根据路径,第三次遇见的节点输出
输出为
D H E B I F G C A
分析
前序,中序,后序遍历,所经过节点的路线是一模一样的,只是访问的时机不同
所以根据图来分析
从入口到出口,分别用 蓝色正方形 、 绿色椭圆形 、 红色圆角矩形 来表示先序、中序、后序访问各节点的时刻
PS:我所用用的遍历均是先向走,在向右的
遍历的非递归表示(栈)
前序的非递归实现
前序遍历的顺序是根-左-右
void PreOrderTraversal(BinTree *BT)
{
if (!BT)
return;
BinTree *P = BT;
stack<BinTree*>st;
while (P != NULL || !st.empty())
{
while (P)
{
st.push(P);
cout << P->Value << endl;
P = P->Left;
}
if (!st.empty())
{
P = st.top();
st.pop();
P = P->Right;
}
}
}
中序的非递归实现
中序的顺序是左-根-右
思路:
- 遇到一个节点先压入栈,并遍历他的左子树
- 当左子树遍历后,从栈顶弹出这个节点并访问
- 然后按其右指针,再去中序遍历该节点的右子树
void PreOrderTraversal(BinTree *BT)
{
if (!BT)
return;
BinTree *P = BT;
stack<BinTree*>st;
while (P != NULL || !st.empty())
{
while (P)//一直向左并将沿途节点压入栈
{
st.push(P);
P = P->Left;
}
if (!st.empty())
{
P = st.top();
cout << P->Value << endl;
st.pop();
P = P->Right;//向右访问右子树
}
}
}
后序遍历的非递归实现
后序的顺序是左-右-根
我认为后序遍历非递归的思路是三个中最难的,
因为后序非递归遍历二叉树的顺序是先访问左子树,再访问右子树,最后访问根节点。当用堆栈来存储节点,必须分清返回根节点时,是从左子树返回的,还从右子树返回的。所以,使用辅助指针Flag,其指向最近访问过的节点。也可以在节点中增加一个标志域,记录是否已被访问
void PreOrderTraversal(BinTree *BT)
{
if (!BT)
return;
BinTree *P = BT,*Flag = NULL;
stack<BinTree*>st;
while (P != NULL || !st.empty())
{
if(P)//走到最左边
{
st.push(P);
P = P->Left;
}
else
{
P = st.top();
if(P->Right != NULL && P->Right != Flag)//右子树存在,并且未被访问
{
P = P->Right;
}
else
{
st.pop();
cout << P->value << endl;
Flag = P;
P = NULL;
}
}
}
}
因初学数据结构,若有错误,欢迎指出