后序线索二叉树怎么画 线索二叉树基本操作详解

发布时间:2017-05-23

来源:服务器之家

遍历二叉树是以一定规则将二叉树中结点排列成一个线性序列,得到二叉树中结点的先序,中序或后序序列。这实际上是对一个非线性结构进行线性化操作,使每个结点(除第一个和最后一个外)在这些线性序列中有且仅有一个直接前驱和直接后继。但是,当以二叉链表作为存储结构时,只能找到结点的左,右孩子的信息,而不能直接得到结点在任一序列中的前驱和后继信息,这种信息只能在遍历的动态过程中才能得到。

因为在有n个结点的二叉链表中必定存在n+1个空链域,故可以利用这些空链域来存放结点的前驱和后继信息。

试做如下规定:若结点有左子树,则其lchild域指示其左孩子,否则令lchild域指示其前驱;若结点有右子树,则其rchild域指示其右孩子,否则令rchild域指示其后继。为了避免混淆,需要改变结点结构,增加两个标志域:LTag,RTag。

其中:LTag = 0,lchild域指示其左孩子;  LTag = 1,lchild域指示其前驱。

RTag = 0,rchild域指示其右孩子;  RTag = 1,rchild域指示其后继。

以这种结点组成的二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点前驱和后继的指针,叫做线索。加上线索的二叉树叫做线索二叉树。对二叉树以某种次序遍历使其变成线索二叉树的过程叫做线索化。

在线索二叉树上进行遍历,只要先找到序列中的第一个结点,然后依次找结点后继直到其后继为空为止;当然也可以找结点的前驱,进行逆序遍历。

求各种次序线索树非叶子结点的前驱和后继的方法:

前序线索树非叶子结点p的前驱:p的双亲结点;

前序线索树非叶子结点p的后继:若p有左孩子,则后继为其左孩子,否则后继是其右孩子。

后序线索树非叶子结点p的前驱:若p有右孩子,则后继为其右孩子;否则后继是其左孩子。

后序线索树非叶子结点p的后继:若p为根结点,则其后继为空;若p为其双亲结点的右孩子,或p为左孩子且其双亲结点无右孩子,则p的后继为其双亲结点;

若p为左孩子,且其双亲结点有右孩子,则其后继为双亲结点右子树的第一个结点(最左边结点)。

中序线索树非叶子结点p的前驱:左子树的最后一个结点(最右边的结点)。

中序线索树非叶子结点p的后继:右子树的第一个结点(最左边结点)。

前序线索树的后继很好找,但前驱是双亲结点,不便查找;虽然中序线索树前驱和后继都不是直接指向,但不需要求双亲,查找还是比较方便的;后序线索树的前驱很好找,但是后继需要分类讨论,情况复杂,而且需要求双亲。综合考虑,中序线索树是最佳的选择。

为了方便起见,我们仿照线性表的存储结构,在二叉树的线索链表上也添加一个头结点,并令其lchild域的指针指向二叉树的根结点,其rchild域的指针指向中序遍历时访问的最后一个结点;反之,令二叉树中序序列的第一个结点的lchild域的指针和最后一个结点的rchild域的指针均指向头结点。这好比为二叉树建立了一个双向线索链表,既可以从第一个结点起顺后继进行遍历,也可以从最后一个结点起顺前驱进行遍历。

我们先来分析如何将一颗普通二叉树改造成线索二叉树。因为普通二叉树没有头结点,故我们需要先创建一个头结点,然后对原二叉树做中序线索化处理。

/*

函数名称:InOrderThreading

函数功能:创建头结点,并将二叉树改造成中序线索树

输入变量:BiThrTreeT:指向原二叉树根结点的指针

输出变量:BiThrTree:指向中序线索树头结点的指针

*/

BiThrTree InOrderThreading(BiThrTree T)//创建头结点,并将二叉树改造成中序线索树

{

BiThrTreeThrt, pre;

Thrt= (BiThrTree)malloc(sizeof(BiThrNode)); //建立头结点

if(!Thrt)

{

printf("Outof space!");

exit(0);

}

Thrt->LTag= Link;

Thrt->RTag= Thread;

Thrt->rchild= Thrt; //右指针回指

if(! T)//若二叉树为空,则左指针回指

{

Thrt->lchild= Thrt;

}

else

{

Thrt->lchild= T;

pre = Thrt;

InThreading_2(&T, &pre);//中序线索化

pre->rchild = Thrt; //最后一个结点线索化,此时pre指向最后一个结点

pre->RTag = Thread;

Thrt->rchild = pre;

}

returnThrt;

}

中序线索化二叉树和中序遍历二叉树算法非常相似,也有递归和非递归有两种算法。代码如下。

/*

函数名称:InThreading_1

函数功能:中序遍历二叉树,并将其中序线索化(递归算法)

输入变量:BiThrTree*p:指向二叉树当前结点指针的指针

BiThrTree *pre:指向二叉树树当前结点的前驱结点指针的指针

输出变量:无

*/

void InThreading_1(BiThrTree *p, BiThrTree*pre)

{

if(*p != NULL)

{

InThreading(&(*p)->lchild,pre); //左子树线索化

if((*p)->lchild == NULL) //若当前结点的左子树为空,则建立前驱线索

{

(*p)->LTag= Thread;

(*p)->lchild= (*pre);

}

else

{

(*p)->LTag= Link;

}

if(*pre != NULL && (*pre)->rchild == NULL) //若前驱结点的右子树为空,则建立后继线索

{

(*pre)->RTag= Thread;

(*pre)->rchild= *p;

}

*pre= *p;    //中序遍历结点,保持pre指向p的前驱

(*pre)->RTag = Link;//默认前驱结点右孩子非空

InThreading(&(*p)->rchild, pre); //右子树线索化

}

}

/*

函数名称:InThreading_2

函数功能:中序遍历二叉树,并将其中序线索化(非递归算法)

输入变量:BiThrTree*p:指向二叉树当前结点指针的指针

BiThrTree *pre:指向二叉树树当前结点的前驱结点指针的指针

输出变量:无

*/

void InThreading_2(BiThrTree *root,BiThrTree *pre) //中序遍历二叉树,并将其中序线索化(非递归算法)

{

BiThrTreestack[MAXSIZE];

BiThrTreep = *root;

inttop = -1;

while(p != NULL || top >= 0)

{

if(p != NULL) //先处理左子树

{

stack[++top]= p;

p= p->lchild;

}

else

{

p= stack[top--];

//线索化当前结点及其前驱结点

if(*pre != NULL && (*pre)->rchild == NULL)

{

(*pre)->RTag= Thread;

(*pre)->rchild= p;

}

if(p->lchild == NULL)

{

p->LTag= Thread;

p->lchild= *pre;

}

else

{

p->LTag= Link;

}

*pre= p;

p= p->rchild; //线索化其右子树

}

}

}

接下来我们讨论遍历中序线索树的算法。要想遍历中序线索树,必须先根据其特征,设计一个能返回结点前驱或后继的函数。

/*

函数名称:Successor

函数功能:返回结点p的后继

输入变量:BiThrTreep:指向中序线索树结点的指针

输出变量:BiThrTree: 指向结点后继的指针

若结点无右孩子,则由后继线索直接得到后继结点;否则后继为右子树的第一个结点(最左边结点)。

*/

BiThrTree Successor(BiThrTree p)

{

if(p->RTag == Thread) //由后继线索直接得到

returnp->rchild;

//后继为右子树的第一个结点(最左边结点)

p= p->rchild;

while(p->LTag == Link)

{

p= p->lchild;

}

returnp;

}

/*

函数名称:Precursor

函数功能:返回结点p的前驱

输入变量:BiThrTreep:指向中序线索树结点的指针

输出变量:BiThrTree: 指向结点前驱的指针。

若结点无左孩子,则由前驱线索直接得到前驱结点;否则前驱为左子树的最后一个结点(最右边结点)。

*/

BiThrTree Precursor(BiThrTree p)

{

if(p->LTag == Thread) //由前驱线索直接得到

returnp->lchild;

//前驱为左子树的最后一个结点(最右边结点)

p= p->lchild;

while(p->RTag == Link)

{

p= p->rchild;

}

returnp;

}

顺序遍历中序线索树,需要先找到第一个结点,即最左边的结点,然后顺序访问其后继即可。

/*

函数名称:InOrderTraverse_Thr

函数功能:顺序遍历中序线索树

输入变量:BiThrTreeT:指向中序线索树头结点的指针

输出变量:无

*/

void InOrderTraverse_Thr(BiThrTree T)

{

BiThrTreep = T->lchild;

while(p->LTag == Link) //先找到第一个结点(最左边结点)

{

p= p->lchild;

}

while(p != T)

{

printf("%c", p->data);

p= Successor(p);//返回结点p的后继

}

}

因为线索树的头结点的右指针指向最后一个结点,所以逆序遍历中序线索树比顺序遍历要来的方便。

/*

函数名称:ReInOrderTraverse_Thr

函数功能:逆序遍历中序线索树

输入变量:BiThrTreeT:指向中序线索树头结点的指针

输出变量:无

*/

void ReInOrderTraverse_Thr_1(BiThrTree T)

{

BiThrTreep = T->rchild; //p指向最后一个结点

while(p != T)

{

printf("%c", p->data);

p= Precursor(p);//返回结点p的前驱

}

}

《大话数据结构》中提供了一个顺序遍历中序线索树的函数,思路很清晰,代码页也很简洁,在这里和大家分享一下。

/*

函数名称:InOrderTraverse_Thr_1

函数功能:顺序遍历中序线索树

输入变量:BiThrTreeT:指向中序线索树头结点的指针

输出变量:无

*/

void InOrderTraverse_Thr_1(BiThrTree T)

{

BiThrTreep = T->lchild;

while(p != T)

{

while(p->LTag == Link) //寻找第一个结点(最左边的结点)

{

p= p->lchild;

}

printf("%c", p->data);

while(p->RTag == Thread && p->rchild != T) //访问直接后续结点(直接由右指针指向)

{

p= p->rchild;

printf("%c", p->data);

}

p= p->rchild; //访问右子树

}

}

到这里,中序线索树的基本操作就介绍完了,大家可以尝试设计在中序线索树中插入新结点或删除结点的函数,其操作和循环双链表差不多,请试试看吧。

二叉树前序中序后续线索树_后序线索二叉树怎么画 线索二叉树基本操作详解 - 办公软件 - 服务器之家...相关推荐

  1. 中序线索树和后序线索树

    约定 Node* Bool Data Bool Node* lchild LTag data RTag rchild LTag=0 时lchild指向左儿子: LTag=1 时lchild指向前驱: ...

  2. 《剑指offer》-- 从上往下打印二叉树、二叉搜素树的后序遍历、二叉树中和为某一值的路径、二叉树与双向链表

    一.从上往下打印二叉树: 1.题目: 上往下打印出二叉树的每个节点,同层节点从左至右打印. 2.解题思路: 用arraylist模拟一个队列来存储相应的TreeNode. 3.代码实现: public ...

  3. linux中python编译器的配置_方舟编译器环境配置及源码编译过程详解

    1)首先将方舟编译器源代码包下载到本地. https://www.openarkcompiler.cn/download/OpenArkCompiler-0.2.tar.gz 2)Ubuntu系统中方 ...

  4. 二叉线索树的先序、中序、后序的线索化及其遍历

    线索二叉树 注意:源码 二叉线索树的概念 二叉线索树是在传统二叉树结构的基础上,加上判断结点左右孩子是否为空的标志–LTag,RTag. 当左孩子为空的时候,lchild指向该节点的前驱结点,当右孩子 ...

  5. 二叉树前序遍历python输出_[宜配屋]听图阁 - Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例...

    本文实例讲述了Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作.分享给大家供大家参考,具体如下: 实现一个功能: 输入:一颗二叉树的先序和中序遍历 输出:后续遍历 思想: 先序遍历中,第 ...

  6. 二叉树前序中序,后序中序,公共最近祖先的实现

    二叉树前序中序,后序中序,公共最近祖先的实现 注释中详细介绍了算法,故不再赘述. 无论是前序还是后序,一个节点的左子树和右子树都是可以看做是分开的,有一定规律可循,故可用递归进行实现. #includ ...

  7. 二叉树前序,中序转后序

    由二叉树的前序和中序如何得到二叉树的后序呢?要给出答案,首先得明白什么是前序.中序.后序. 二叉树前序:遍历顺序为,根节点.左子树.右子树:中序:遍历顺序为,左子树.根节点.右子树:后序:遍历顺序为, ...

  8. 二叉树 ---- 前序 中序 后序 知二求一

    二叉树 ---- 前序 中序 后序 知二求一 先说一下什么是二叉树的前中后序; 根:根节点 左代表遍历左子树 右代表遍历右子树 前序:根-左---右 中序:左-根---右 后序:左-右---根 如图求 ...

  9. 二叉树前序中序后序及其推理

    二叉书的前中后序遍历顺序. 以下面这个图为例: 前序遍历为:1 2 4 7 3 5 6 8 后序遍历为:7 4 2 5 8 6 3 1 中序遍历为:4 7 2 1 5 3 8 6 规则很简单就是:前序 ...

最新文章

  1. %@ INCLUDE FILE=%与JSP:INCLUDE PAGE=/区别
  2. error while loading shared libraries的解決方法
  3. Netty学习笔记(六)Pipeline的传播机制
  4. 忽视大小写函数_使用率低但功能强大的6个Excel函数公式应用技巧解读!
  5. 【python接口自动化-requests库】【三】优化重构requests方法
  6. 开发自己的PHP MVC框架(一)
  7. C++ 输入和输出IO
  8. 字符编码(一):序言
  9. spring-第二篇ApplicationContext国际化及事件机制
  10. 新安装的mysql设置密码
  11. 镇魂街武神躯怎么修改服务器,镇魂街武神躯怎么重置守护灵_守护灵重置方法_3DM手游...
  12. hp服务器bios检测硬盘接口,惠普bios硬盘设置图解
  13. Oracle 18c新特性一览
  14. win10怎么录制电脑屏幕 电脑录制视频
  15. 《大型网站技术架构-核心原理与案例分析》(李智慧 著)第1章-大型网站架构演化
  16. wpa_supplicant、hostapd编译
  17. iOS 直播专题1-直播流程原理
  18. 计算机常见故障维修方法,电脑常见故障,手把手教你电脑故障维修技巧
  19. 在线工作计划安排日历表工具
  20. 旷视创始人印奇被司机敲诈300万元未遂:“我有公司敏感信息录音”

热门文章

  1. 电脑d盘不见了怎么恢复?详细步骤在这
  2. 免疫力低吃nmn有用吗,nmn提高免疫力效果如何,掌握健康!
  3. 卡巴斯基将瑞星卡卡当病毒查杀 瑞星表示不解
  4. QQ游戏: 四国军棋和中国象棋客户端失败
  5. Moss 2007 入门
  6. 有哪些靠谱的域名注册平台
  7. Python-csv文件打开、csv文件保存和csv文件删除行信息
  8. ES6转码工具的安装
  9. 小项目分享:51单片机音乐喷泉制作全过程资料(附送给初学者的忠告)
  10. 网站被新网温馨提示 链接地址含有违规内容无法访问的解决