日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

线索二叉树(c/c++)

發布時間:2025/6/17 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线索二叉树(c/c++) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

線索二叉樹

定義:

對于n個結點的二叉樹,在二叉鏈存儲結構中有n+1個空鏈域,利用這些空鏈域存放在某種遍歷次序下該結點的前驅結點和后繼結點的指針,這些指針稱為線索,加上線索的二叉樹稱為線索二叉樹。

特點:

利用線索二叉樹進行遍歷時,不必采用堆棧處理,可看做是對線性結構進行訪問,速度比一般二叉樹的遍歷速度快,且節約存儲空間。并且任意一個結點都能直接找到它的前驅和后繼結點。 但是結點的插入和刪除麻煩,且速度也較慢。

中序線索二叉樹

存儲結構為
lcltagdatartagrc
typedef struct tbtNode {char data;//結點中的信息struct tbtNode* lc;//指向左孩子結點struct tbtNode* rc;//指向右孩子結點int ltag, rtag;//左右指針標識 }tbtNode;

當某個結點的ltag等于0時,表示該結點的lc指針不為空,即它有左孩子;當ltag等于1時,表示該結點的lc為空指針,這時就將其設置為線索。指向該結點在中序遍歷中的直接前驅。
同理rtag指向該結點在中序遍歷中的直接后繼。
當ltag/rtag為1時,lc/rc由原來的空指針被修改為指向該結點的前驅/后繼。

算法思路:

1,進行中序線索化時,初始化所有ltag和rtag都為0;
2,采用p指針指向當前結點,采用pre指針指向當前結點的前一個結點。
3,初始將pre置為NULL,通過遞歸入棧找到中序遍歷中的第一個結點p,對它的lc和ltag修改,令其ltag=1;lc=pre;然后對pre賦值為p, 而p將被賦值為它在中序遍歷中的下一個結點。
第一種情況:若p沒有右子樹,那么p應該被賦值為它的父結點,這通過退棧操作來完成。
第二張情況:若p有右子樹,則需要將p->lc遞歸入棧找到p->lc結點最左邊的結點
4,函數執行到最后,pre指向中序遍歷的最后一個結點。需要將pre->rtag=1;pre->rc=NULL;至此結束。

線索化代碼實現:

在這采用兩個函數來實現中序線索化,注意!inThread函數的pre參數為對指針的引用。

void createInThread(tbtNode* p)//創建中序線索二叉樹 {tbtNode* pre = NULL;if (p != NULL){inThread(p, pre);//傳遞pre指針的引用,否則inThread運行完畢后,pre仍為NULLpre->rc = NULL;//此時pre為二叉樹中序遍歷最后一個結點,其右子樹定為空pre->rtag = 1;} } void inThread(tbtNode* p, tbtNode*& pre)//對pre指針的引用 {if (p != NULL){inThread(p->lc, pre);//對p的左子樹遞歸調用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);//對當前p的左子樹遞歸調用} }

在中序線索二叉樹中求后繼的代碼如下:

tbtNode* next(tbtNode* p) {if (p != NULL){if (p->rtag == 1)return p->rc;tbtNode* temp = p->rc;while (temp->ltag==0)//判定條件不能寫成temp->lc != NULLtemp = temp->lc;return temp;} }

附上一個完整的例子:

#include<iostream> typedef struct tbtNode {char data;//結點中的信息struct tbtNode* lc;//左孩子結點struct tbtNode* rc;//右孩子結點int ltag, rtag;//左右指針標識 }tbtNode;tbtNode* initial(char* ele, int num);//用數組初始化一棵樹(創建一棵完全二叉樹) void createInThread(tbtNode* p);//創建中序線索二叉樹 void inThread(tbtNode* p, tbtNode*& pre);//對二叉樹進行線索化 tbtNode* next(tbtNode* p);//求p結點的后繼結點 void inOrder(tbtNode* p);//中序遍歷(中序線索二叉樹) int main() {using namespace std;char data[6] = { 'a', 'b', 'c', 'd', 'e', 'f' };tbtNode* p = initial(data, 6);createInThread(p);cout << "中序線索樹遍歷:";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)//將所有結點的左右子樹置為空,左右標識均置為0{temp[i].lc = NULL;temp[i].rc = NULL;temp[i].ltag = 0;temp[i].rtag = 0;++i;}i = 0;while (i < num/2)//通過完全二叉樹的順序存儲來創建樹的結構{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++)//對樹中的每個結點賦值temp[i].data = ele[i];return temp; } void createInThread(tbtNode* p) {tbtNode* pre = NULL;if (p != NULL){inThread(p, pre);//傳遞pre指針的引用,否則inThread運行完畢后,pre仍為NULLpre->rc = NULL;//此時pre為二叉樹中序遍歷最后一個結點,其右子樹定為空pre->rtag = 1;} } void inThread(tbtNode* p, tbtNode*& pre)//對pre指針的引用 {if (p != NULL){inThread(p->lc, pre);//對p的左子樹遞歸調用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);//對當前p的左子樹遞歸調用} } tbtNode* next(tbtNode* p) {if (p != NULL){if (p->rtag == 1)return p->rc;tbtNode* temp = p->rc;while (temp->ltag==0)//判定條件不能寫成temp->lc != NULLtemp = temp->lc;return temp;} } void inOrder(tbtNode* p) {if (p != NULL){while (p->ltag == 0)p = p->lc;//查找中序遍歷第一個結點while (p != NULL)//類似鏈表的順序訪問進行中序遍歷{std::cout << p->data << ' ';p = next(p);}} }
后序線索二叉樹

關于后序線索二叉樹,在這里只介紹如何求p結點的后繼。
一,如果p->rtag為1,那么p的后繼為p->rc
二,若p->rtag為0時:
1,若p結點是它的父結點f的右孩子,那么父結點f為p的后繼。
2,若若p結點是它的父結點f的左孩子:a,若p沒有右兄弟,那么父結點f為p的后繼。b,若p有右兄弟,那么p的后繼為在右兄弟上后序遍歷得到的第一個結點。(有些累,敲不懂了…無代碼~)

總結

以上是生活随笔為你收集整理的线索二叉树(c/c++)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。