二叉树的递归遍历
(1)先序遍历(父、左、右)
void PreOrderTraversal(BinTree BT){
if(BT){
printf("%d",BT->Data);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
(2)中序遍历(左、父、右)
void PreOrderTraversal(BinTree BT){
if(BT){
PreOrderTraversal(BT->Left);
printf("%d",BT->Data);
PreOrderTraversal(BT->Right);
}
}
(3)后序遍历(左、右、父)
void PreOrderTraversal(BinTree BT){
if(BT){
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
printf("%d",BT->Data);
}
}
总结:上述三种遍历方法的遍历路径是一样的,只是打印的时机不一样。先序是第一次遇到结点时打印,中序是在第二次遇到结点时打印,后序是第三次遇到结点时打印。
二叉树的非递归遍历(堆栈)
(1)中序遍历算法
遇到一个结点,把它压栈,并遍历其左子树;
当左子树遍历完,弹出栈顶元素,并访问这个元素;
然后按其右指针再按如上程序操作。
void InOrderTraversal(BinTree BT){
BinTree T=BT;
Stack S=CreatStack(MaxSize);
while(T || !IsEmpty){
while(T){
Push(S,T);
T=T->Left;
}
if(!IsEmpty(S)){
T=Pop(S);
printf("%5d",T->Data);
T=T->Right;
}
}
}
(2)先序遍历算法
遇到一个结点,访问这个元素,并把它压栈,遍历其左子树;
当左子树遍历完,弹出栈顶元素;
然后按其右指针再按如上程序操作。
void InOrderTraversal(BinTree BT){
BinTree T=BT;
Stack S=CreatStack(MaxSize);
while(T || !IsEmpty){
while(T){
Push(S,T);
printf("%5d",T->Data);
T=T->Left;
}
if(!IsEmpty(S)){
T=Pop(S);
T=T->Right;
}
}
}
(3)后序遍历
与中序和先序不一样,算法需要修改。前两者都是pop左子树再pop父结点再pop右子树。下面的算法中,pop出左子树后,会pop父结点,但是要判断两种情况:这个根是否有右子树、它的右子树是否刚pop出来。满足这两种情况则打印这个父结点,不满足则放回堆栈,指针指向它的右子树继续遍历。
void PostOrderTraversal(BinTree BT) {
BinTree T = BT, PrePop = NULL; //PrePop记录上一个Pop出来的结点
Stack S = CreatStack(MaxSize);
while (T || !IsEmpty(S)) {
while (T) { //一直向左将结点压入堆栈
Push(S, T);
T = T->Left;
}
//将Pop的过程改为循环
while (!IsEmpty(S)) { //后序遍历有两种情况可以Pop该结点
T = Pop(S);
if (T->Right == PrePop || T->Right == NULL) { //该结点的右结点为空或者上一次Pop的是该结点的右结点
printf("%05d", T->Data);
PrePop = T;
}
else { //若不满足以上两种情况 说明该节点右侧节点还未被Pop
Push(S, T); //则将该结点重新压回堆栈
T = T->Right; //然后指向该结点的右节点
break; //退出Pop循环
}
}
}
}
层序遍历
用队列实现:根节点入队,从队列中取出一个元素,访问该元素的左右儿子,若左右儿子非空,则顺序入队。
void LevelOrderTraversal(BinTree BT){
Queue Q;
BinTree T;
if(!BT){
return;
}
Q=CreateQueue(MaxSize);
Add(Q,BT);
while(!IsEmptyQ(Q)){
T=DeleteQ(Q);
printf("%d\n",T->Data);
if(T->Left){
AddQ(Q,T->Left);
}
if(T-Right){
AddQ(Q,T->Right);
}
}
}
遍历二叉树的应用
eg1:输出二叉树中的叶子结点。(利用先序递归遍历)
void PreOrderTraversal(BinTree BT){
if(BT){
if(!BT->Left && !BT->Right){
printf("%d",BT->Data);
}
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
eg2:求二叉树的高度(改编后序递归遍历)
int PostOrderGetHeight(BinTree BT){
int HL,HR,MaxH;
if(BT){
HL=PostOrderGetHeight(BT->Left);
HR=PostOrderGetHeight(BT->Right);
MaxH=(HL>HR)?HL:HR;
return(MaxH+1);
}
else return 0;
}
eg3:二元运算表达式树及其遍历
为了防止优先级混乱,遍历完一个左子树、父结点、右子树后要加括号。
eg4:由两种遍历序列确定二叉树(必须包含中序遍历)如:
根据先序序列,a是根节点,则中序序列中,a前面的是左子树包含的元素,a后面是右子树包含的元素。
在先序序列,b是左子树的根节点,则中序序列中,c是左子树,ed是右子树。按照这种方法一直分析下去可知结构。