后序線索二叉樹中,結點的后繼:
如果結點的雙親有右孩子,則結點的后繼為雙親的右子樹中第一個被訪問的結點
如果結點的雙親沒有右孩子,則結點的后繼為雙親
如果結點為雙親的右孩子,則結點的后繼為雙親
因為找到后序遍歷中,找到結點的后繼需要知道節點的雙親,所以可以用三叉鏈表(trifurcate linked list)來存儲結點
1.后序線索化二叉樹(用三叉鏈表存儲結構、有頭結點)
void postThreading(TriTree p){ if(p){ postThreading(p->lChild); postThreading(p->rChild); if(!p->lChild){ p->lTag=1; p->lChild=pre; } if(!pre->rChild){ pre->rTag=1; pre->rChild=p; } pre=p; } } bool postThreadTree(TriTree T,TriTree &head){ if(!(head=new TriTNode)) return false; head->lTag=0; head->rTag=1; head->parent=NULL; if(!T){head->lChild=head;head->rChild=head;} else{ pre=head; head->lChild=T; head->rChild=T; T->parent=head; postThreading(T); if(!pre->rChild){ pre->rTag=1; pre->rChild=head; } } return true; }
2.遍歷后序線索二叉樹
void postTraverseTriTree(TriTree head){ TriTree p=head->lChild; int tag=0; while(p->parent!=NULL){ while(p->lTag==0&&tag==0){p=p->lChild;} if(p->rTag==1){//結點無右孩子,可以順着線索訪問后繼 visit(p->data); while(p->rTag==1&&p->rChild->parent!=NULL){ p=p->rChild; visit(p->data); } }else if(tag==0){//結點有右孩子且右孩子還沒被訪問過 p=p->rChild; continue; }else{//結點有右孩子且右孩子已經被訪問過 visit(p->data); } //p已經訪問掉了,繼續找p的后繼 if(p==p->parent->rChild){p=p->parent;tag=1;} else if(p->parent->rTag==0){p=p->parent->rChild;tag=0;} else{p=p->parent;tag=1;} } }
3.刪除后序線索二叉樹的內存空間 在刪除掉雙親的一個孩子時,將雙親對應的孩子指針置為NULL
void deleteTriTree(TriTree &head){ TriTree p=head,q=NULL; while(p->parent!=NULL){ while(p->lChild&&p->lTag==0){ p=p->lChild; } q=p; while(p->rTag==1&&p->rChild->parent!=NULL){ p=p->rChild; if(q->parent->lChild==q) q->parent->lChild=NULL; else q->parent->rChild=NULL; delete q; q=p; } if(p==p->parent->rChild){ q=p; p=p->parent; delete q; p->rChild=NULL; }else if(p->parent->rChild){ q=p; p=p->parent->rChild; q->parent->lChild=NULL; delete q; }else{ q=p; p=p->parent; delete q; p->lChild=NULL; } } delete head; head=NULL; }
4.用 三叉鏈表存儲結構+前序序列+中序序列 構建二叉樹
bool preAndInCreateTriTree(TriTree &p,TriTree parent,int *preOrder,int *inOrder,int length){ if(length>0){ if(!(p=new TriTNode)) return false; p->data=preOrder[0]; p->lTag=0; p->rTag=0; p->parent=parent; int i; for(i=0;i<length&&inOrder[i]!=preOrder[0];++i); preAndInCreateTriTree(p->lChild,p,preOrder+1,inOrder,i); preAndInCreateTriTree(p->rChild,p,preOrder+i+1,inOrder+i+1,length-i-1); }else{ p=NULL; } return true; }
測試代碼:
#include<iostream> using namespace std; typedef struct TriTNode{//trifurcate linked list tree node struct TriTNode *lChild,*rChild,*parent; int data,lTag,rTag; }TriTNode,*TriTree; TriTree pre=NULL; void visit(int val){ cout<<val<<" "; } bool preAndInCreateTriTree(TriTree &p,TriTree parent,int *preOrder,int *inOrder,int length){ if(length>0){ if(!(p=new TriTNode)) return false; p->data=preOrder[0]; p->lTag=0; p->rTag=0; p->parent=parent; int i; for(i=0;i<length&&inOrder[i]!=preOrder[0];++i); preAndInCreateTriTree(p->lChild,p,preOrder+1,inOrder,i); preAndInCreateTriTree(p->rChild,p,preOrder+i+1,inOrder+i+1,length-i-1); }else{ p=NULL; } return true; } int main(){ int n,*preOrder,*inOrder; cout<<"Input the number of nodes : "; cin>>n; preOrder=new int[n]; inOrder=new int[n]; cout<<"Input the pre-order sequence : "<<endl; for(int i=0;i<n;++i) cin>>preOrder[i]; cout<<"Input the in-order sequence : "<<endl; for(int i=0;i<n;++i) cin>>inOrder[i]; TriTree T; TriTree head; if(!preAndInCreateTriTree(T,NULL,preOrder,inOrder,n)){ cout<<"Fail to construct this tree"<<endl; }else{ postThreadTree(T,head); cout<<"\nPost-traverse:"<<endl; postTraverseTriTree(head); } deleteTriTree(head); T=NULL; }