二叉樹3種遍歷演算法遞迴與非遞迴實現詳解
阿新 • • 發佈:2019-01-23
一, 二叉樹先序遍歷的實現
- 遞迴實現
void PreOrderTraverse(BiTree T)
{
if( T )
{
VisitF(T->data);//訪問根節點
PreOrderTraverse(T->lchild);//遞迴左子樹
PreOrderTraverse(T->rchild);//遞迴右子樹
}
}
2. 非遞迴實現
思路:
- 判斷棧是否為空或子樹為空
- 若不為空,就訪問左孩子並將其入棧,直至左孩子為空
- 若左孩子為空,就出棧,然後訪問右孩子,入棧,就這樣不斷的迴圈。
void PreOrderTraverse_Nonrecursion(BiTree T) { LiStack S ; BiTree p ; S = NULL ; p = T ; InitStack(S) ; if(NULL == p) { printf("樹為空!\n") ; return ; } while(p || !StackEmpty(S)) { if(p) { Push(S, p) ; VisitF(p->data); p = p->lchild ; } else { Pop(S, p) ; p = p->rchild ; } } free(S) ; }
二, 二叉樹中序遍歷的實現
- 遞迴實現
/*
中序遍歷二叉樹
*/
void InOrderTraverse(BiTree T)
{
if( T )
{
InOrderTraverse(T->lchild);
VisitF(T->data);
InOrderTraverse(T->rchild);
}
}
2. 非遞迴實現
思路:思路基本和先序差不多,只是輸出資料的時候不一樣
-
判斷棧和樹是否為空,
-
若不,則判斷樹是否為空,
-
不為繼續將左子樹進棧,若為空,則出棧,輸出資料,然後訪問右子樹。
void InOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree p ;
S = NULL ;
p = T ;
InitStack(S) ;
if(NULL == p)
{
printf("樹為空!\n") ;
return ;
}
while(p || !StackEmpty(S))
{
if(p)
{
Push(S, p) ;
p = p->lchild ;
}
else
{
Pop(S, p) ;
VisitF(p->data);
p = p->rchild ;
}
}
free(S) ;
}
三, 二叉樹中序遍歷的實現
- 遞迴實現
/*
後續遍歷二叉樹
*/
void PostOrderTraverse(BiTree T)
{
if( T )
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
VisitF(T->data);
}
}
2. 非遞迴實現
思路 :實現有多多種方法,有兩個棧,或加標誌位實現,但是我覺得如下實現最容易懂
要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點P,先將其入棧。如果P不存在左孩子和右孩子,則可以直接訪問它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,則同樣可以直接訪問該結點。若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。
void PostOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree cur, pre ;
S = NULL ;
InitStack(S) ;
if(NULL == T)
{
printf("樹為空!\n") ;
return ;
}
pre = NULL ;
cur = NULL ;
Push(S,T) ;
while(!StackEmpty(S))
{
cur = NULL ;
GetTop(S,cur) ;
if((cur->lchild == NULL && cur->rchild == NULL) || (pre != NULL && (pre == cur->lchild ||pre == cur->rchild)))
{
VisitF(cur->data);
pre = cur ;
Pop(S,cur) ;
}
else
{
if(cur->rchild != NULL)
{
Push(S,cur->rchild) ;
}
if(cur->lchild != NULL)
{
Push(S,cur->lchild) ;
}
}
}
free(S) ;
}
如下是完整程式碼:
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR -1
typedef char TElemType;
typedef int Status;
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode,*BiTree;
typedef BiTNode * StackElemType;
typedef struct LinkNode //棧的節點
{
StackElemType data ;
LinkNode * next ;
} LinkNode,*LiStack;
typedef BiTNode * QueueElemType ; //定義佇列包含的資料型別
typedef struct QNode //定義佇列節點
{
QueueElemType data ;
struct QNode * next ;
} QNode,*QueuePtr;
typedef struct
{
QueuePtr fronts;
QueuePtr rears;
} LinkQueue;
Status creatBiTree(BiTree &T);
void Visit(char ch,int level);
void PreOrderTraverse(BiTree T,int level);
void InOrderTraverse(BiTree T,int level);
void PostOrderTraverse(BiTree T,int level);
Status InitStack(LiStack &S);
void Push(LiStack &S, StackElemType data);
void Pop(LiStack & S, StackElemType &data);
int StackEmpty(LiStack &S);
int GetTop(LiStack &S, StackElemType & data);
Status InitQueue(LinkQueue &Q);
Status EnQueue(LinkQueue &Q, QueueElemType data);
Status DeQueue(LinkQueue &Q, QueueElemType & data);
int QueueEmpty(LinkQueue Q);
void PreOrderTraverse_Nonrecursion(BiTree T);
void InOrderTraverse_Nonrecursion(BiTree T);
void PostOrderTraverse_Nonrecursion(BiTree T);
/*********************************************************************/
/*****************************棧的方法********************************/
//棧的函式定義
Status InitStack(LiStack &S)
{
S = (LinkNode *)malloc(sizeof(LinkNode)) ;
if(NULL == S)
{
printf("記憶體不足,不能分配棧!\n") ;
exit(0) ;
}
S->next = NULL ;
}
void Push(LiStack &S, StackElemType data)
{
LiStack q ;
q = (LinkNode *)malloc(sizeof(LinkNode)) ;
if(NULL == q)
{
printf("記憶體不足,不能分配棧!\n") ;
exit(0) ;
}
/*
插入順序相當於頭插法.
*/
q->data = data ;
q->next = S->next ;
S->next = q ;
}
void Pop(LiStack & S, StackElemType &data)
{
LiStack q;
if(NULL == S->next)
{
printf("棧為空,無返回值!\n") ;
}
q = S->next ;
data = q->data ;
S->next = q->next ;
free(q) ;
}
int StackEmpty(LiStack &S)
{
if(NULL == S->next)
{
return(1) ;
}
return(0) ;
}
int GetTop(LiStack &S, StackElemType & data)
{
if(NULL != S->next)
{
data = S->next->data ;
return(1) ;
}
else
{
//data = NULL ;
return(0) ;
}
}
/*********************************************************************/
/*****************************佇列的方法******************************/
//佇列函式的定義
Status InitQueue(LinkQueue &Q)
{
Q.fronts = Q.rears = (QNode *)malloc(sizeof(QNode)) ;
if(NULL == Q.fronts)
{
printf("記憶體不足!\n") ;
return ERROR;
}
Q.fronts->next = NULL;
}
Status EnQueue(LinkQueue &Q, QueueElemType data)
{
QueuePtr q ;
q = (QNode*)malloc(sizeof(QNode));
if(NULL == q)
{
printf("記憶體不足!\n") ;
return ERROR;
}
//構造q
q->data = data ;
q->next = NULL;
q->next = Q.rears->next ;
Q.rears = q ;
return OK;
}
Status DeQueue(LinkQueue &Q, QueueElemType & data)
{
QueuePtr p ;
if(Q.fronts == Q.rears)
{
printf("佇列為空!\n") ;
return ERROR ;
}
p = Q.fronts->next ;
data = p->data ;
Q.fronts->next = p->next ;
if(Q.rears == p)
Q.rears = Q.fronts ;
free(p);
return OK;
}
int QueueEmpty(LinkQueue Q)
{
if(Q.fronts == Q.rears)
return(1) ;
else
return(0) ;
}
/*********************************************************************/
/*
先序建立二叉樹
*/
Status creatBiTree(BiTree &T)
{
char ch;
scanf("%c",&ch);
if('@' == ch)
{
T = NULL;
}
else
{
//申請失敗
if(!(T = (BiTNode*)malloc(sizeof(BiTNode))))
return ERROR;
T->data = ch;
creatBiTree(T->lchild);
creatBiTree(T->rchild);
}
return OK;
}
void VisitF(char ch)
{
printf("%c ",ch);
}
void Visit(char ch,int level)
{
printf("%c 位於第 %d 層 \n",ch,level);
}
/*
先序遍歷二叉樹
*/
void PreOrderTraverse(BiTree T,int level)
{
if( T )
{
VisitF(T->data);
PreOrderTraverse(T->lchild,++level);
PreOrderTraverse(T->rchild,++level);
}
}
void PreOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree p ;
S = NULL ;
p = T ;
InitStack(S) ;
if(NULL == p)
{
printf("樹為空!\n") ;
return ;
}
while(p || !StackEmpty(S))
{
if(p)
{
Push(S, p) ;
VisitF(p->data);
p = p->lchild ;
}
else
{
Pop(S, p) ;
p = p->rchild ;
}
}
free(S) ;
}
/*
中序遍歷二叉樹
*/
void InOrderTraverse(BiTree T)
{
if( T )
{
InOrderTraverse(T->lchild);
VisitF(T->data);
InOrderTraverse(T->rchild);
}
}
void InOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree p ;
S = NULL ;
p = T ;
InitStack(S) ;
if(NULL == p)
{
printf("樹為空!\n") ;
return ;
}
while(p || !StackEmpty(S))
{
if(p)
{
Push(S, p) ;
p = p->lchild ;
}
else
{
Pop(S, p) ;
VisitF(p->data);
p = p->rchild ;
}
}
free(S) ;
}
/*
後續遍歷二叉樹
*/
void PostOrderTraverse(BiTree T)
{
if( T )
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
VisitF(T->data);
}
}
void PostOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree cur, pre ;
S = NULL ;
InitStack(S) ;
if(NULL == T)
{
printf("樹為空!\n") ;
return ;
}
pre = NULL ;
cur = NULL ;
Push(S,T) ;
while(!StackEmpty(S))
{
cur = NULL ;
GetTop(S,cur) ;
if((cur->lchild == NULL && cur->rchild == NULL) || (pre != NULL && (pre == cur->lchild ||pre == cur->rchild)))
{
VisitF(cur->data);
pre = cur ;
Pop(S,cur) ;
}
else
{
if(cur->rchild != NULL)
{
Push(S,cur->rchild) ;
}
if(cur->lchild != NULL)
{
Push(S,cur->lchild) ;
}
}
}
free(S) ;
}
int main()
{
int level = 1;
BiTree T = NULL;
creatBiTree(T);
printf("先序遍歷二叉樹,每個結點在第幾行\n");
PreOrderTraverse(T,level);
printf("\n\n");
printf("先序遍歷二叉樹,非遞迴演算法\n");
PreOrderTraverse_Nonrecursion(T);
printf("\n\n\n");
/***************************************************/
printf("中序遍歷二叉樹\n");
InOrderTraverse(T);
printf("\n\n");
printf("中序遍歷二叉樹,非遞迴演算法\n");
InOrderTraverse_Nonrecursion(T);
printf("\n\n\n");
/***************************************************/
printf("後序遍歷二叉樹\n");
PostOrderTraverse(T);
printf("\n\n");
printf("後序遍歷二叉樹,非遞迴演算法\n");
PostOrderTraverse_Nonrecursion(T);
printf("\n\n\n");
return 0;
}