【數(shù)據(jù)結(jié)構(gòu)】線索二叉樹

基本概念

遍歷二叉樹是對非線性結(jié)構(gòu)結(jié)點的線性化過程,由此得到的遍歷序列中,每個結(jié)點有且僅有一個前驅(qū)和后繼(除了序列中的第一個和最后一個結(jié)點)。

原始二叉鏈表的結(jié)點結(jié)構(gòu)僅包含數(shù)據(jù)元素信息和左右指針域,若在結(jié)點結(jié)構(gòu)中增加前驅(qū)和后繼的指針域,則該存儲結(jié)構(gòu)稱為線索二叉樹。

雖然可以直接增加兩個指針域來實現(xiàn)這種結(jié)構(gòu),但這樣會使結(jié)構(gòu)的存儲密度大大降低。(存儲密度 = 數(shù)據(jù)元素本身占用的存儲量 / 結(jié)點結(jié)構(gòu)占用的存儲量)

要想利用空指針域來存放前驅(qū)、后繼的地址,還需要將前驅(qū)、后繼和左、右子樹根結(jié)點區(qū)分開。因此我們新增兩個標(biāo)志域:LTag和RTag(整型),1表示有子樹,0表示無子樹。

1)當(dāng)LTag = 0時,lchild域指示結(jié)點的左子樹根結(jié)點;當(dāng)LTag = 1時,lchild域指示結(jié)點在某個遍歷序列中的前驅(qū)。

2)當(dāng)RTag = 0時,rchild域指示結(jié)點的右子樹根結(jié)點;當(dāng)RTag = 1時,rchild域指示結(jié)點在某個遍歷序列中的后繼。

指向前驅(qū)、后繼的指針稱為線索。

typedef struct ThBinode
{
    Elemtype data;
 
    struct ThBinode *lchild, *rchild;
 
    int LTag, RTag;
 
} ThBinode, *ThBiTree;

構(gòu)造線索二叉樹

構(gòu)造線索二叉樹實質(zhì)上是將二叉鏈表中的空指針域改為前驅(qū)、后繼指針域。

又因為前驅(qū)、后繼的信息只有在遍歷的時候才能得到,所以線索化的過程就是在遍歷的時候修改空指針的過程。

為了記下遍歷過程中訪問結(jié)點的先后關(guān)系,附設(shè)一個指針pre指向剛剛訪問過的結(jié)點(即序列中的前一個結(jié)點),而指針p指向當(dāng)前訪問的結(jié)點。


/*--------以結(jié)點p為根的子樹的中序線索化--------*/
 
void InThreading(ThBiTree p)
{
    if(p)
    {
        InThreading(p->lchild);     /*左子樹遞歸線索化*/
 
        if(!p->lchild)              /*如果沒有左子樹*/
        {
            p->LTag = 1;            /*設(shè)置前驅(qū)*/
            p->lchild = pre;
        }
 
        else p->RTag = 0;           /*有左子樹*/
 
        if(!pre->rchild)            /*如果沒有右子樹*/
        {
            pre->RTag = 1;          /*設(shè)置后繼*/
            pre->rchild = p;
        }
 
        else pre->rchild = 0;
 
        pre = p;
 
        InThreading(p->rchild);     /*右子樹遞歸線索化*/
    }
}
/*---------帶頭結(jié)點的二叉樹的中序線索化--------*/
 
void InOrderThreading(ThBiTree &tb, ThBiTree t)
{
    tb = new ThBinode;      /*建立頭結(jié)點*/
 
    tb->LTag = 0;           /*頭結(jié)點有左孩子,為根結(jié)點*/
    tb->Rtag = 1;           /*頭結(jié)點無右孩子,后繼線索為中序遍歷的最后一個結(jié)點*/
 
    tb->rchild = tb;        /*初始化時后繼為頭結(jié)點本身*/
 
    if(!t) tb->lchild = tb; /*若二叉樹為空,左孩子也為頭結(jié)點本身*/
 
    else
    {
        tb->lchild = t; pre = tb;   /*頭結(jié)點的作用體現(xiàn),統(tǒng)一根結(jié)點與其他結(jié)點的處理方式*/
 
        InThreading(t);             /*對二叉樹中序線索化*/
 
        pre->RTag = 1;              /*線索化結(jié)束后,pre為二叉樹的最右結(jié)點*/
 
        pre->rchild = tb;           /*使其右線索指向頭結(jié)點*/
                                    
        tb->rchild = pre;           /*將頭結(jié)點的后繼從它本身改為最右結(jié)點*/
    }
}
 

 

遍歷線索二叉樹

由于有了結(jié)點的前驅(qū)和后繼信息,線索二叉樹的遍歷和指定次序下查找結(jié)點的前驅(qū)和后繼算法都變得簡單。

線索二叉樹的遍歷不需要設(shè)棧,避免了頻繁的進(jìn)棧、出棧,因此在時間和空間上都較遍歷二叉樹節(jié)省。

因此,若需要經(jīng)常查找結(jié)點在所遍歷線性序列中的前驅(qū)和后繼,則采用線索鏈表作為存儲結(jié)構(gòu)。

1)中序線索二叉樹

  1. 查找p的前驅(qū):查左線索;若無左線索,結(jié)點的前驅(qū)是遍歷左子樹時訪問的最后一個結(jié)點。

  2. 查找p的后繼:查右線索;若無右線索,結(jié)點的后繼是遍歷右子樹時訪問的第一個結(jié)點。

2)先序線索二叉樹

  1. 查找p的前驅(qū):查左線索;若無左線索,結(jié)點的前驅(qū)是結(jié)點的雙親結(jié)點,或是先序遍歷其雙親結(jié)點左子樹時最后訪問的結(jié)點。

  2. 查找p的后繼:查右線索;若無右線索,結(jié)點的后繼必為結(jié)點的左子樹(若存在)或右子樹根結(jié)點。

3)后序線索二叉樹

1. 查找p的前驅(qū):查左線索;若無左線索,且無右線索時,結(jié)點的前驅(qū)是右子樹根結(jié)點;若無左線索,但是有右線索時,結(jié)點的前驅(qū)是左子樹根結(jié)點。
2. 查找p的后繼,這種查找比較復(fù)雜,分4類情況討論:

若p為二叉樹的根結(jié)點,后繼為空;
若p為右子樹根結(jié)點,后繼為雙親結(jié)點;
若p為左子樹根結(jié)點,且無右兄弟,后繼為雙親結(jié)點;
若p為左子樹根結(jié)點,且有右兄弟,后繼為后序遍歷雙親結(jié)點右子樹時訪問的第一個結(jié)點。

由上述情況可知,在先序線索二叉樹上找前驅(qū)和在后序線索二叉樹上找后繼都比較復(fù)雜。

遍歷線索二叉樹的時間復(fù)雜度為O(n),與遞歸或非遞歸遍歷二叉鏈表一樣,但前者的空間復(fù)雜度為O(1),而后者為O(n),因為遍歷線索二叉樹不需要棧。


/*----------遍歷中序線索二叉樹----------*/

void InOrderTraverse(ThBiTree t)
{/*t指向線索二叉樹的頭結(jié)點,而頭結(jié)點的左指針指向二叉樹的根結(jié)點*/
   ThBinode *p = t->lchild;        /*使p指向根結(jié)點*/

   while(p != t)                   /*若線索二叉樹不為空或遍歷未結(jié)束*/
   {
       while(p->LTag == 0) p=p->lchild;    /*沿左孩子往下,定位*/

       cout<<p->data;                      /*訪問左子樹為空的結(jié)點*/

       while(p->RTag == 1 && p->rchild != t)   /*若有右線索,且右線索不為頭結(jié)點*/
       {
           p = r->rchild;
           cout<<p->data;                  /*沿右線索訪問后繼結(jié)點*/
       }

       p = p->rchild;              /*轉(zhuǎn)向p的右子樹*/
   }
}

原文鏈接:https://blog.csdn.net/ha1f_awake/article/details/85186310

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。