二叉树的线索化
线索二叉树

6.4 线索化二叉树从前面的讨论可知,遍历二叉树就是将非线性结构的二叉树线性化,即按一定规则将二叉树中的结点排列成一个线性序列依次访问。
如图6.20(a)所示的二叉树,经中序遍历得到线性序列:BADEC,经前序遍历得到线性序列:ABCDE,经后序遍历得到线性序列:BEDCA。
在这些线性序列中,二叉树中的每个结点(除第一个和最后一个外)有且仅有唯一的一个前趋和唯一的一个后继,很容易找到各个结点的直接前驱和直接后继。
但当以二叉链表作为二叉树的存储结构时,只能找到结点的左、右孩子,而不能直接找到前驱和后继,只有在遍历的动态过程中得到这些信息。
如果将这些信息在第一次遍历时保存起来,在需要再次对二叉树进行“遍历”时就可以将二叉树视为线性结构进行访问,从而简化遍历操作。
那么,如何存储遍历中得到的结点前驱和后继的信息呢?一个简单的办法是在每个结点上增加两个指针域fwd和bkwd,分别指向存储遍历中得到的结点前驱和后继。
fwd L child data R child bkwd这是采用多重链表来表示二叉树。
这种方法虽简单易行,但这种结构的存储密度将大大降低,浪费存储空间。
另一种方法,是利用原有链域L child 和R child的空链域。
在n个结点的二叉链表中有2n个孩子链域,其中仅有n-1个链域是用来指示结点的左右孩子,而另外n+1个链域是空链域。
现在把这些空链域利用起来,使其指向结点的前驱或后继;对那些原来就不为空的链域,则仍然指向左或右孩子。
如果把指向前驱和后继的指针称为线索(Thread),那么,如何区分指向左、右孩子的指针和指向前驱、后继的线索呢?在原结点结构上增加标志域定义为:0 Lchild为左指针,指向左孩子0 Rchild为右指针,指向右孩子ltag=rtag=1 Lchild为左线索,指向前驱 1 Rchild为右线索,指向后继以这种结点构成的二叉链表作为二叉树的存储结构,叫做线索链表,其C语言类型说明如下:Typedef struct ThreadTNode{enum{0,1} ltag, rtag;Elem Type data;Struct ThreadTNode *Lchild, *Rchild;}ThreadTNode, *ThreadTree;为了节省内存空间,我们用C语言的位段方法将结点中的左标志域和右标志域与数据域合并在一个存储单元中(即各用一位表示左标志和右标志,其余各位表示结点值)。
实验8 线索二叉树的创建和遍历

实验八线索二叉树的创建和遍历1.实验目的(1)掌握二叉树的线索链表存储结构。
(2)能够实现二叉树的线索链表的创建、遍历等基本操作。
2.实验内容编程实现二叉树的线索链表存储表示的基本操作,包括线索二叉树的创建与遍历。
3.实验要求(1)根据实验内容编写程序,上机调试并获得运行结果(2)撰写实验报告4.准备工作本次实验将会构造此二叉树,并会对此二叉树进行遍历5.关键步骤与算法(1)构造线索二叉树算法步骤;若某节点的左孩子节点指针域(lchild)为空,就可以利用它来指出该节点在某种遍历序列中的直接前驱的存储地址;若某节点的右孩子指针域(rchild)为空,就可以利用它来指出该节点在某种遍历序列中的直接后继的存储地址。
那些非空的指针域仍存放指向该节点左、右孩子节点的指针域。
这样,就得到了一棵线索二叉树。
算法如下;1.//按先序遍历序列输入树中各节点的值,构造线索二叉树2.BiThrTree* CreateBiThrTree()3.{4. BiThrTree *s;5. DataType ch;6. scanf("%c",&ch);7.8.if(ch == '#')9. exit(0);10.if(ch == '@')11. s = NULL;12.else if (ch=='\n')13. getchar();14.15.else16. {17. s = (BiThrTree *)malloc(sizeof(BiThrTree));18.if(!s)19. exit(ERROR);20. s->data = ch;21. s->lflag = 0;22. s->rflag = 0;23. s->lchild = CreateBiThrTree();24. s->rchild = CreateBiThrTree();25. }26.return s;27.}(2) 将二叉树中序线索化现将树递归到左子树然后再判断这个树的左右子树是否为空,如果为空则把它们的标志设为1,代表线索,首先设一个current代表前驱结点,然后判断它是否为空,如果为空则进行下一次递归,如果不为空,则判断左标志和右标志如果左标志为线索,则让前驱节点的右孩子指向当前节点,如果右标志为1,则让当前节点的左孩子指向前驱结点算法如下;1.void InThreading(BiThrTree *t)2.{3.if(t != NULL)//先判断树为不为空,如果为空,则不执行函数4. {5. InThreading(t->lchild);//递归调用左子树进行线索化6.if(t->lchild == NULL)7. t->lflag = 1;8.if(t->rchild == NULL)9. t->rflag = 1;10.//以上两步是判断这个结点的左右结点是否为空,若为空,把他们对应的flag标上111.if(current != NULL)//因为要用到current所以要判断一下,且current只有当t回到倒数第二个结点时,才会不为NULL12. {13.if(current->rflag == 1)14. current->rchild = t;//前驱结点的右孩子指针指向当前节点t15.if(t->lflag == 1)16. t->lchild = current;//现结点t的左孩子指针指向前驱结点17. }18. current = t;//让前驱结点为t为下一次执行函数做准备19. InThreading(t->rchild);//递归调用右子树进行线索化20. }21.}6.源代码1.#include<malloc.h>2.#include<stdio.h>3.#include<stdlib.h>4.#include<io.h>5.#define ERROR -16.7.typedef char DataType;8.typedef struct BiThrNode//二叉树的二叉链表的存储结构9.{10. DataType data;11.struct BiThrNode *lchild,*rchild;12.int lflag,rflag;//左右标志,值为0表示指针,值为1表示线索13.}BiThrTree;14.BiThrTree *current = NULL;15.//检查if的==16.//按先序遍历序列输入树中各节点的值,构造线索二叉树17.BiThrTree* CreateBiThrTree()18.{19. BiThrTree *s;20. DataType ch;21. scanf("%c",&ch);22.23.if(ch == '#')24. exit(0);25.if(ch == '@')26. s = NULL;27.else if (ch=='\n')28. getchar();29.30.else31. {32. s = (BiThrTree *)malloc(sizeof(BiThrTree));33.if(!s)34. exit(ERROR);35. s->data = ch;36. s->lflag = 0;37. s->rflag = 0;38. s->lchild = CreateBiThrTree();39. s->rchild = CreateBiThrTree();40. }41.return s;42.}43.//将二叉树前序线索化(递归)44.void PreThreading(BiThrTree *t)45.{46.if(t != NULL)//先判断树为不为空,如果为空,则不执行函数47. {48.if(t->lchild == NULL)49. t->lflag = 1;50.if(t->rchild == NULL)51. t->rflag = 1;52.//以上两步是判断这个结点的左右结点是否为空,若为空,把他们对应的flag标上153.if(current != NULL)//因为要用到current所以要判断一下,且current只有当t回到倒数第二个结点时,才会不为NULL54. {55.if(current->rflag == 1)56. current->rchild = t;//前驱结点的右孩子指针指向当前节点t57.if(t->lflag == 1)58. t->lchild = current;//现结点t的左孩子指针指向前驱结点59. }60. current = t;//让前驱结点为t为下一次执行函数做准备61.if(t->lflag == 0)62. PreThreading(t->lchild);//递归调用右子树进行线索化63.if(t->rflag == 0)64. PreThreading(t->rchild);65. }66.}67.//遍历前序线索二叉树68.void PreVisitThrtree(BiThrTree *t)69.{70.while(t != NULL)//大循环71. {72.while(t->lflag == 0)73. {74. printf("%c\t",t->data);75. t = t->lchild;76. }77. printf("%c\t",t->data);78. t = t->rchild;79. }80.}81.82.//检查if的==83.//将二叉树中序线索化(递归)84.void InThreading(BiThrTree *t)85.{86.if(t != NULL)//先判断树为不为空,如果为空,则不执行函数87. {88. InThreading(t->lchild);//递归调用左子树进行线索化89.if(t->lchild == NULL)90. t->lflag = 1;91.if(t->rchild == NULL)92. t->rflag = 1;93.//以上两步是判断这个结点的左右结点是否为空,若为空,把他们对应的flag标上194.if(current != NULL)//因为要用到current所以要判断一下,且current只有当t回到倒数第二个结点时,才会不为NULL95. {96.if(current->rflag == 1)97. current->rchild = t;//前驱结点的右孩子指针指向当前节点t98.if(t->lflag == 1)99. t->lchild = current;//现结点t的左孩子指针指向前驱结点100. }101. current = t;//让前驱结点为t为下一次执行函数做准备102. InThreading(t->rchild);//递归调用右子树进行线索化103. }104.}105.//检查if的==106.//遍历中序线索二叉树107.void InVisitThrtree(BiThrTree *t)108.{109.while(t != NULL)//大循环110. {111.while(t->lflag == 0)//小循环1;此循环第一次进行时首先要去找到最左节点112. t = t->lchild;113.if(t == NULL)114. exit(ERROR);115. printf("%c\t",t->data);116.while(t->rflag == 1 && t->rchild != NULL)//小循环2117. {118. t = t->rchild;119. printf("%c\t",t->data);120. }121. t = t->rchild;122./*123.两种情况:124. 1.如果t的右子树为空则t直接指向t的中序后继结点.125. 2.如果t的右子树不为空,即t->rflag为0,那么退出这个小循环2回到大循环中,再到小循环1中去找t的右子树的最左下的结点.126. */127. }128.}129.130.//将二叉树后序线索化(递归)131.void PostThreading(BiThrTree *t)132.{133.if(t != NULL)//先判断树为不为空,如果为空,则不执行函数134. {135. PreThreading(t->lchild);136. PreThreading(t->rchild);137.if(t->lchild == NULL)138. t->lflag = 1;139.if(t->rchild == NULL)140. t->rflag = 1;141.//以上两步是判断这个结点的左右结点是否为空,若为空,把他们对应的flag标上1142.if(current != NULL)//因为要用到current所以要判断一下,且current只有当t回到倒数第二个结点时,才会不为NULL143. {144.if(current->rflag == 1)145. current->rchild = t;//前驱结点的右孩子指针指向当前节点t146.if(t->lflag == 1)147. t->lchild = current;//现结点t的左孩子指针指向前驱结点148. }149. current = t;//让前驱结点为t为下一次执行函数做准备150. }151.}152.//遍历后序线索二叉树153.void PostVisitThrtree(BiThrTree *t)154.{155.if(t)156. {157.while(t->lchild != NULL && t->lflag == 0)158. {159. t = t->lchild;//先遍历到最左边的节点160. }161. }162.}163.//主函数164.void main()165.{166. BiThrTree *t,*s;167. printf("\t\t请按先序序列输入二叉树(如:ABC@@DE@G@@F@@@#)\n\t\t");168. t = CreateBiThrTree();169. InThreading(t);170. printf("\t\t按中序遍历输出线索二叉树:\n\t\t");171. InVisitThrtree(t);172. printf("\n");173.//getchar();174.//getchar();175. fflush(stdin);//这个操作必须要进行,或者是进行上面注释的那两步操作,要不然176. printf("\t\t请按先序序列输入二叉树(如:ABC@@DE@G@@F@@@#)\n\t\t");177. s = CreateBiThrTree();178. PreThreading(s);179. printf("\t\t按前序遍历输出线索二叉树:\n\t\t");180. PreVisitThrtree(s);181.}7.测试图8.实验总结然对于这一节,主要是讨论线索二叉树的建立以及遍历,对于二叉树的建立,主要有五个部分构成,分别是data,lchild,rchild,lflag,rflag,而它与二叉树不同的地方就是多了lflag和rflag的判断,当当前节点的左节点为空时一定会指向它的前驱结点,当前驱节点的右节点为空时,让前驱结点的右指针域指向当前节点,这就是线索化,而对于前序中序后序的线索化本质都是一样的。
线索二叉树

遍历 线索 二叉 树非
{
while(p->ltag==0) p=p->left; /*从根往下找到"最左"的结
点,即中序序列的开始结点*/
do
{
递归 算法
printf("%c",p->date);/*访问结点*/
p=succ(p);
}while(p!=NULL); }
返回
}
树
数据结构
在中序遍历线索树过程中,按下述两条 原则即可找到后继结点:
– 1) 如果某结点的右线索标志域为1,说明其 右指针域是线索,这个线索所指的即是该结 点的后继结点;
– 2) 如果某结点的右线索标志为0,则其右指 针域是指向右儿子结点的指针,由此结点的 右儿子结点起按左指针域指针逐结点向左查 找,一直找到左线索标志域为1的结点,即 是该结点的后继结点。
{
中
if(p!=NULL)
序
{ inthread(p->left,pre); /*左子树线索化*/
线
if(p->left==NULL)
索
/*若当前结点的左子树为空,则建立指 向其前趋结点的前趋线索*/
化
{
算
p->ltag=1;
法
p->left=pre; }
else
p->ltag=0树;
if (pre!=NULL && pre->right==NULL)
这种结点类型和相应结点的指针类型定义如 下:
typedef struct tnode {
ElemType data; int ltag,rtag; /*ltag和rtag只能取值为0或1*/ struct tnode *left,*right; }tbtree;
线索二叉树

0 A0 0 B1
0 C0
1 D0
1 E1
1F1
1 G1
(b) root
0
1
ห้องสมุดไป่ตู้
0 A0
0 B1
0 C0
0 A0
0 B1
0 C0
1 D0
1 E1
1F1
1 D0
1 E1
1F1
1 G1
1 G1
(c)
(d)
线索二叉树 b—中序 c—前序 d—后序
一旦建立了某种方式的线索二叉树后,用户程序就可以 像操作双向链表一样操作该线索二叉树。
if(tree->current == tree->root) tree->nextComplete = 1;
}
int EndOfNext(ThreadBiTree *tree) //判断是否已到中序线索二叉树的最后一个结点 { return tree->nextComplete; }
例8-3 编写一个程序,首先建立如图8-10(a)所示的不带头结点的二叉树, 然后中序线索化该二叉树,最后用循环结构输出该中序线索化二叉树各结 点的序列信息。
这种算法设计要求分别设计三个函数: First():定位在第一个结点位置; Next():移动到下一个结点位置; End():是否已经到最后下一个结点位置; 当然,还需要一个根据二叉树构造线索二叉树的函数。
typedef struct { ThreadBiNode *root;
ThreadBiNode *current; int nextComplete; }ThreadBiTree;
规定:当某结点的左指针为空时,令该指针指向按某种方法遍历二叉树时 得到的该结点的前驱结点;当某结点的右指针为空时,令该指针指向按某种 方法遍历二叉树时得到的该结点的后继结点。仅仅这样做会使我们不能区分 左指针指向的结点到底是左孩子结点还是前驱结点,右指针指向的结点到底 是右孩子结点还是后继结点。因此我们再在结点中增加两个线索标志位来区 分这两种情况。
线索二叉树

6·4 线索二叉树1、线索二叉树的结点结构二叉树的遍历本质上是将一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继(第一个结点无前驱,最后一个结点无后继)。
对于二叉树的一个结点,查找其左右子女是方便的,其前驱后继只有在遍历中得到。
为了容易找到前驱和后继,有两种方法。
一是在结点结构中增加向前和向后的指针fwd和bkd,这种方法增加了存储开销,不可取;二是利用二叉树的空链指针。
现将二叉树的结点结构重新定义如下:其中:ltag=0 时ltag=1 时lchild指向前驱;rtag=0 时rchild指向左子女;rtag=1 时rchild指向后继;以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表,指向前驱和后继的指针叫线索,加上线索的二叉树叫线索二叉树,对二叉树进行某种形式遍历使其变为线索二叉树的过程叫线索化。
学习线索化时,有三点必须注意:一是何种“序”的线索化,是先序、中序还是后序;二是要“前驱”线索化、“后继”线索化还是“全”线索化(前驱后继都要);三是只有空指针处才能加线索。
2、对二叉树进行中序线索化的算法bithptr *pre; /* 全程变量*/void INTHREAD(bithptr *p){if(p!=NULL){ INTHREAD(p->lchild); /* 左子树线索化*/if(p->lchild==NULL) { p->ltag=1;p->lchild=pre;}if(p->rchild==NULL) p->rtag=1;if(pre!=NULL && pre->rtag==1) pre->rchild=p;pre=p; /* 前驱指向当前结点*/INTHREAD(p->rchild); /* 右子树线索化*/}3、在线索二叉树上查找前驱和后继(1)中序线索二叉树:若结点的ltag=1,lchild指向其前驱;否则,该结点的前驱是以该结点为根的左子树上按中序遍历的最后一个结点。
线索二叉树

void InThreading(BiThrTree p) { if ( p ) { InThreading ( p -> lchild ); //左子树中序线索化 左子树中序线索化 if ( p->lchild = = NULL ) { p->LTag=Thread; p->lchild= pre; } //左线索为 ; 左线索为pre 左线索为 if ( pre->rchild == NULL ) { pre->RTag=Thread; pre->rchild= p ;} //后继线索 后继线索 pre = p; //保持 指向 的前驱 保持pre指向 保持 指向p的前驱 InThreading(p -> rchild ); //右子树中序线索化 右子树中序线索化 } }//InThreading
指向该线性序列中的“前驱”和 “后继” 的指针 指针,称作“线索” 线索” 指针 线索
A B C D E F G H K
^B
C^ E^
^D^
包含 “线索” 的存储 结构,称作 “线索链 线索链 表” 与其相应的二叉树, 线索二叉树” 称作 “线索二叉树 线索二叉树中序线索二叉树源自A0 1B
C
NULL
Status InOrderThreading (BiThrTree &Thrt , BiThrTree T ) { //将二叉树 改变为其中序线索二叉树 将二叉树T改变为其中序线索二叉树 if ( !Thrt = (BiThrTree ) malloc (sizeof(BiThrNode))) exit ( OVERFLOW ); Thrt-> LTag = Link ; Thrt ->RTag = Thread; Thrt -> rchild = Thrt; if ( !T ) Thrt -> lchild = Thrt; //空树 空树 else { Thrt -> lchild = T ; pre = Thrt ; InTreading( T ); //中序遍历进行中序线索化 中序遍历进行中序线索化 pre-> rchild = Thrt; pre->RTag= Thread; Thrt -> rchild = pre; } return OK; }
简述二叉树的五种形态

简述二叉树的五种形态二叉树是一种常用的数据结构,它由节点组成,每个节点最多有两个子节点。
根据节点的分布情况,二叉树可以分为五种形态,分别是满二叉树、完全二叉树、平衡二叉树、搜索二叉树和线索二叉树。
一、满二叉树满二叉树是指除了叶子节点外,每个节点都有两个子节点的二叉树。
也就是说,满二叉树的所有层都是满的,并且最后一层的叶子节点都靠左排列。
满二叉树的节点数可以通过公式计算得到,假设树的高度为h,则节点数为2^h - 1。
满二叉树的特点是结构简单,查找速度快。
在满二叉树中,任意两个节点的路径长度都相同。
二、完全二叉树完全二叉树是指除了最后一层之外,其他层都是满的,并且最后一层的叶子节点都靠左排列的二叉树。
完全二叉树的特点是节点数较少,结构相对简单。
完全二叉树通常用数组来表示,因为它的节点之间的关系可以通过数组的下标来表示。
在完全二叉树中,任意一个节点的左子节点的下标为2i,右子节点的下标为2i+1。
三、平衡二叉树平衡二叉树是指左右子树的高度差不超过1的二叉树。
平衡二叉树的特点是查找、插入和删除的时间复杂度都为O(logn),其中n是节点的数量。
平衡二叉树的高度可以通过节点的平衡因子来计算,平衡因子定义为左子树的高度减去右子树的高度。
平衡因子的取值范围为-1、0和1,当平衡因子的绝对值大于1时,需要通过旋转操作来调整树的平衡性。
四、搜索二叉树搜索二叉树,也称为二叉搜索树或排序二叉树,是一种特殊的二叉树。
它的特点是对于树中的任意一个节点,其左子树中的所有节点都小于它,右子树中的所有节点都大于它。
搜索二叉树的中序遍历结果是一个递增的有序序列。
搜索二叉树的特点是可以快速地查找某个节点,时间复杂度为O(logn),其中n是节点的数量。
但是,如果搜索二叉树不平衡,即左子树或右子树过深,则会导致查找的时间复杂度退化为O(n)。
五、线索二叉树线索二叉树是对二叉树进行了优化的数据结构,它通过添加指向前驱和后继节点的线索,使得遍历操作更加高效。
数据结构C语言版_线索二叉树

int InOrderTraverse_Thr(BiThrTree T,int(*Visit)(TElemType))
{
BiThrTree p;
p=T->lchild; // p指向根结点
while(p!=T)
{ // 空树或遍历结束时,p==T
// 空格(字符型)表示空结点
int CreateBiThrTree(BiThrTree *T)
{
TElemType h;
scanf("%c",&h);
if(h==Nil)
*T=NULL;
else
{
*T=(BiThrTree)malloc(sizeof(BiThrNode));
if(!p->lchild) // 没有左孩子
{ Biblioteka p->LTag=Thread; // 前驱线索
p->lchild=pre; // 左孩子指针指向前驱
}
if(!pre->rchild) // 前驱没有右孩子
{
pre->RTag=Thread; // 后继线索
"b为左子树的二叉树)\n");
CreateBiThrTree(&T); // 按先序产生二叉树
InOrderThreading(&H,T); // 中序遍历,并中序线索化二叉树
printf("中序遍历(输出)二叉线索树:\n");
InOrderTraverse_Thr(H,vi); // 中序遍历(输出)二叉线索树
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
二叉树的线索化:
以二叉链表作为存储结构时,只能找到结点的左、右孩子信
息,而不能直接得到结点在任一序列(先序、中序或后序序列)
中的前驱和后继信息,这种信息只有在遍历的动态过程中才能得
到。
为了保存这种在遍历过程中得到的信
息,我们利用二叉链表中的空链域(由于结点没有左子树或右子树),
来存放结点的前驱和后继信息。
作如下规定:
①若结点有左子树,则其lchild 域指示其左孩子,否则令
lchild 域指示其前驱;
②若结点有右子树,则其rchild 域指示其右孩子,否则令
rchild 域指示其后继。
(1)线索链表的结点结构
lchild LTag data RTag rchild
其中: data:数据域;
lchild :左指针域,指向该结点的左孩子;
rchild :右指针域,指向该结点的右孩子;
0lchild域指示结点的左孩子
LTag =
1lchild域指示结点的前驱
0rchild域指示结点的右孩子
RTag =
1rchild域指示结点的后继
请将根据图 1 所示编写一个程序实现构建线索二叉树。
thrt
0 1
bt
0 A 0
0 B 0 0 C 0
1 D 1 0 E 0 1 F 1 1 G 1
1 H 1 0 I 0
1 J 1 1 k 1
图1
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define NULL 0
#define OK 1
#define ERROR 0
typedef enum PointerTag { Link,Thread };//Link==0, 指向孩子; Thread==1, 指向前驱后继 typedef char TElemType;
typedef int Status;
//线索化二叉树的存储结构
typedef struct BiThrNode
{ TElemType data;
struct BiThrNode *lchild,*rchild; // 左孩子与右孩子的指针
PointerTag LTag,RTag; //左右标志域,指示是孩子还是前驱后继
} BiThrNode,*BiThrTree;
//按照先序输入二叉树各个节点,创建原
始二叉树, Status CreateBiTree(BiThrTree&
T) {
#表示空树
char ch;
scanf("%c",&ch);
if('#'==ch) T=NULL;
else
{ T=(BiThrTree )malloc(sizeof(BiThrNode));
if(!T) exit(ERROR);
T->data=ch;
T->LTag=T->RTag=Link;// 建表时初始化都为
CreateBiTree(T->lchild);// 构造左子树CreateBiTree(T->rchild);// 构造右子树Link(
即
0)
}
return OK;
}
BiThrTree pre=NULL; // 定义 pre 为函数 InThreading 的外部变量,使其指向最后一个节点 void InThreading(BiThrTree p); // 函数声明
//中序遍历二叉树,将其线索化,Thrt 指向头结点
Status InOrderThreading(BiThrTree &Thrt,BiThrTree T)
{
Thrt=(BiThrTree)malloc(sizeof(BiThrNode)); // 分配头结点if(!Thrt) exit(ERROR);
//以下三步都是在初始化头结点
Thrt->LTag=Link;// 假设头结点的有右孩子
Thrt->RTag=Thread;// 假设头结点有后继
Thrt->rchild=Thrt;// 暂时使头结点的右指针指向自己
if(!T) Thrt->lchild=Thrt; // 如果树空,就令头结点左指针指向自己
else
{ // 下面先线索头结点
Thrt->lchild=T; // 头结点左指针指向根
pre=Thrt; // 先 pre 指向头指针(也就是根节点的前驱)
//接着线索二叉树
InThreading(T); // 调用函数将T 线索化
//最后线索尾节点
pre->RTag=Thread;// 假设最后一点有后继
pre->rchild=Thrt;// 最后一个点右指针指向头结点
Thrt->rchild=pre;// 头结点的右指针指向最后一个点
}
return OK;
}
//将根为p 的二叉树线索化,千万记住,p 是局部变量,当进入下一次递归时他会屏蔽上一
个p,
//但是上一个p 仍然保留着,等到函数返回时他就又
恢复了上一个
void InThreading(BiThrTree p)
{
p
if(p) // 仅仅当 p 不空时才后继续下面的操作,如果
{ InThreading(p->lchild); // 左子树线索化p 空,那么直接结束,不返回任何值
// 对于当前节点,仅仅处理他与前驱的关系
if(!p->lchild) { p->LTag=Thread; p->lchild=pre; }// 如果当前点左边为空,
指向前驱 if(!pre->rchild) { pre->RTag=Thread; pre->rchild=p; } // 如果上
一点右空,指向后继
pre=p;
InThreading(p->rchild); // 右子树线索化
}
}
//非递归调用,中序线索二叉树 ,T 指向头结点,头结点的 lchild
指向根 Status InOrderTraverse_Thr(BiThrTree T,Status
(*Visit)(TElemType e))
{
BiThrTree p;
p=T->lchild; //p 指向根节点
while(p!=T)
{
while(p->LTag==Link) p=p->lchild; // 一直到最左一个元素
Visit(p->data); // 访问最左
while(p->RTag==Thread&&p->rchild!=T)
{ p=p->rchild;Visit(p->data); } // 如果有后继就访问后继
p=p->rchild; // 没有后继先指向右子树,下一个循环会找到最左子孙
}
return OK;
}
Status Print(TElemType e)
{
printf("%c ",e);
return OK;
}
int main()
{
BiThrTree t=NULL,Thrt=NULL; CreateBiTree(t);// 创建树InOrderThreading(Thrt,t);
InOrderTraverse_Thr(Thrt,Print); return 0;
}。