线索二叉树

注意:源码

  • 二叉线索树的概念
    二叉线索树是在传统二叉树结构的基础上,加上判断结点左右孩子是否为空的标志–LTag,RTag。
    当左孩子为空的时候,lchild指向该节点的前驱结点,当右孩子为空的时候,rchild指向该节点后继结点。以此提高链表的储存密度。下面我们给出二叉线索树的结构:
 typedef struct BiTNode{char data;//数据域int LTag = 0;//左标签int RTag = 0;//右标签struct BiTNode* lchild = nullptr;//指针必须初始化,c11标准struct BiTNode* rchild = nullptr;//左右孩子}BiTNode, * BiTree;
  • 二叉线索树相对于一般二叉树的优点
    当以二叉链表作为储存结构,只能找到结点的左右孩子信息,而不能得到结点在任意序列中的前驱和后继信息,这种信息只有在遍历的动态过程中才能得到,而二叉线索树可以保存这些动态过程中的前驱和后继信息。而且由于一般二叉树有n个结点必定存在(n+1)的空链域(容易证得)。因此可以充分利用这些空链域储存前驱和后继信息,提高储存密度。

  • 创建二叉树
    我们以先序遍历创建二叉树,先输入根节点,再创建左子树,在创建右子树(若结点data为#,表示空树)。代码如下:

 void CreateBiTree(BiTree& T,BiTree P)//先序输入 {char ch;cin >> ch;if (ch == '#') T = NULL;else{T = new BiTNode;//分配空间T->data = ch;//根节点赋值T->parent = P;CreateBiTree(T->lchild,T);//建立左子树CreateBiTree(T->rchild,T);//建立右子树}}
  • 先序线索化二叉树
    按照根左右的顺序进行先序线索化,具体流程为:
    首先,我们先创建一个空的BiTree Thrt (一方面用于作为第一个结点的前驱结点,最后一个节点的后继结点,另一方面也可以将二叉树形成一个双向链表,既可以从第一个结点起顺后继进行遍历,也可以从最后一个结点起顺前驱进行遍历,非常方便-^- ^-),创建一个BiTree pre 始终指向刚刚访问过的结点。
    其次,我们先找到根结点,若此结点没有左孩子,我们将lchild指向它的前驱,并将此节点赋给pre。若pre没有右孩子,我们将pre的rchild指向当前节点。
    最后,递归左子树,再递归右子树。
    我们所要遍历的树如下所示:


先序线索化后的二叉树就是这个样子(有点丑 -^- ^- ):

下面附上代码(pre是一个BiTree类型的全局变量,如果不要带头结点的线索树,就将第一个最左面的结点的lchild置空,之后pre指向此节点):

//以结点T为根的子树先序线索化
void PreThreading(BiTree& T)
{if (T)//T非空{if (!T->lchild)//左子树为空{T->LTag = 1;T->lchild = pre;//指向前驱结点}else{T->LTag = 0;}if (!pre->rchild){pre->RTag = 1;pre->rchild = T;//指向后继结点}else{T->RTag = 0;}pre = T;//pre指向当前节点if (T->LTag == 0)//这点很重要,只有结点有左孩子的时候才可以遍历左子树,否则会陷入死循环{PreThreading(T->lchild);//遍历左子树}if (T->RTag == 0)//同上{PreThreading(T->rchild);//遍历右子树}}
}
//以结点T为根的字树先序线索化//带头节点的二叉树先序线索化
void PreOrderThreading(BiTree& Thrt, BiTree T)
{Thrt = new BiTNode;//头节点Thrt->LTag = 0;//左标签为零,表明有左子树Thrt->RTag = 1;Thrt->rchild = Thrt;//右子树指向自己if (!T)//若为空树,右子树指向自己{Thrt->lchild = Thrt;}else{Thrt->lchild = T;//左指针指向Tpre = Thrt;PreThreading(T);//进行线索化pre->rchild = Thrt;//此时pre为最右面的那个节点,让它的右子树为Thrtpre->RTag = 1;Thrt->rchild = pre;//Thrt的右子树为pre,形成闭环}
}
//带头节点的二叉树先序线索化

此时,二叉树的先序线索化就结束了。

  • 中序线索化二叉树
    中序线索化二叉树的步骤和先序二叉树很相似,具体步骤为:
    1.遍历左子树,找到最左面的结点,让他的lchild指向pre,并将pre指向当前节点。
    2.对根节点重复以上步骤。
    3.在遍历右子树。
    下面是中序线索化二叉树的图(图依旧很丑):

    下面附上代码(代码还是那个代码,只不过换了一下顺序):
//以结点T为根的子树中序线索化
void InThreading(BiTree &T)
{if (T)//T非空{InThreading(T->lchild);//遍历左子树if (!T->lchild)//左子树为空{T->LTag = 1;T->lchild = pre;}else{T->LTag = 0;}if (!pre->rchild){pre->RTag = 1;pre->rchild = T;}else{T->RTag = 0;}pre = T;InThreading(T->rchild);//遍历右子树}
}
//以结点T为根的字树中序线索化//带头节点的二叉树中序线索化
void InOrderThreading(BiTree& Thrt, BiTree T)
{Thrt = new BiTNode;Thrt->LTag = 0;Thrt->RTag = 1;Thrt->rchild = Thrt;if (!T){Thrt->lchild = Thrt;}else{Thrt->lchild = T;pre = Thrt;InThreading(T);pre->rchild = Thrt;pre->RTag = 1;Thrt->rchild = pre;}
}
//带头节点的二叉树中序线索化
  • 后序线索化二叉树
    后序线索化二叉树和前面的思路一样:
    1.先遍历左子树,找到最左面的结点,若其lchild为空,这lchild 指向pre,若pre的rchild为空,则pre的rchild指向当前结点。
    2.遍历右子树,进行上面的步骤。
    3.最后再对根节点进行如上操作。
    下面是后序线索化二叉树的图(图还是很丑):

    附上代码:
//以结点T为根的子树后序线索化
void PosThreading(BiTree& T)
{if (T)//T非空{PosThreading(T->lchild);//遍历左子树PosThreading(T->rchild);//遍历右子树if (!T->lchild)//左子树为空{T->LTag = 1;T->lchild = pre;}else{T->LTag = 0;}if (!pre->rchild){pre->RTag = 1;pre->rchild = T;}else{T->RTag = 0;}pre = T;}
}
//以结点T为根的字树后序线索化//带头节点的二叉树后序线索化void PosOrderThreading(BiTree& Thrt, BiTree T){Thrt = new BiTNode;Thrt->LTag = 0;Thrt->RTag = 1;Thrt->rchild = T;if (!T){Thrt->lchild = Thrt;}else{Thrt->lchild = T;pre = Thrt; PosThreading(T);}}//带头节点的二叉树后序线索化

看到这里,二叉线索树的线索化就算结束了,当我们的故事还没有结束(生活不止眼前的线索化,还有二叉树的遍历)。下面我们来谈一谈二叉树线索树 的遍历。

  • 遍历先序线索树
    先序遍历线索树时,首先定义一个BiTree p,指向头节点p 的左子树,即 p = T->child。
    然后,我们要输出p的信息,如果该节点有左子树,便p指向左子树,并输出结点信息,若没有左子树,便p指向右子树,输出信息。
    最后,当p指向T,循环结束。
    下面是先序遍历的图例(动画做的不好):

    下面附上代码(就是如此简单):
 //遍历先序线索二叉树void PreTraverse_Thr(BiTree T){BiTree p = T->lchild;while (p != T){cout << p->data;if (p->LTag == 0){p = p->lchild;}else{p = p->rchild;}}}
//遍历先序线索二叉树
  • 遍历中序线索树
    遍历中序线索树的思路就是按照左根右的思路:
    首先,先找到最左面的结点p,输出节点值。
    然后,若左面的结点的rchild=1,p = p->rchild,输出结点值,循环往复。
    若遍历到根节点p,p = p->rchild。在循环往复,直至p为T结束。
    下面是中序遍历的图例(动画依旧做的不好):

    附上代码(依旧那么简单):
//遍历中序线索二叉树
void InTraverse_Thr(BiTree T)
{BiTree p = T->lchild;//while (p != T){while (p->LTag == 0){p = p->lchild;}cout << p->data;while (p->RTag == 1 && p->rchild != T){p = p->rchild;cout << p->data;}p = p->rchild;}
}
//遍历中序线索二叉树
  • 遍历后序线索树
    遍历后序线索树有点难搞呀。原先的二叉树结构需要做一下改动,我们要为每个结点添加父节点,以解决当遍历到右子树时无法访问父节点。
    代码如下:
 typedef struct BiTNode{char data;//数据域int LTag = 0;//左标签int RTag = 0;//右标签struct BiTNode* lchild = nullptr;//指针必须初始化,c11标准struct BiTNode* rchild = nullptr;//左右孩子struct BiTNode* parent = nullptr;//双亲}BiTNode, * BiTree;

有了上面的结构,后序遍历线索树就简单多了。
1.首先我们应该像中序遍历一样,先找到最左面的结点p,输出节点的值,若p->rchild == 1;p = p->rchild,输出节点的值,一直循环往复,直到p->lchild == 0 并且 p->rchild == 0。
2.此时p为根节点(相对来说),我们需要靠双亲结点继续遍历,并输出节点的值。直到我们找到真正的根节点p,此时p = p->rchild。
3.重复1,2步骤,直到p的双亲结点为空。
演示图列:

附上代码(这次不简单哦):

//后序遍历需要双亲节点
void PosTraverse_Thr(BiTree T)
{BiTree root = T->lchild;//初始节点BiTree prev = nullptr;//记录上一个节点while (root){if (root->lchild == root->rchild)//如果双亲没有左子树或者右子树{root = root->rchild;}while (root->LTag == 0 && root->lchild != prev)//找到最左边的节点{root = root->lchild;}while (root->RTag == 1)//输出并遍历节点的后继{cout << root->data;prev = root;//记录上一个节点root = root->rchild;}if (root == T->lchild)//判断是不是根节点{cout << root->data;return;}while (root->rchild == prev)//不是根节点,访问当前节点的双亲节点{cout << root->data;prev = root;root = root->parent;if (root == nullptr)//遍历到根节点,退出{return;}}if (root->RTag == 0)//遍历右子树{root = root->rchild;}}
}
//遍历后序线索二叉树

二叉线索树的先序、中序、后序的线索化及其遍历相关推荐

  1. 线索树找*p的中序后继且中序遍历 二叉线索树

    //线索树找*p的中序后继且中序遍历 二叉线索树 #define thread 1 #define link 0 typedef struct Bt{char data;struct Bt *lc;/ ...

  2. “后序遍历二叉运算树进行Lambda演算的化简”带来的联系

    今天闲来无事,想到一个自以为绝妙的想法,那就是用后序遍历二叉树Lambda演算的化简. 数据结构与算法中,我们想写个计算器就必须遇到一个问题,表达式求值!其实表达式很多就是我们所谓的现实生活中的问题解 ...

  3. 已知一棵二叉树的中序序列和后序序列,写一个建立该二叉树的二叉链表存储结构的算法...

    已知一棵二叉树的中序序列和后序序列,写一个建立该二叉树的二叉链表存储结构的算法 #define N 10 //二叉树节点的个数 char postorderstr[]={};//后序序列 char i ...

  4. 数据结构学习记录(二)——折半查找二叉判定树的画法

    以下给出我在学习中总结的一种比较简便的构造折半二叉判定树的思路以及方法: 思路分析: 在计算mid值时,使用的时mid=(low+high)/2  .这里由于mid为int类型,自动默认为向下取整,因 ...

  5. 【CVPR2020-中科院-腾讯优图】基于注意力卷积二叉神经树的细粒度视觉分类

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 本文由腾讯优图实验室和中科院软件所联合提出.细粒度视觉分类(Fine-Graine ...

  6. 下拉菜单实现树状结构_二叉索引树(树状数组)的原理

    背景 了解到二叉索引树这个数据结构,是在 leetcode 的 307 题,题目是要求实现一个数据结构,可以返回数组任意区间的和以及更新数组的某个值. 307.Range Sum Query - Mu ...

  7. 树形结构:二叉排列树,二叉搜索树

    二叉排列树,二叉搜索树 这个数听见得比较多,含义是:左边<=中间<=右边,换句话来说使用中序遍历最后得到结果就是一个有序得序列. 建立一颗二叉排列树 class BinTNode:def ...

  8. 1597. 根据中缀表达式构造二叉表达式树 双端队列

    1597. 根据中缀表达式构造二叉表达式树 给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时 ...

  9. 统计学习方法第五章作业:ID3/C4.5算法分类决策树、平方误差二叉回归树代码实现

    ID3/C4.5算法分类决策树 import numpy as np import math class Node:def __init__(self,feature_index=None,value ...

  10. 二叉索引树 -- 区间信息的维护与查询

    二叉索引树,俗称树状数组,也叫Fenwick树. 例: 给定一个n个元素的数组A1, A2, A3, --, An, 设计一个数据结构,支持以下两种操作. 1.Add  x  y       :让Ax ...

最新文章

  1. 继python(银行转账)简单Model修改版(二)
  2. Util应用程序框架公共操作类(八):Lambda表达式公共操作类(二)
  3. 在GitHub上管理项目
  4. #翻译NO.5# --- Spring Integration Framework
  5. Hadoop的HA机制
  6. 直击Kafka的心脏——控制器
  7. Enum in C#
  8. elementUI-添加自定义图标
  9. Hyperledger Fabric 1.0 从零开始(七)——启动Fabric多节点集群
  10. realvnc 6 教程 linux,CentOS 6下VNC的安装与配置
  11. android textview设置大小,android – 如何缩放/调整文本大小以适应TextView?
  12. 手机版q群管机器人_手机QQ机器人怎么用,QQ机器人手机版怎么设置
  13. 基于改进的CASA模型反演NPP
  14. e会学c语言程序设计基础网课答案,C程序设计(双语版)习题答案
  15. 5G牌照都发完了,那些传说中的5G手机Ready了吗?
  16. python3实用小工具--商品库存查看工具(附源码)
  17. 心得-计算机软考之嵌入式系统工程师
  18. MB/T 2020/4/9-技术创新方法·概述
  19. 《第一行代码》阅读记录—Git和Notification
  20. html5 视口,HTML5样板:元视口和宽度=设备宽度(HTML5 Boilerplate: Meta viewpo

热门文章

  1. k8s核心技术-集群安全机制(RBAC实现鉴权)---K8S_Google工作笔记0040
  2. oracle在日本遇到的技术问题
  3. 2015年4月7号的日志
  4. 成功在家用ssh远程连上了学校电脑虚拟机当中的ubuntu(代价是虚拟机全部黑屏只能用SSH连接了!)
  5. python编程(redis操作)
  6. mysql rpm server_记录一次最新版MySQL-server-5.6.20-1.el6.x86_64.rpm的安装
  7. idea json格式化插件_IDEA常用插件
  8. sqlerver 字符串转整型_sqlerver2005(2)
  9. polybase配置 sql_安装SQL Server 2016时提示“Polybase要求安装Oracle JRE 7更新51或更高版本”错误的解决方式...
  10. fetch jsonp连接mysql_fetch跨域浏览器请求头待研究