二叉樹的特點是每個結點至多隻有兩棵子樹,它是一種很重要的資料結構,從樹的特點我們可以利用遞迴很容易的實現它的建立以及遍曆操作,上一篇已經用遞迴的方法實現了二叉樹的先序、中序和後序的遍曆,下面的代碼是二叉樹的非遞迴遍曆的實現,三種遍曆方式都給出了兩種實現方法(注釋掉的即為第二種實現方法),注釋部分已經講原理寫出來了,由於自己語言群組織能力不是很好,原理就是從網上找來的,我自己是通過這些原理來實現的遍曆二叉樹,希望也能給看到代碼的人同樣協助。
/**@2012-12-14*二叉樹的非遞迴(先序、中序、後序)遍曆*/#include<iostream>using namespace std;typedef char TElemType;//二叉樹資料元素的類型typedef struct BitreeNode{TElemType TItem;struct BitreeNode *lchild;struct BitreeNode *rchild;}BitreeNode,*Bitree;typedef structSNode{ Bitree SItem;struct SNode *next;}SNode , * LinkStack;//初始化二叉樹int InitBitree(Bitree &T){T=(Bitree)malloc(sizeof(BitreeNode));if(!T)return 0;T->TItem='#';T->lchild=NULL;T->rchild=NULL;return 1;}//初始化棧int InitStack(LinkStack &S){S=(LinkStack)malloc(sizeof(SNode)); //通過malloc函數分配空間if (!S)return 0; //如果分配失敗,則返回0S->next=NULL;return 1;}//判斷棧是否為空白int StackEmpty(LinkStack S){if (S!=NULL) //判斷棧是否存在{if (S->next==NULL){return 1;}}return 0;}//建立二叉樹int CreateBitree(Bitree &T){TElemType ch;ch=getchar();//測試字串abc##de#g##f###if(ch=='#')T=NULL;else{T=(Bitree)malloc(sizeof(BitreeNode));if(!T)return 0;else{T->TItem=ch;CreateBitree(T->lchild);CreateBitree(T->rchild);}}return 1;}//擷取棧頂元素int GetTop(LinkStack S,Bitree &e){LinkStack q=S;if (S!=NULL) //判斷棧是否存在{if (q->next!=NULL)//判斷棧是否為空白{while (q->next!=NULL){q=q->next;}e=q->SItem;return 1;}}return 0; //如果不能得到資料元素,則返回0(false)}//壓棧函數int Push(LinkStack &S,Bitree e){LinkStack q=S;LinkStack m=(LinkStack)malloc(sizeof(SNode)); //通過malloc函數分配空間if (S!=NULL){while (q->next!=NULL){q=q->next;}m->SItem=e;m->next=NULL;q->next=m;}return 0;}//出棧函數int Pop(LinkStack &S,Bitree &e){LinkStack q=S;if (S!=NULL){if (q->next!=NULL) //若棧不是空的{while (q->next->next!=NULL){q=q->next;}e=q->next->SItem;q->next=NULL;return 1;}}return 0;}//遍曆訪問函數int Visit(TElemType e){if(e!=NULL){cout<<e<<" ";return 1;}elsereturn 0;}/*先序遍曆二叉樹根->左->右;1)訪問結點P,並將結點P入棧;2)判斷結點P的左孩子是否為空白,若為空白,則取棧頂結點並進行出棧操作,並將棧頂結點的右孩子置為當前的結點P,迴圈至1); 若不為空白,則將P的左孩子置為當前的結點P;3)直到P為NULL並且棧為空白,則遍曆結束。*/int PreOrederTraverse(Bitree &T,int(*Visit)(TElemType)){/*LinkStack S;Bitree p=T;InitStack(S);Push(S,T);while (p || !StackEmpty(S)){while (p!=NULL){Visit(p->TItem);Push(S,p);p=p->lchild;}if(!StackEmpty(S)){GetTop(S,p);Pop(S,p);p=p->rchild;}}*/LinkStack S;Bitree p=T;InitStack(S);Push(S,T);while (!StackEmpty(S)){while (GetTop(S,p) && p){if(!Visit(p->TItem))return 0;Push(S,p->lchild);//向左走到盡頭}Pop(S,p);//null 指標退棧if(!StackEmpty(S)){//訪問節點,向右一步Pop(S,p);Push(S,p->rchild);}}return 0;}/**中遍曆二叉樹:左->根->右1)若其左孩子不為空白,則將P入棧並將P的左孩子置為當前的P,然後對當前結點P再進行相同的處理;2)若其左孩子為空白,則取棧頂元素並進行出棧操作,訪問該棧頂結點,然後將當前的P置為棧頂結點的右孩子;3)直到P為NULL並且棧為空白則遍曆結束*/int InOrderTraverse(Bitree &T,int(*Visit)(TElemType)){/*LinkStack S;Bitree p=T;InitStack(S);Push(S,T);//根指標進棧while (p || !StackEmpty(S)){if(p){Push(S,p);p=p->lchild;//根指標進棧,遍曆左子樹}else//根指標退棧,訪問根結點,遍曆右子樹{Pop(S,p);if(!Visit(p->TItem))return 0;p=p->rchild;}}*/LinkStack S;Bitree p=T;InitStack(S);Push(S,T);//根指標進棧while (!StackEmpty(S)){while (GetTop(S,p) && p){Push(S,p->lchild);//向左走到盡頭}Pop(S,p);//null 指標退棧if(!StackEmpty(S)){//訪問節點,向右一步Pop(S,p);if(!Visit(p->TItem))return 0;Push(S,p->rchild);}}return 1;}/**後序遍曆二叉樹:左->右->根1)對於任一結點P,先將其入棧。2)如果P不存在左孩子和右孩子,或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,則可以直接存取該結點。3)若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問。 左孩子和右孩子都在根結點前面被訪問。*/int PostOrderTraverse(Bitree &T,int(*Visit)(TElemType)){/*Bitree q=T;LinkStack S;InitStack(S);while (T || !StackEmpty(S)){if (T){Push(S, T);T=T->lchild;}else{GetTop(S, T);if (T->rchild==NULL || T->rchild==q){Visit(T->TItem);Pop(S, T);q=T;T=NULL;}else{T=T->rchild;}} }*/LinkStack S;Bitree cur;//當前結點Bitree pre=NULL;//前一次訪問的結點InitStack(S);Push(S,T);//根指標進棧 while(!StackEmpty(S)) { GetTop(S,cur); if((cur->lchild==NULL&&cur->rchild==NULL)||(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild))) {//如果當前結點沒有孩子結點或者孩子節點都已被訪問過 Visit(cur->TItem); Pop(S,cur); pre=cur; } else//將P的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問 { if(cur->rchild!=NULL) Push(S,cur->rchild); if(cur->lchild!=NULL) Push(S,cur->lchild); } } return 0;}int main(){Bitree T;InitBitree(T);CreateBitree(T);cout<<"先序遍曆:";PreOrederTraverse(T,Visit);cout<<endl;cout<<"中序遍曆:";InOrderTraverse(T,Visit);cout<<endl;cout<<"後序遍曆:";PostOrderTraverse(T,Visit);cout<<endl;return 0;}