日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

(原)数据结构——线索二叉树

發布時間:2024/4/13 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (原)数据结构——线索二叉树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  原文地址:http://www.cnblogs.com/Security-Darren/p/4716082.html

  轉載務必注明出處!

  線索二叉樹的思想來源于二叉樹的存儲結構中,存在一些空的指針域,因此是否能夠將這些空間利用起來,存儲一些關于節點間先后順序的信息,由此產生了線索二叉樹。線索二叉樹中,線索反映前驅、后繼的關系,而指針則體現左右子樹。

  以二叉鏈表為例,線索二叉樹存儲結構上的特點是添加標識符,表明左右指針域究竟存的是指向前驅和后繼的線索,還是指向左右子樹的指針;

  線索二叉樹的優勢是一旦對一棵二叉樹建立了相應的線索結構,當以后使用特定的方式遍歷這課樹時,可以避免遞歸方式和非遞歸方式(利用棧)帶來的空間開銷。

  構建和遍歷線索二叉樹的思路如下:

  • 首先構造一棵二叉樹(構造二叉樹可以使用任意順序:先序、中序、后續均可);
  • 按照一定的順序線索化這棵二叉樹
  • 然后按照相同的順序遍歷該二叉樹,就可以利用上一步構建的線索信息。

  這里以帶線索的二叉鏈表方式作為存儲結構,先序創建一棵二叉樹,然后中序線索化這棵二叉樹,得到的是一棵中序線索二叉樹,此后再中序遍歷該二叉樹,就可以使用這里的線索信息,不用額外的棧空間。

  原文地址:http://www.cnblogs.com/Security-Darren/p/4716082.html

  轉載務必注明出處!

  

該例子共包括一個biThrTree.h文件和一個biThrTree..c文件

1. biThrTree.h,節點存儲結構

1 #include<stdio.h> 2 #include<stdlib.h> 3 4 #define OK 1 5 #define ERROR 0 6 #define OVERFLOW -1 7 8 typedef int Status; 9 10 typedef char TElemType; 11 12 typedef enum {Link, Thread} PointerTag; 13 14 typedef struct BiThrNode{ 15 TElemType data; 16 PointerTag LTag, RTag; // 枚舉型的特點,LTag和RTag初始為0,即Link 17 struct BiThrNode *lchild, *rchild; 18 }BiThrNode, *BiThrTree; 19 20 BiThrTree pre = NULL; // 在線索化二叉樹中用到,記錄遍歷過程中,一個節點的前驅

  由于枚舉型的變量聲明是如果沒有賦初值,默認設置初值為0,所以等于默認每個BiThrNode實例的LTag和RTag都是Link。

?

2. biThrTree.h,簡單的遍歷操作——打印

Status PrintElement(TElemType e){printf("%c", e);return OK; }

  這里定義一個最簡單的遍歷操作作為示意,僅僅打出被遍歷元素包含的數據,我們的線索二叉樹遍歷函數接受指向函數的指針,可以方便地改變遍歷函數中進行的遍歷操作。

?

3. biThrTree.h,先序創建二叉樹

  創建二叉樹可以采用任何順序,這里以先序創建為例。

1 BiThrTree CreateBiThrTree() 2 { 3 TElemType ch; 4 BiThrTree T; 5 6 scanf("%c", &ch); 7 getchar(); // “吃掉”每次輸入到緩沖區中的回車,不能缺少 8 if (ch == '$') 9 T = NULL; 10 else{ 11 T = (BiThrTree)malloc(sizeof(BiThrNode)); 12 if(!T) 13 exit(OVERFLOW); 14 T->data = ch; // 11 - 14行代碼與下面兩個遞歸調用的位置體現了創建函數采用的遍歷順序 15 printf("Input lchild of %c:\n", ch); 16 T->lchild = CreateBiThrTree(); 17 printf("Input rchild of %c:\n", ch); 18 T->rchild = CreateBiThrTree(); 19 } 20 return T; 21 }

?

  這里以美元符號"$"表示空指針,告訴程序一個節點沒有左子樹或右子樹。

  創建一棵二叉樹與單純以某種順序寫出二叉樹的遍歷結果不同,在創建二叉樹時,要以某個符號指定NULL指針,這樣程序才知道哪里是葉子節點,哪里不能再向左/右,必須回退了。

  具體的例子在本文最后的運行示例中給出。

?

4. biThrTree.h,中序線索化已經創建的二叉樹

  線索化針對的是已經創建好的二叉樹,將其中的空指針域利用起來指向前驅后繼的過程就是線索化。

1 void InThreading(BiThrTree p){ 2 if(p){ 3 InThreading(p->lchild); 4 if(!(p->lchild)){ 5 p->LTag = Thread; 6 p->lchild = pre; 7 } 8 if(!(pre->rchild)){ 9 pre->RTag = Thread; 10 pre->rchild = p; 11 } 12 pre = p; 13 InThreading(p->rchild); 14 } 15 } 16 17 Status InOrderThreading(BiThrTree *Thrt, BiThrTree T){ 18 (*Thrt) = (BiThrTree)malloc(sizeof(BiThrNode)); //頭節點不同于二叉樹的根節點 19 if(!(*Thrt)) 20 exit(OVERFLOW); 21 (*Thrt)->RTag = Thread; 22 (*Thrt)->rchild = *Thrt; 23 (*Thrt)->LTag = Link; 24 25 if(!T) 26 (*Thrt)->lchild = *Thrt; 27 else{ 28 (*Thrt)->lchild = T; 29 pre = *Thrt; // 全局的pre,這里初始化指向頭結點 30 InThreading(T); 31 pre->rchild = *Thrt; // 此時pre停留在中序遍歷二叉樹時的最后一個節點上 32 pre->RTag = Thread; 33 (*Thrt)->rchild = pre; 34 } 35 return OK; 36 }

?

?  線索化只針對原來是空的指針域,一個節點如果左指針域為空,那么線索化后該指針域指向其遍歷過程中的前驅;類似的,如果其右指針域為空,線索化后右指針域指向其遍歷過程的后繼。線索化后的二叉鏈樹中不存在空的指針域。

  考慮這段代碼中的 4 -12 行,一方面線索化的過程只關注已經創建好的二叉樹中那些空的指針域;另一方面,上文關于存儲結構的介紹已經提到,LTag和RTag的初始值都是Link,所以當中序遍歷到達某個節點時,非空的指針域已經不需要再設置Link。

  ?4 -12 行代碼中,對于中序遍歷到的每一個節點,如果它的左指針域為空,那么我們在這次遍歷中將其置為線索,而如果它的右指針域為空,我們在遍歷走向下一個節點時線索化上一個節點的右指針域。

  這樣帶來一個問題,一棵樹中最后一個被遍歷到的節點的右指針域沒有被線索化,這也就是 31 - 33 行代碼的工作。

  InOrderThreading() 創建一個額外的頭結點 Thrt ,頭結點不同于二叉樹的根節點。頭結點用來解決遍歷二叉樹過程中,第一個遍歷到的節點沒有前驅和最后一個遍歷到的節點沒有后繼的問題。

  對于一棵非空的二叉樹,Thrt的LTag為Link,左指針指向二叉樹的根節點;遍歷二叉樹時的第一個節點,如果左指針域為空,則將其指向Thrt。Thrt的RTag為Thread,Thrt的右指針指向遍歷二叉樹時的最后一個節點,同時如果最后一個節點的右指針域為空,則將其指向Thrt。

  從而中序線索化時,將會形成一個從Thrt出發,再回到Thrt的閉環,這也是線索化的優勢。

?

5. biThrTree.h,中序遍歷已經線索化的二叉樹

  采用某種順序線索化的二叉樹,可以相應地采用同樣的順序進行遍歷,中序遍歷中序線索二叉樹,不需要額外的棧空間支持,根據線索即可完成遍歷,適用于需要經常對樹進行遍歷操作,或者給定某個節點,需要判斷其前驅或者后繼的情境。

Status InOrderTraverse_Thr( BiThrTree Thrt, Status (*Visit)(TElemType e)){BiThrTree p;p = Thrt->lchild;while(p != Thrt){while(p->LTag == Link)p = p->lchild; //先走到最左端,開始if(!(*Visit)(p->data))return ERROR;while(p->RTag == Thread && p != Thrt){p = p->rchild;// 如果右指針是個線索,直接向后遍歷后繼(*Visit)(p->data);}if (p != Thrt) // 如果不加區分就走向右子樹,很有可能出現死循環,因為 p剛剛停到Thrt,還沒進行下一次循環判斷,就立刻指向Thrt的后繼,循環可能不會終止p = p->rchild;}return OK;

?  線索化和利用線索的遍歷必須遵循相同的順序。

?

6. biThrTree.c,主程序進行功能測試

1 #include"biThrTree.h" 2 3 // 1. Create Binary Tree with Pre-Order input(Creation can be in any order) 4 // 2. In-Order Threading this tree (How to threading the tree depends on in what 5 // order you are goning to traverse the tree.) 6 // 3. then In-Order Traverse this tree 7 8 int main(int argc, char *argv[]){ 9 BiThrTree T, temp; 10 11 printf("Creating Binary Thread Tree.\n"); 12 T = CreateBiThrTree(); 13 if(!T) 14 return OVERFLOW; 15 printf("Binary Thread Tree Created.\n"); 16 17 if(!InOrderThreading(&temp, T)) 18 return ERROR; 19 20 printf("In Order Traversing the Binary Thread Tree:\n"); 21 if(!InOrderTraverse_Thr(temp, &PrintElement)) 22 return ERROR; 23 printf("\nIn Order Traversing Accomplished.\n"); 24 25 return OK; 26 }

?  主程序首先創建一棵二叉樹,然后對其進行中序線索化,最后中序遍歷,打印遍歷結果。

  下面以輸入:

ABC$$DE$G$$F$$$

?

?為例先序構建一棵二叉樹,這棵二叉樹的樣子如下:

A/B/ \C D/ \E F\G

?

  在構建二叉樹時,必須指定空指針的位置。

  在GCC下編譯,程序執行的過程如下:

1 ./a.out 2 Creating Binary Thread Tree. 3 A 4 Input lchild of A: 5 B 6 Input lchild of B: 7 C 8 Input lchild of C: 9 $ 10 Input rchild of C: 11 $ 12 Input rchild of B: 13 D 14 Input lchild of D: 15 E 16 Input lchild of E: 17 $ 18 Input rchild of E: 19 G 20 Input lchild of G: 21 $ 22 Input rchild of G: 23 $ 24 Input rchild of D: 25 F 26 Input lchild of F: 27 $ 28 Input rchild of F: 29 $ 30 Input rchild of A: 31 $ 32 Binary Thread Tree Created. 33 In Order Traversing the Binary Thread Tree. 34 CBEGDFA 35 In Order Traversing Accomplished.

?  最后介紹一個中序線索化二叉樹的優點,即中序線索化后,對于二叉樹中的任何一個節點,我們都可以快速地求它的前驅和后繼:

前驅:

  • 左指針是Thread,lchild就是前驅
  • 左指針是Link,lchild是其左子樹,但是可以找到前驅:中序遍歷是先左子樹,對于左子樹而言,最后遍歷左子樹的右子樹,所以此時一個節點的前驅是其左子樹最右下的節點,沿著左子樹的右Link一直向下,遇到RTag為Thread的就是目標節點的前驅

后繼:

  • 右指針是Thread,則rchild就是后繼
  • 右指針是Link,rchild是右子樹,但是可以找到后繼:中序遍歷時,后遍歷某個節點的右子樹,而該節點的后繼就是其右子樹中最先被遍歷到的,即其右子樹最左下的節點,沿著右子樹的左Link一直向左下,直到遇到LTag為Thread的就是目標節點的后繼。

  所以,中序線索化還是很便于索引樹中任意一個節點的前驅后繼關系的。

轉載于:https://www.cnblogs.com/Security-Darren/p/4716082.html

總結

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

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

主站蜘蛛池模板: 天天干夜夜怕 | 欧美久久免费 | 在线观看中文字幕亚洲 | 黄色aaa毛片 | 日日夜夜免费精品 | 少妇按摩一区二区三区 | 最近中文字幕mv免费高清在线 | 日韩不卡免费 | 尤物av在线 | 午夜视频在线免费看 | 91人妻一区二区三区 | 果冻传媒18禁免费视频 | 亚洲精品久久久久久久蜜桃臀 | 日韩欧美国产一区二区三区 | 精品国产视频在线 | 精品少妇一区二区三区在线观看 | 亚洲综合p | a视频网站 | 免费成人在线观看动漫 | 女女互慰吃奶互揉调教捆绑 | 蜜桃臀一区二区三区 | 欧洲在线一区 | 天天操天天爱天天干 | 中文字幕亚洲成人 | 中文字幕久久久久 | 在线成人免费电影 | 在线看黄色的网站 | 91国内视频 | 日本熟女毛茸茸 | 成人免费精品视频 | 久草福利在线 | 国产一卡二卡在线播放 | 国产女人在线 | 欧美天堂视频 | 黄色一级图片 | 欧美激情va永久在线播放 | 免费人成在线观看视频播放 | 800av在线视频| 免费 成 人 黄 色 | 国产成人一区二区三区别 | 黄色国产片 | 青草青草久热 | 国产九九 | 国产成年无码久久久久毛片 | 欧美日韩成人在线视频 | 高清黄色一级片 | 国产福利片一区二区 | 激烈的性高湖波多野结衣 | 歪歪视频在线观看 | www香蕉视频 | 北条麻妃av在线 | 美女毛片在线 | 成人免费视频软件网站 | 亚洲色图在线视频 | caoporn成人 | 欧美激情喷水 | 国产第一av | 日韩欧美不卡在线 | 日韩av一区二区三区在线观看 | 红猫大本营在线观看的 | 美女精品 | 伊人伊色 | 丁香伊人 | 亚洲人体一区 | 国产午夜视频在线播放 | 狠久久| 男人天堂av网 | 最新不卡av | 91网站免费看 | 日韩av在线网址 | www.天堂av | 亚洲精品午夜 | 欧美日韩免费一区 | 夜夜骚视频 | 久久韩日| 久久久久香蕉 | 久久免费看 | 国产一区二区三区在线免费 | 麻豆传媒在线看 | 中文字幕一区二区三区免费 | 亚洲伦理在线播放 | 99久久精品免费看国产 | 国产做爰xxxⅹ高潮视频12p | 男女草比视频 | 毛片在线视频观看 | 国产精品美女av | 久久人 | 91视频在线观看 | 一级特黄av | 伊人7 | 免费一区二区三区视频在线 | 97超碰色| 久久国产精品99久久人人澡 | 欧美色精品 | 激情五月在线观看 | 国产真实乱在线更新 | 久久久久久国产精品日本 | 成人1区2区3区 | 久久久久亚洲av片无码v |