先序遍歷:若二叉樹為空,則空操作;否則訪問根節點;先序遍歷左子樹;先序遍歷右子樹。
中序遍歷:若二叉樹為空,則空操作;否則中序遍歷左子樹;訪問根節點;中序遍歷右子樹。
后序遍歷:若二叉樹為空,則空操作;否則后序遍歷左子樹;后序遍歷右子樹;訪問根節點。
二叉鏈表:鏈表中的結點包含三個域:數據域和左右指針域。
三叉鏈表:在二叉鏈表的基礎上增加指向雙親結點的指針域。
以下代碼均使用二叉鏈表。
//二叉樹的二叉鏈表存儲表示
typedef char TElemType;
typedef struct BiNode
{
TElemType data;
struct BiNode *lchild, *rchild;
} BiNode , *BiTree;
1. 生成二叉樹
可以在遍歷過程中生成結點,建立二叉樹的存儲結構。按先序序列建立二叉樹的二叉鏈表的算法如下:
/*
* 按先序次序輸入二叉樹中結點的值(一個字符),空格字符表示空樹,構造二叉鏈表表示的二叉樹T。
*/
Status CreatBiTree(BiTree *T)
{
char ch;
scanf("%c", &ch);
//如果當前輸入的字符為空格,則(*T)指向空樹。
if (ch == ' ')
{
(*T) = NULL;
}
else
{
if (!((*T) = (BiTree)malloc(sizeof(BiNode))))
exit(OVERFLOW);
(*T)->data = ch; //生成根結點
CreatBiTree(&((*T)->lchild)); //構造左子樹
CreatBiTree(&((*T)->rchild)); //構造右子樹
}
return OK;
}
假設輸入字符依次為ABC##DE#G##F###(#表示空格),則生成的二叉樹如下所示:
2. 二叉樹遍歷遞歸算法
a. 先序遍歷
/*
* 采用二叉鏈表存儲結構,Visit是對數據元素操作的應用函數,
* 先序遍歷二叉樹T的遞歸算法,對每個數據元素調用函數Visit。
*/
Status PreOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
if (T)
{
if (Visit(T->data))
if (PreOrderTraverse_Recursive(T->lchild, Visit))
if (PreOrderTraverse_Recursive(T->rchild, Visit))
return OK;
return ERROR; //函數不會執行到這一步,不會返回Error。這樣寫只是為了沒有編譯警告。
}
else
return OK; //當T為空樹時,停止遞歸。
}
b. 中序遍歷
Status InOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
if (T)
{
if (InOrderTraverse_Recursive(T->lchild, Visit))
if (Visit(T->data))
if (InOrderTraverse_Recursive(T->rchild, Visit))
return OK;
return ERROR;
}
else
return OK;
}
c. 后序遍歷
Status PostOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
if (T)
{
if (PostOrderTraverse_Recursive(T->lchild, Visit))
if (PostOrderTraverse_Recursive(T->rchild, Visit))
if (Visit(T->data))
return OK;
return ERROR;
}
else
return OK;
}
3. 二叉樹遍歷非遞歸算法
a. 先序遍歷
/*
* 先序遍歷二叉樹,非遞歸算法。
*/
Status PreOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S; //棧S中存儲指向樹結點的指針。
BiTree p;
S = (Stack*)malloc(sizeof(Stack));
InitStack(S);
Push(S, T); //根指針進棧。
while (!StackEmpty(S))
{
//獲取棧頂指針,如果棧頂指針不為空,訪問該結點。並將該結點的左子樹進棧。
if (GetTop(S, &p) && p)
{
if (!Visit(p->data))
return ERROR;
Push(S, p->lchild);
}
//棧頂指針為空,表明之前壓入的左子樹或者右子樹為空。
else
{
Pop(S, &p); //空指針退棧
if (!StackEmpty(S))
{
Pop(S, &p); //已被訪問過的根結點退棧。此時,該退棧結點的左子樹已被全部訪問過。
Push(S, p->rchild); //右子樹進棧。
}
}
}
return OK;
}
b. 中序遍歷
/*
* 采用二叉鏈表存儲結構,Visit是對數據元素進行操作的應用函數,
* 中序遍歷二叉樹的非遞歸算法,對每個數據元素調用函數Visit。
*/
Status InOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S;
BiTree p;
S = (Stack *)malloc(sizeof(Stack));
InitStack(S);
Push(S, T); //根指針進棧
while (!StackEmpty(S))
{
//向左走到盡頭
while (GetTop(S, &p) && p)
{
Push(S, p->lchild);
}
//空指針退棧
Pop(S, &p);
//訪問節點,並向右一步
if (!StackEmpty(S))
{
Pop(S, &p);
if (!Visit(p->data))
return ERROR;
Push(S, p->rchild);
}
}
return OK;
}
或者
/*
* 采用二叉鏈表存儲結構,Visit是對數據元素進行操作的應用函數,
* 中序遍歷二叉樹的非遞歸算法,對每個數據元素調用函數Visit。
*/
Status InOrderTraverse_NonRecursive_2(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S;
BiTree p = T;
S = (Stack *)malloc(sizeof(Stack));
InitStack(S);
while (p || !StackEmpty(S))
{
//根指針進棧,遍歷左子樹
if (p)
{
Push(S, p);
p = p->lchild;
}
//根指針退棧,訪問根結點,遍歷右子樹
else
{
Pop(S, &p);
if (!Visit(p->data))
return ERROR;
p = p->rchild;
}
}
return OK;
}
c. 后序遍歷
/*
* 后序遍歷二叉樹,非遞歸算法
*/
Status PostOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S;
BiTree p, pre=NULL;//pre指向已訪問過的最后一個結點。
S = (Stack*)malloc(sizeof(Stack));
InitStack(S);
Push(S, T);//根指針進棧
while (!StackEmpty(S))
{
//獲取棧頂指針,如果當前結點有左子樹,並且左子樹結點不是剛被訪問的節點。如果當前結點有右子樹,並且右子樹結點不是剛被訪問的結點。
//表明棧頂指針指向的樹結點未被訪問,且左子樹和右子樹均未被訪問。此時,將結點的左子樹進棧。
if (GetTop(S, &p) && p->lchild && pre != p->lchild && !(p->rchild && pre == p->rchild))
Push(S, p->lchild);
//如果棧頂指針的右子樹存在,且未被訪問。則將右子樹進棧
else if (p->rchild && pre != p->rchild)
Push(S, p->rchild);
//如果左子樹和右子樹均被訪問過,則結點退棧,並進行訪問。更新pre。
else
{
Pop(S, &p);
if (!Visit(p->data))
return ERROR;
pre = p;
}
}
return OK;
}
4.測試完整代碼
/*
* 假設輸入字符為:ABC##DE#G##F###,實際輸入時,#用空格代替。
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef int Status;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
//二叉樹的二叉鏈表存儲表示
typedef char TElemType;
typedef struct BiNode
{
TElemType data;
struct BiNode *lchild, *rchild;
} BiNode , *BiTree;
//棧的順序存儲結構
#define STACK_INIT_SIZE 100 //存儲空間初始分配量
#define STACKINCREMENT 10 //存儲空間分配增量
typedef struct
{
BiTree *base;
BiTree *top;
int stacksize;
} Stack;
//函數聲明
Status InitStack(Stack *S);
Status Push(Stack *S, BiTree p);
Status Pop(Stack *S, BiTree *p);
Status GetTop(Stack *S, BiTree *p);
Status StackEmpty(Stack *S);
Status CreatBiTree(BiTree *T);
Status PreOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e));
Status InOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e));
Status PostOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e));
Status PreOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e));
Status InOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e));
Status InOrderTraverse_NonRecursive_2(BiTree T, Status(*Visit)(TElemType e));
Status PostOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e));
Status PrintElement(TElemType e);
int main()
{
BiTree T;
CreatBiTree(&T);
//先序
PreOrderTraverse_Recursive(T, PrintElement); putchar('\n');
PreOrderTraverse_NonRecursive(T, PrintElement); putchar('\n');
//中序
InOrderTraverse_Recursive(T, PrintElement); putchar('\n');
InOrderTraverse_NonRecursive(T, PrintElement); putchar('\n');
InOrderTraverse_NonRecursive_2(T, PrintElement); putchar('\n');
//后序
PostOrderTraverse_Recursive(T, PrintElement); putchar('\n');
PostOrderTraverse_NonRecursive(T, PrintElement); putchar('\n');
return 0;
}
/*
* 按先序次序輸入二叉樹中結點的值(一個字符),空格字符表示空樹,構造二叉鏈表表示的二叉樹T。
*/
Status CreatBiTree(BiTree *T)
{
char ch;
scanf("%c", &ch);
//如果當前輸入的字符為空格,則(*T)指向空樹。
if (ch == ' ')
{
(*T) = NULL;
}
else
{
if (!((*T) = (BiTree)malloc(sizeof(BiNode))))
exit(OVERFLOW);
(*T)->data = ch; //生成根結點
CreatBiTree(&((*T)->lchild)); //構造左子樹
CreatBiTree(&((*T)->rchild)); //構造右子樹
}
return OK;
}
/*
* 采用二叉鏈表存儲結構,Visit是對數據元素操作的應用函數,
* 先序遍歷二叉樹T的遞歸算法,對每個數據元素調用函數Visit。
*/
Status PreOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
if (T)
{
if (Visit(T->data))
if (PreOrderTraverse_Recursive(T->lchild, Visit))
if (PreOrderTraverse_Recursive(T->rchild, Visit))
return OK;
return ERROR; //函數不會執行到這一步,不會返回Error。這樣寫只是為了沒有編譯警告。
}
else
return OK; //當T為空樹時,停止遞歸。
}
Status InOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
if (T)
{
if (InOrderTraverse_Recursive(T->lchild, Visit))
if (Visit(T->data))
if (InOrderTraverse_Recursive(T->rchild, Visit))
return OK;
return ERROR;
}
else
return OK;
}
Status PostOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
if (T)
{
if (PostOrderTraverse_Recursive(T->lchild, Visit))
if (PostOrderTraverse_Recursive(T->rchild, Visit))
if (Visit(T->data))
return OK;
return ERROR;
}
else
return OK;
}
/*
* 先序遍歷二叉樹,非遞歸算法。
*/
Status PreOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S; //棧S中存儲指向樹結點的指針。
BiTree p;
S = (Stack*)malloc(sizeof(Stack));
InitStack(S);
Push(S, T); //根指針進棧。
while (!StackEmpty(S))
{
//獲取棧頂指針,如果棧頂指針不為空,訪問該結點。並將該結點的左子樹進棧。
if (GetTop(S, &p) && p)
{
if (!Visit(p->data))
return ERROR;
Push(S, p->lchild);
}
//棧頂指針為空,表明之前壓入的左子樹或者右子樹為空。
else
{
Pop(S, &p); //空指針退棧
if (!StackEmpty(S))
{
Pop(S, &p); //已被訪問過的根結點退棧。此時,該退棧結點的左子樹已被全部訪問過。
Push(S, p->rchild); //右子樹進棧。
}
}
}
return OK;
}
/*
* 采用二叉鏈表存儲結構,Visit是對數據元素進行操作的應用函數,
* 中序遍歷二叉樹的非遞歸算法,對每個數據元素調用函數Visit。
*/
Status InOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S;
BiTree p;
S = (Stack *)malloc(sizeof(Stack));
InitStack(S);
Push(S, T); //根指針進棧
while (!StackEmpty(S))
{
//向左走到盡頭
while (GetTop(S, &p) && p)
{
Push(S, p->lchild);
}
//空指針退棧
Pop(S, &p);
//訪問節點,並向右一步
if (!StackEmpty(S))
{
Pop(S, &p);
if (!Visit(p->data))
return ERROR;
Push(S, p->rchild);
}
}
return OK;
}
/*
* 采用二叉鏈表存儲結構,Visit是對數據元素進行操作的應用函數,
* 中序遍歷二叉樹的非遞歸算法,對每個數據元素調用函數Visit。
*/
Status InOrderTraverse_NonRecursive_2(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S;
BiTree p = T;
S = (Stack *)malloc(sizeof(Stack));
InitStack(S);
while (p || !StackEmpty(S))
{
//根指針進棧,遍歷左子樹
if (p)
{
Push(S, p);
p = p->lchild;
}
//根指針退棧,訪問根結點,遍歷右子樹
else
{
Pop(S, &p);
if (!Visit(p->data))
return ERROR;
p = p->rchild;
}
}
return OK;
}
/*
* 后序遍歷二叉樹,非遞歸算法
*/
Status PostOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e))
{
Stack *S;
BiTree p, pre=NULL;//pre指向已訪問過的最后一個結點。
S = (Stack*)malloc(sizeof(Stack));
InitStack(S);
Push(S, T);//根指針進棧
while (!StackEmpty(S))
{
//獲取棧頂指針,如果當前結點有左子樹,並且左子樹結點不是剛被訪問的節點。如果當前結點有右子樹,並且右子樹結點不是剛被訪問的結點。
//表明棧頂指針指向的樹結點未被訪問,且左子樹和右子樹均未被訪問。此時,將結點的左子樹進棧。
if (GetTop(S, &p) && p->lchild && pre != p->lchild && !(p->rchild && pre == p->rchild))
Push(S, p->lchild);
//如果棧頂指針的右子樹存在,且未被訪問。則將右子樹進棧
else if (p->rchild && pre != p->rchild)
Push(S, p->rchild);
//如果左子樹和右子樹均被訪問過,則結點退棧,並進行訪問。更新pre。
else
{
Pop(S, &p);
if (!Visit(p->data))
return ERROR;
pre = p;
}
}
return OK;
}
//遍歷數據元素時所調用函數
Status PrintElement(TElemType e)
{
putchar(e);
return OK;
}
//初始化棧
Status InitStack(Stack *s)
{
s->base = (BiTree*)malloc(sizeof(BiTree)*STACK_INIT_SIZE);
s->top = s->base;
s->stacksize = STACK_INIT_SIZE;
return OK;
}
//獲得棧頂元素
Status GetTop(Stack *s, BiTree *c)
{
if (StackEmpty(s))
return ERROR;
*c = *(s->top - 1);
return OK;
}
//判斷棧是否為空
Status StackEmpty(Stack *s)
{
if (s->base == s->top)
return OK;
return ERROR;
}
//進棧
Status Push(Stack *s, BiTree c)
{
//如果空間不夠,增加空間的分配
if (s->top - s->base >= s->stacksize)
{
s->base = (BiTree*)realloc(s->base, sizeof(BiTree)*(s->stacksize + STACKINCREMENT));
s->stacksize = s->stacksize + STACKINCREMENT;
}
*(s->top++) = c;
return OK;
}
//出棧
Status Pop(Stack *s, BiTree *c)
{
if (StackEmpty(s))
return ERROR;
*c = *(--s->top);
return OK;
}
5.測試結果
注:程序中生成的樹為上圖中的樹


