1. 程式人生 > >二叉樹線索化和遍歷的演算法

二叉樹線索化和遍歷的演算法

前言:

關於二叉線索樹有什麼作用,為什麼要建立這裡就不介紹。因為時間問題,只是總結一下線索化和遍歷的演算法。這個演算法和前面總結過的非遞迴法遍歷二叉樹都算是資料結構裡面難度係數比棧,佇列,線性表那些大的演算法。限定時間內要寫出來還是有些難度,最好是能有所總結,才能做到得心應手。

先序:

先序線索化

void PreThreading(BiTreeNode *p, BiTreeNode *pre==NULL) { //在資料結構中我比較喜歡用p指標指向正在操作的結點
    if(p != NULL){

        if(p->lchild == NULL) { //當前結點的左孩子為空可作索引(前繼索引)
p->lchild = prev; p->ltag = 1; //1表示索引,0表示結點 } if(prev != NULL && prev->rchlid == NULL) { //上一個結點的右孩子為空可作索引(後繼索引) prev->rchild = p; prev->ltag = 1; } prev = p; //前驅往後走一步 if(p->ltag == 0) //p也往前走, 先左走後右,按照先序遍歷的順序 根-左-右
PreThreading(p->lchild); PreThreading(p->rchild); } }

前序遍歷

//用前序線索化建立的線索樹來進行前序遍歷,實際上ltag為1,即前續索引指標是沒什麼卵用的。主要用的是後續索引指標,這個指標也就使得我們進行前序遍歷不需要藉助遞迴和棧也能完成。
void PreOrder(BiTreeNode *ROOT) {
    if(ROOT == NULL)
        return;
    BiTreeNode *p = ROOT;//工作指標
    while(p != NULL
) { //將左子樹遍歷完,之所以只需要tag為0,是因為空指標直接標1了,即空指標=索引結點 while(p->ltag == 0) { cout << p->data << " "; p = p->lchild; } cout << p->data << " "; //最左一個結點,自身也要訪問 //這就是後續線索指標的作用了,直接訪問後續 if(p->ltag == 1) p = p->rchild;//這一步結束之後如果p是NULL,則這次迴圈完就結束了 while(p != NULL) { if (p->ltag = 0) //左邊還有結點 break; //跳出小迴圈,回到大迴圈繼續做 cout << p->data << " "; p = p->rchild; //由於上面已經過濾了有左孩子的情況,只要一直往右走就是。 } } }

中序

中序線索化

void InThreading(ThreadTree &p,ThreadTree &pre) {
    if(p != NULL)
        InThreading(p->lchild,pre);
        if(p->lchild == NULL) { //前驅線索
            p->lchild = pre;
            p->ltag = 1;
        }
        if(pre!=NULL && pre->rchild==NULL) { //後續線索
            pre->rchild = p;
            pre->rtag = 1;
        }
        InThreading(p->rchild,pre);
}

中序遍歷線索樹

TheradNode *FirstNode(ThreadNode *p) { //找到最左邊結點(前序在這一步就要邊走邊訪問)
    while(p->Itag==0) p=p->lchild;
    return p;
}
ThreadNode *NextNode(ThreadNode *p) { 
    if(p->rtag == 0) return FirstNode(p->rchild);//繼續訪問右結點的前序
    else return p->rchild;//直接返回後續線索(這個就是中序序列下一個結點,注意區別於之前的前序序列)
}
void Inorder(ThreadNode *T) {
    for(ThreadNode *p=FirstNode(T);p!=NULL;p=NextNode())
        visit(p);
}

後序

後序線索化

void PostThreading(ThreadTree &p,ThreadTree &pre) {
    if(p!=NULL) {
        PostThreading(p->rchild);
        PostThreading(p->lchild);
        if(p->lchild==NULL) {
            p->lchild = pre;
            p->ltag = 1;
        }
        if(pre!=NULL && pre->rchild == NULL) {
            pre->rchild = p;
            pre->rtag = 1;
        }
        pre = p;
    }
}

後續遍歷

後續如果沒有新增雙親指標,是無法實現的。
怎麼理解呢:
這裡寫圖片描述
如圖,遍歷到E的時候,下一個結點是B,但是E的左右都有孩子結點,沒有多餘的指標可以指向B,所以除非藉助雙親指標或者棧的幫助,否則無法實現。