线索二叉树(c/c++)
線索二叉樹(shù)
定義:
對(duì)于n個(gè)結(jié)點(diǎn)的二叉樹(shù),在二叉鏈存儲(chǔ)結(jié)構(gòu)中有n+1個(gè)空鏈域,利用這些空鏈域存放在某種遍歷次序下該結(jié)點(diǎn)的前驅(qū)結(jié)點(diǎn)和后繼結(jié)點(diǎn)的指針,這些指針?lè)Q為線索,加上線索的二叉樹(shù)稱(chēng)為線索二叉樹(shù)。
特點(diǎn):
利用線索二叉樹(shù)進(jìn)行遍歷時(shí),不必采用堆棧處理,可看做是對(duì)線性結(jié)構(gòu)進(jìn)行訪問(wèn),速度比一般二叉樹(shù)的遍歷速度快,且節(jié)約存儲(chǔ)空間。并且任意一個(gè)結(jié)點(diǎn)都能直接找到它的前驅(qū)和后繼結(jié)點(diǎn)。 但是結(jié)點(diǎn)的插入和刪除麻煩,且速度也較慢。
中序線索二叉樹(shù)
存儲(chǔ)結(jié)構(gòu)為
當(dāng)某個(gè)結(jié)點(diǎn)的ltag等于0時(shí),表示該結(jié)點(diǎn)的lc指針不為空,即它有左孩子;當(dāng)ltag等于1時(shí),表示該結(jié)點(diǎn)的lc為空指針,這時(shí)就將其設(shè)置為線索。指向該結(jié)點(diǎn)在中序遍歷中的直接前驅(qū)。
同理rtag指向該結(jié)點(diǎn)在中序遍歷中的直接后繼。
當(dāng)ltag/rtag為1時(shí),lc/rc由原來(lái)的空指針被修改為指向該結(jié)點(diǎn)的前驅(qū)/后繼。
算法思路:
1,進(jìn)行中序線索化時(shí),初始化所有l(wèi)tag和rtag都為0;
2,采用p指針指向當(dāng)前結(jié)點(diǎn),采用pre指針指向當(dāng)前結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)。
3,初始將pre置為NULL,通過(guò)遞歸入棧找到中序遍歷中的第一個(gè)結(jié)點(diǎn)p,對(duì)它的lc和ltag修改,令其ltag=1;lc=pre;然后對(duì)pre賦值為p, 而p將被賦值為它在中序遍歷中的下一個(gè)結(jié)點(diǎn)。
第一種情況:若p沒(méi)有右子樹(shù),那么p應(yīng)該被賦值為它的父結(jié)點(diǎn),這通過(guò)退棧操作來(lái)完成。
第二張情況:若p有右子樹(shù),則需要將p->lc遞歸入棧找到p->lc結(jié)點(diǎn)最左邊的結(jié)點(diǎn)
4,函數(shù)執(zhí)行到最后,pre指向中序遍歷的最后一個(gè)結(jié)點(diǎn)。需要將pre->rtag=1;pre->rc=NULL;至此結(jié)束。
線索化代碼實(shí)現(xiàn):
在這采用兩個(gè)函數(shù)來(lái)實(shí)現(xiàn)中序線索化,注意!inThread函數(shù)的pre參數(shù)為對(duì)指針的引用。
void createInThread(tbtNode* p)//創(chuàng)建中序線索二叉樹(shù) {tbtNode* pre = NULL;if (p != NULL){inThread(p, pre);//傳遞pre指針的引用,否則inThread運(yùn)行完畢后,pre仍為NULLpre->rc = NULL;//此時(shí)pre為二叉樹(shù)中序遍歷最后一個(gè)結(jié)點(diǎn),其右子樹(shù)定為空pre->rtag = 1;} } void inThread(tbtNode* p, tbtNode*& pre)//對(duì)pre指針的引用 {if (p != NULL){inThread(p->lc, pre);//對(duì)p的左子樹(shù)遞歸調(diào)用if (p->lc == NULL ){p->lc = pre;p->ltag = 1;}if (pre != NULL&&pre->rc == NULL){pre->rc = p;pre->rtag = 1;}pre = p;p = p->rc;inThread(p, pre);//對(duì)當(dāng)前p的左子樹(shù)遞歸調(diào)用} }在中序線索二叉樹(shù)中求后繼的代碼如下:
tbtNode* next(tbtNode* p) {if (p != NULL){if (p->rtag == 1)return p->rc;tbtNode* temp = p->rc;while (temp->ltag==0)//判定條件不能寫(xiě)成temp->lc != NULLtemp = temp->lc;return temp;} }附上一個(gè)完整的例子:
#include<iostream> typedef struct tbtNode {char data;//結(jié)點(diǎn)中的信息struct tbtNode* lc;//左孩子結(jié)點(diǎn)struct tbtNode* rc;//右孩子結(jié)點(diǎn)int ltag, rtag;//左右指針標(biāo)識(shí) }tbtNode;tbtNode* initial(char* ele, int num);//用數(shù)組初始化一棵樹(shù)(創(chuàng)建一棵完全二叉樹(shù)) void createInThread(tbtNode* p);//創(chuàng)建中序線索二叉樹(shù) void inThread(tbtNode* p, tbtNode*& pre);//對(duì)二叉樹(shù)進(jìn)行線索化 tbtNode* next(tbtNode* p);//求p結(jié)點(diǎn)的后繼結(jié)點(diǎn) void inOrder(tbtNode* p);//中序遍歷(中序線索二叉樹(shù)) int main() {using namespace std;char data[6] = { 'a', 'b', 'c', 'd', 'e', 'f' };tbtNode* p = initial(data, 6);createInThread(p);cout << "中序線索樹(shù)遍歷:";inOrder(p);cout << endl;return 0; } tbtNode* initial(char* ele, int num) {if (num<1)return NULL;tbtNode* temp = new tbtNode[num];int i = 0;while (i < num)//將所有結(jié)點(diǎn)的左右子樹(shù)置為空,左右標(biāo)識(shí)均置為0{temp[i].lc = NULL;temp[i].rc = NULL;temp[i].ltag = 0;temp[i].rtag = 0;++i;}i = 0;while (i < num/2)//通過(guò)完全二叉樹(shù)的順序存儲(chǔ)來(lái)創(chuàng)建樹(shù)的結(jié)構(gòu){if (2*i+1<num)temp[i].lc = temp + 2 * i + 1;if (2*i+2<num)temp[i].rc = temp + 2 * i + 2;++i;}for (i = 0; i < num; i++)//對(duì)樹(shù)中的每個(gè)結(jié)點(diǎn)賦值temp[i].data = ele[i];return temp; } void createInThread(tbtNode* p) {tbtNode* pre = NULL;if (p != NULL){inThread(p, pre);//傳遞pre指針的引用,否則inThread運(yùn)行完畢后,pre仍為NULLpre->rc = NULL;//此時(shí)pre為二叉樹(shù)中序遍歷最后一個(gè)結(jié)點(diǎn),其右子樹(shù)定為空pre->rtag = 1;} } void inThread(tbtNode* p, tbtNode*& pre)//對(duì)pre指針的引用 {if (p != NULL){inThread(p->lc, pre);//對(duì)p的左子樹(shù)遞歸調(diào)用if (p->lc == NULL ){p->lc = pre;p->ltag = 1;}if (pre != NULL&&pre->rc == NULL){pre->rc = p;pre->rtag = 1;}pre = p;p = p->rc;inThread(p, pre);//對(duì)當(dāng)前p的左子樹(shù)遞歸調(diào)用} } tbtNode* next(tbtNode* p) {if (p != NULL){if (p->rtag == 1)return p->rc;tbtNode* temp = p->rc;while (temp->ltag==0)//判定條件不能寫(xiě)成temp->lc != NULLtemp = temp->lc;return temp;} } void inOrder(tbtNode* p) {if (p != NULL){while (p->ltag == 0)p = p->lc;//查找中序遍歷第一個(gè)結(jié)點(diǎn)while (p != NULL)//類(lèi)似鏈表的順序訪問(wèn)進(jìn)行中序遍歷{std::cout << p->data << ' ';p = next(p);}} }后序線索二叉樹(shù)
關(guān)于后序線索二叉樹(shù),在這里只介紹如何求p結(jié)點(diǎn)的后繼。
一,如果p->rtag為1,那么p的后繼為p->rc
二,若p->rtag為0時(shí):
1,若p結(jié)點(diǎn)是它的父結(jié)點(diǎn)f的右孩子,那么父結(jié)點(diǎn)f為p的后繼。
2,若若p結(jié)點(diǎn)是它的父結(jié)點(diǎn)f的左孩子:a,若p沒(méi)有右兄弟,那么父結(jié)點(diǎn)f為p的后繼。b,若p有右兄弟,那么p的后繼為在右兄弟上后序遍歷得到的第一個(gè)結(jié)點(diǎn)。(有些累,敲不懂了…無(wú)代碼~)
總結(jié)
以上是生活随笔為你收集整理的线索二叉树(c/c++)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 二叉树的非递归遍历(c/c++)
- 下一篇: 哈夫曼树(最优二叉树)(c/c++)