先序遍歷:若二叉樹為空,則空操作;否則訪問根節點;先序遍歷左子樹;先序遍歷右子樹。
中序遍歷:若二叉樹為空,則空操作;否則中序遍歷左子樹;訪問根節點;中序遍歷右子樹。
后序遍歷:若二叉樹為空,則空操作;否則后序遍歷左子樹;后序遍歷右子樹;訪問根節點。
二叉鏈表:鏈表中的結點包含三個域:數據域和左右指針域。
三叉鏈表:在二叉鏈表的基礎上增加指向雙親結點的指針域。
以下代碼均使用二叉鏈表。
//二叉樹的二叉鏈表存儲表示 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.測試結果
注:程序中生成的樹為上圖中的樹