1. 程式人生 > >用棧實現二叉樹的遍歷(非遞迴)

用棧實現二叉樹的遍歷(非遞迴)

先實現棧

#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 ) ;

}

}

}