用棧實現二叉樹的遍歷(非遞迴)
先實現棧
#include <stdio.h>
#include <stdlib.h>#include <string.h>
typedef char ElemType;
#define STACKSIZE 20
typedef struct st
{
ElemType *data;
int top;
int MaxSize;
}stack;
void Init_stack(stack *p);//初始化棧
bool Is_Empty(stack *p);//判斷是否為空棧
bool Is_Full(stack *p);//判斷棧是否為滿棧
int GetLength(stack *p);//獲取棧內元素個數
bool push(stack *p, ElemType value);//入棧
ElemType top(stack *p);//彈出棧頂元素
ElemType pop(stack *p);//出棧
void show_stack(stack *p);//展示棧內元素
void Init_stack(stack *p)
{
if (p == NULL)
return;
p->top = -1;
p->MaxSize = STACKSIZE;
p->data = (ElemType *)malloc(sizeof(ElemType)*p->MaxSize);
memset(p->data, 0, sizeof(ElemType)*p->MaxSize);
}
bool Is_Empty(stack *p)
{
if (p->top = -1 || p == NULL)
{
return true;
}
return false;
}
bool Is_Full(stack *p)
{
if (p->top + 1 == p->MaxSize || p == NULL)
{
return true;
}
return false;
}
int GetLength(stack *p)
{
return p->top+1;
}
bool push(stack *p, ElemType value)
{
bool res = false;
if (!Is_Full(p))
{
p->data[++p->top] = value;
res = true;
}
return res;
}
//出棧操作分為兩步,是為了保證出棧精確
ElemType top(stack *p)
{
if ( p != NULL )
{
return p->data[p->top];}
}
ElemType pop(stack *p)
{
if (p->top >= 0 && p != NULL)
{
p->top--;
}
}
void show_stack(stack *p)
{
int count = p->top;
while (count != -1)
{
printf("%c ", p->data[count]);
count--;
}
}
假設二叉樹的結構為:
則其前序遍歷為:ABCDEFGH. 中序遍歷為:CBEDFAGH . 後序遍歷為:CEFDBHGA
用棧實現中序遍歷的思想:讓二叉樹左-中-右遍歷,若不為空則入棧,若為空出棧
過程如下所示:
將其轉化為程式碼,如下:
void NiceInOrder ( BtNode *ptr )
{
if ( NULL == ptr ) return ;
stack st;
Init_Stack ( &st ) ;
while ( ptr !=NULL || ! Is_empty ( &st ) )
{
while ( ptr !=NULL )
{
push ( & st , ptr -> data ) ;
ptr = ptr -> LiftChild ;
}
ptr = top ( &st ) ; pop( &st ) ; // 遇到空直接出棧
printf ( " %c ", ptr -> data ) ;
ptr = ptr -> RightChild ;
}
}
後序遍歷思想為:每個節點都要進棧兩次,第二次退棧是才訪問節點。第一次進棧時,在遍歷左子樹的過程中將根節點進棧,待左子樹訪問完後,回溯的節點退棧,即退出這個根節點,但不能立即訪問,只能藉助於這個根去找該根的右子樹,並遍歷這棵右子樹,直到該右子樹全部遍歷以後,再退出該根節點,並訪問它。所以,為了記錄節點是第一次還是第二次進棧,需單獨定義一個節點作為標誌。
程式碼如下:
void NicePastOrder ( BtNode *ptr )
{
if ( NULL == ptr ) return ;
stack st;
Init_Stack ( &st ) ;
BtNode *tag=NULL;
while ( ptr !=NULL || ! Is_empty ( &st ) )
{
while ( ptr !=NULL )
{
push ( & st , ptr -> data ) ;
ptr = ptr -> LiftChild ;
}
ptr = top ( &st ) ; pop( &st ) ; // 遇到空直接出棧
if ( ptr -> RightChild == NULL || ptr -> RightChild == tag )
{
printf ( "%c", ptr -> data ) ;
tag = ptr ;
ptr = NULL ;
}
else
{
push ( &st, ptr ) ;
ptr = ptr -> RightChild ;
}
}
}
前序遍歷的思想:若棧不為空且ptr不為空時入棧即出棧並列印,然後將其右孩子入棧,再繼續訪問其左孩子;若ptr為空,則出棧。
程式碼如下:
void NicePerOrder ( BtNode *ptr )
{
if ( ptr == NULL ) return ;
stack st ;
Init_Stack ( &st ) ;
while ( ptr !=NULL || ! Is_Empty ( &st ) )
{
if ( ptr )
{
push ( &st , ptr ) ;
ptr = top ( &st ) ; pop ( &st ) ;
printf ( "%c " , ptr -> data ) ;
push ( &st , ptr -> RightChild ) ;
ptr = ptr -> LeftChild ;
}else
{
ptr = top ( &st ) ; pop ( &st ) ;
}
}
}