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

一、 概念

二叉樹按照先序昌阿、中序饥脑、后續(xù)遍歷的方法形成一個線性序列后恳邀,每個結(jié)點(除第一個和最后一個外),都有且僅有一個直接前驅(qū)和直接后繼灶轰。但是谣沸,當(dāng)二叉鏈表作為存儲結(jié)構(gòu)時,只能找到結(jié)點的左右孩子的信息笋颤,而不能直接得到結(jié)點在任一序列中的前驅(qū)和后繼信息乳附,這個信息只在遍歷的過程中才能得到。因此引入線索二叉樹來保存這些在遍歷過程中得到的前驅(qū)和后繼的信息伴澄。

雖然可以在每個結(jié)點中增加兩個指針域來存放在遍歷時得到的有關(guān)前驅(qū)和后繼信息赋除,但這樣做使得存儲密度大大降低。由于有n個結(jié)點的二叉鏈表中必定存在n+1個空鏈域非凌,因此可以充分利用這些空鏈域來存放結(jié)點的前驅(qū)和后繼信息贤重。

Tip:
證明:n個結(jié)點的二叉鏈表中必定存在n+1個空鏈域
含有n個結(jié)點的二叉鏈表中,每個結(jié)點都有兩個鏈域清焕,因此一共有2n個鏈域并蝗。
除了根結(jié)點以外的每個點都有一個父結(jié)點,所以一共有n-1結(jié)點需要使用一個鏈域來指向父結(jié)點秸妥。
所以一共有2
n-(n-1)=n+1個鏈域是空的滚停。

為此做如下規(guī)定:當(dāng)結(jié)點的左指針為空(即無左子樹)時,令該指針指向該結(jié)點的前驅(qū)結(jié)點粥惧;當(dāng)結(jié)點的右指針為空(即無右子樹)時键畴,令該指針指向該結(jié)點的后繼結(jié)點;為了避免混淆突雪,還需要增加兩個標(biāo)志位來區(qū)分指針指向的是其孩子還是前驅(qū)及后繼起惕。


image.png
typedef struct BiThrNode  
{  
   TelemTpye data;  
   struct BiThrNode *lchild,*rchild;      /*左右孩子指針*/  
   int LTag,RTag;               /*左右標(biāo)志*/  
} BiThrNode,*BiThrTree; 

以這種結(jié)點結(jié)構(gòu)構(gòu)成的二叉鏈表作為二叉樹的存儲結(jié)構(gòu),叫做線索鏈表咏删,其中指向結(jié)點前驅(qū)和后繼的指針叫做線索惹想。加上線索的二叉樹稱之為線索二叉樹。

對二叉樹以某種次序遍歷使其變成線索二叉樹的過程叫做線索化督函。

二嘀粱、建立線索二叉樹

線索化的過程就是遍歷二叉樹的過程。在遍歷的過程中辰狡,檢查當(dāng)前結(jié)點的左锋叨、右指針域是否為空,若為空宛篇,將它們改為指向前驅(qū)結(jié)點或后繼結(jié)點的線索娃磺。

二叉樹的中序序列a+b*c-d-e/f,形成的中序線索鏈表叫倍,如下圖所示:


image.png

以結(jié)點為根的中序線索化算法:

void InThreading(BiThrTree p) {  
    //pre是全局變量偷卧,初始化時其右孩子指針為空嘿般,便于在樹的最左點開始建線索
    if (p) {  
        InThreading(p->lchild);            /*左子樹遞歸線索化*/  
        if(!p->lchild) {                      /*p的左孩子為空*/  
            p->LTag=1;                     /*給p加上左線索*/  
            p->lchild=pre;                 /*p的左孩子指針指向pre(前驅(qū))*/  
        }  
        else {  
            p->LTag=0;  
        }  
        if(!pre->rchild) {                  /*pre的右孩子為空*/  
            pre->RTag=1;                  /*給pre加上右線索*/  
            pre->rchild=p;                /*pre的右孩子指針指向p(后繼)*/  
        }  
        else {
            pre->RTag=0;  
        }  
        pre=p;                            /*保持pre指向p的前驅(qū)*/  
        InThreading(p->rchild);           /*右子樹遞歸線索化*/  
     }  
}  

三、遍歷線索二叉樹

由于有了結(jié)點的前驅(qū)和后繼信息涯冠,線索二叉樹的遍歷和在指定次序下查找結(jié)點的前驅(qū)和后繼算法都變得簡單。因此逼庞,若需經(jīng)常查找結(jié)點的前驅(qū)和后繼蛇更,就可以采用線索鏈表作為存儲結(jié)構(gòu)。

1赛糟、 在中序線索二叉樹中查找
A派任、 查找p指針?biāo)附Y(jié)點的前驅(qū):
若p->LTag = 1,則p的左鏈指示其前驅(qū)(/ 的前驅(qū)是e)
若p->LTag = 0璧南,則說明p有左子樹掌逛,結(jié)點的前驅(qū)是遍歷左子樹時最后訪問的一個結(jié)點(* 的前驅(qū)是b)
B、 查找p指針?biāo)附Y(jié)點的后繼:
若p->RTag = 1司倚,則p的右鏈指示其后繼豆混。(b的后繼為
若p->RTag = 0,則說明p有右子樹动知。結(jié)點的后繼應(yīng)是遍歷其右子樹時訪問的第一個結(jié)點皿伺,即右子樹中最左下的結(jié)點。(查找
的后繼時盒粮,首先沿右指針找到其右子樹的根結(jié)點-鸵鸥,然后順其左指針往下直至其左標(biāo)志為1的結(jié)點,即為結(jié)點*的后繼丹皱,是結(jié)點c妒穴。)

2、 在先序線索二叉樹中查找(以下圖為例:先序遍歷為1 2 4 8 9 5 10 11 3 6 12 7)
A摊崭、 查找p指針?biāo)附Y(jié)點的前驅(qū):
若p->LTag = 0讼油,則說明p有左子樹,此時p的前驅(qū)有兩種情況:若p是其雙親的左孩子呢簸,則其前驅(qū)為其雙親結(jié)點(4結(jié)點汁讼,因為有左孩子8,所以p->LTag = 0阔墩,而4又是雙親2的左孩子嘿架,所以4的前驅(qū)是其雙親2),否則應(yīng)是其雙親的左子樹上先序遍歷最后訪問到的結(jié)點(5結(jié)點啸箫,因為有左孩子10耸彪,所以p->LTag = 0,而5又是其雙親2的右孩子忘苛,所以他的前驅(qū)為雙親2的左子樹先序遍歷最后訪問的結(jié)點9)
B蝉娜、 查找p指針?biāo)附Y(jié)點的后繼:
若p->RTag = 0唱较,則說明p有右子樹, p的后繼必為其左子樹根(若存在)或右子樹根召川。(2結(jié)點有右子樹南缓,所以p->RTag = 0,而2又有左子樹荧呐,所以2的后繼為左子樹的根4汉形,如果沒有6,12這兩個結(jié)點,3結(jié)點有右子樹倍阐,所以p->RTag = 0概疆,但3沒有左子樹,所以3的后繼為右子樹的根7)


image.png

3峰搪、 在后序線索二叉樹中查找 (以上圖為例:后序遍歷為8 9 4 10 11 5 2 12 6 7 3 1)
A岔冀、 查找p指針?biāo)附Y(jié)點的前驅(qū):
若p->LTag = 0,當(dāng)p->RTag也為0時概耻,則p的右鏈指示其前驅(qū)(結(jié)點4有左右兩個孩子使套,因此p->LTag = 0, p->RTag = 0鞠柄,4的前驅(qū)為右鏈9)童漩;若p->LTag=0,而p->RTag=1春锋,則p的左鏈指示其前驅(qū)(結(jié)點6只有左孩子矫膨,因此p->LTag = 0, p->RTag = 1期奔,6的前驅(qū)為左鏈12)侧馅。
B、 查找p指針?biāo)附Y(jié)點的后繼情況比較復(fù)雜呐萌,分以下情況討論:
以下圖為例:后序遍歷為:A B C D E F G H
若p是二叉樹的根馁痴,則后繼為空。
若p是其雙親的右孩子肺孤,則后繼為雙親結(jié)點罗晕。(B的后繼為C,結(jié)點C的后繼為D)
若p是其雙親的左孩子赠堵,且p沒有右兄弟小渊,則其后繼為雙親結(jié)點。(結(jié)點F的后繼為G)
若p是其雙親的左孩子茫叭,且p有右兄弟酬屉,則其后繼為雙親的右子樹上按后序遍歷列出的第一個結(jié)點(即右子樹中“最左下”的葉結(jié)點) 。(結(jié)點D的后繼為E)


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市呐萨,隨后出現(xiàn)的幾起案子杀饵,更是在濱河造成了極大的恐慌,老刑警劉巖谬擦,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件切距,死亡現(xiàn)場離奇詭異,居然都是意外死亡惨远,警方通過查閱死者的電腦和手機谜悟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锨络,“玉大人,你說我怎么就攤上這事狼牺∠鄱” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵是钥,是天一觀的道長掠归。 經(jīng)常有香客問我,道長悄泥,這世上最難降的妖魔是什么虏冻? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮弹囚,結(jié)果婚禮上厨相,老公的妹妹穿的比我還像新娘。我一直安慰自己鸥鹉,他們只是感情好蛮穿,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著毁渗,像睡著了一般践磅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灸异,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天府适,我揣著相機與錄音,去河邊找鬼肺樟。 笑死檐春,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的么伯。 我是一名探鬼主播喇聊,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蹦狂!你這毒婦竟也來了誓篱?” 一聲冷哼從身側(cè)響起朋贬,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窜骄,沒想到半個月后锦募,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡邻遏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年糠亩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片准验。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡赎线,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糊饱,到底是詐尸還是另有隱情垂寥,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布另锋,位于F島的核電站滞项,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏夭坪。R本人自食惡果不足惜文判,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望室梅。 院中可真熱鬧戏仓,春花似錦、人聲如沸亡鼠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拆宛。三九已至嗓奢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浑厚,已是汗流浹背股耽。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钳幅,地道東北人物蝙。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像敢艰,于是被迫代替她去往敵國和親诬乞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容