前言

在《大话数据结构》P190 页中有一句话:其实线索二叉树,就等于是把一棵二叉树转变成了一个双向链表。

对于这句话实在想不懂,线索二叉树只是把二叉树以某种次序遍历把空域填上前驱或后继而已,若度为 2 的结点没有多余的指针域用于线索了,那双向链表就断了啊。

李柱明博客:https://www.cnblogs.com/lizhuming/p/15487406.html

线索二叉树的概念

概念:

  • 引入原因:二叉链表中,只能看出左右孩子,而看不出某序遍历的前驱和后继。

  • 线索:指向前驱和后继的指针称为线索。

  • 线索链表:加上线索的二叉链表称为线索链表。

  • 线索二叉树(Threaded Binary Tree):加上线索的二叉树称为线索二叉树。

    • 左域为空则改为前驱。
    • 右域为空则改为后继。
    • 每个节点添加左右 tag,用于标记左右域指针是孩子还是线索。
  • 线索化:对二叉树以某种次序遍历使其变为线索二叉树的过程。

    • 前、中、后序线索二叉树。

线索二叉树的实现

前驱和后继的信息只有在遍历二叉树时才能得到。而在遍历二叉树时便可以线索化。

线索化:

  • 在遍历过程中修改空指针。

  • 空左域为前驱。

  • 空右域为后继。

  • 实际实现:

    • 前、中、后序:正常的中序遍历算法。在遍历过程中,把输出数据部分改为线索化内容,即是修改空指针。

线索二叉树的遍历:

  • 中序:采用非递归方式:

    • 中序遍历算法思路:先找到最左下,再中,再切到右子树找到右子树的最左下,再中,再右...。

      • 简单来说就是:左、中、右。先找最左下。切到右时也要先找右的最左下。
    • 实现步骤:

      1. 找最左下:一直循环找左孩子,直到找到 ltag 为线索的节点。

      2. 找到最左下节点后,输出数据。

      3. 判断该节点是否有后继。

        1. 有:则直接跳到后继节点。输出数据。判断该节点是否有后继(就是重复步骤 3)。(线索)
        2. 无:则切到右孩子,对该右子树做前序遍历。即是找这个右孩子的最左下(重复步骤 1 、2、3)。(孩子)
        3. 提醒:左右域只有两种情况:1. 线索;2. 孩子。

线索二叉树节点:

/* 线索二叉树节点结构 */
typedef int tree_elem_type; /* link_e==0表示指向左右孩子指针, */
/* thread_e==1表示指向前驱或后继的线索 */
typedef enum {link_e, thread_e} pointer_tag_e; typedef struct tree_node
{
struct tree_node *lchild; // 左子域
struct tree_node *rchild; // 右兄域
pointer_tag_e ltag; // 左标志
pointer_tag_e rtag; // 右标志
tree_elem_type data; // 数据
}binary_tree_node_t;

线索化代码参考下面参考代码。

线索二叉树的寻点思路二

以中序线索二叉树为例,令 P 所指节点的某个结点。查找 p 所指结点的后继点的方法:

  1. 若 p->rtag==1,则 p->rchild 指向其后继节。

  2. 若 p->rtag==0,则 p 所指结点的中序后继必然是其右子树中进行中序遍历时得到的第一个结点。也就是 p 的右子树中“最左下”的结点。

    1. 这点可以利用递归。
    2. 也可以参考下面代码的非递归方法。

寻点代码参考下面代码。

类双向链表参考图

参考代码

中序遍历线索化

  • 注意:in_threading(); 函数使用前需要对 pre 节点进行赋有效节点值。
  • 下面为类双向链表线索化和线索遍历参考代码
binary_tree_node_t *pre = NULL; /* 全局变量, 上一访问节点 */

/* 中序遍历进行中序线索化 */
void in_threading(binary_tree_node_t *p)
{
if(p)
{
in_threading(p->lchild); /* 递归左子树线索化 */
if(!p->lchild) /* 没有左孩子 */
{
p->ltag = thread_e; /* 前驱线索 */
p->lchild = pre; /* 左孩子指针指向前驱 */
}
if(!pre->rchild) /* 前驱没有右孩子 */
{
pre->rtag = thread_e; /* 后继线索 */
pre->rchild = p; /* 前驱右孩子指针指向后继(当前结点p) */
}
pre = p; /* 保持pre指向p的前驱 */
in_threading(p->rchild); /* 递归右子树线索化 */
}
} /* 中序遍历二叉树tree,并将其中序线索化,tree_list指向头结点 */
int in_order_threading(binary_tree_node_t **tree_list_p, binary_tree_node_t *tree)
{
*tree_list_p = (binary_tree_node_t *)malloc(sizeof(binary_tree_node_t));
if(!*tree_list_p)
return -1; (*tree_list_p)->ltag = link_e; /* 孩子,用于指根 */
(*tree_list_p)->rtag = thread_e; /* 线索,只最右下。即是链尾 */
(*tree_list_p)->rchild = (*tree_list_p); /* 初始化:右指针回指 */ if(!tree) /* 若二叉树空,则左指针回指 */
(*tree_list_p)->lchild = *tree_list_p;
else
{
(*tree_list_p)->lchild = tree; pre = (*tree_list_p); in_threading(tree); /* 中序遍历进行中序线索化 */ pre->rchild = *tree_list_p; pre->rtag = thread_e; /* 最后一个结点线索化 */ (*tree_list_p)->rchild = pre;
} return 0;
} /* 中序遍历二叉线索树tree(头结点)的非递归算法 */
int in_order_traverse_tree_list(binary_tree_node_t *tree)
{
binary_tree_node_t *p = NULL; p = tree->lchild; /* p指向根结点 */ while(p != tree)
{
/* 找到最左下节点 */
while(p->ltag == link_e)
p = p->lchild; if(!visit(p->data)) /* 访问其左子树为空的结点 */
return -1; /* 判断是否有后继,且不是整个树的最右下节点 */
while(p->rtag == thread_e && p->rchild != tree)
{
p = p->rchild;
visit(p->data); /* 访问后继结点 */
}
p = p->rchild; /* 切换到右子树。然后继续中序遍历该右子树 */
} return -1;
}

【数据结构&算法】12-线索二叉树的更多相关文章

  1. 数据结构算法及应用——二叉树

    一.二叉树性质 特性1 包含n (n> 0 )个元素的二叉树边数为n-1 特性2 二叉树的高度(height)或深度(depth)是指该二叉树的层数(有几层元素,而不是有层的元素间隔) 特性3 ...

  2. 【PHP数据结构】完全二叉树、线索二叉树及树的顺序存储结构

    在上篇文章中,我们学习了二叉树的基本链式结构以及建树和遍历相关的操作.今天我们学习的则是一些二叉树相关的概念以及二叉树的一种变形形式. 完全二叉树 什么叫完全二叉树呢?在说到完全二叉树之前,我们先说另 ...

  3. 【Java】 大话数据结构(9) 树(二叉树、线索二叉树)

    本文根据<大话数据结构>一书,对Java版的二叉树.线索二叉树进行了一定程度的实现. 另: 二叉排序树(二叉搜索树) 平衡二叉树(AVL树) 二叉树的性质 性质1:二叉树第i层上的结点数目 ...

  4. 数据结构《9》----Threaded Binary Tree 线索二叉树

    对于任意一棵节点数为 n 的二叉树,NULL 指针的数目为  n+1 , 线索树就是利用这些 "浪费" 了的指针的数据结构. Definition: "A binary ...

  5. 数据结构之线索二叉树——C语言实现

     线索二叉树操作 (1) 线索二叉树的表示:将每个节点中为空的做指针与右指针分别用于指针节点的前驱和后续,即可得到线索二叉树. (2) 分类:先序线索二叉树,中序线索二叉树,后续线索二叉树 (3) 增 ...

  6. javascript实现数据结构:线索二叉树

    遍历二叉树是按一定的规则将树中的结点排列成一个线性序列,即是对非线性结构的线性化操作.如何找到遍历过程中动态得到的每个结点的直接前驱和直接后继(第一个和最后一个除外)?如何保存这些信息? 设一棵二叉树 ...

  7. 数据结构之---C语言实现线索二叉树

    //线索二叉树,这里在二叉树的基础上增加了线索化 //杨鑫 #include <stdio.h> #include <stdlib.h> typedef char ElemTy ...

  8. 笔试算法题(41):线索二叉树(Threaded Binary Tree)

    议题:线索二叉树(Threaded Binary Tree) 分析: 为除第一个节点外的每个节点添加一个指向其前驱节点的指针,为除最后一个节点外的每个节点添加一个指向其后续节点的指针,通过这些额外的指 ...

  9. 数据结构算法集---C++语言实现

    //数据结构算法集---C++语言实现 //各种类都使用模版设计,可以对各种数据类型操作(整形,字符,浮点) /////////////////////////// // // // 堆栈数据结构 s ...

随机推荐

  1. linux mint 18.1 安装备忘录

    本次全新安装mint18.1,遇到一些问题,全部解决,怕日后忘记,再捣鼓琢磨,浪费时间,特记录在此: 一.楷体字体问题 安装完后的mint18.1,显示都是楷体,经请教薄荷论坛高手,可用以下办法解决: ...

  2. P4258-[WC2016]挑战NPC【带花树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4258 题目大意 给出\(n\)个球,\(m\)个篮筐,每个球都可以被放入一些特定的篮筐,每个球都要放,要求球的个 ...

  3. 面试官问:App测试和Web测试有什么区别?

    WEB 测试和 App 测试从流程上来说,没有区别.都需要经历测试计划方案,用例设计,测试执行,缺陷管理,测试报告等相关活动. 从技术上来说,WEB 测试和 APP 测试其测试类型也基本相似,都需要进 ...

  4. 【C++ Primer Plus】编程练习答案——第4章

    1 void ch4_1() { 2 using namespace std; 3 string fname, lname; 4 char grade; 5 unsigned int age; 6 c ...

  5. 硝烟中的Scrum和XP

    硝烟中的Scrum和XP 初次接触Scrum和XP(更加准确的说是"看到"),心里不免有些疑问,软件开发为什么会有如此多的方式,难道软件开发.软件工程不就是写写代码的事儿吗?直到后 ...

  6. 洛谷3721 HNOI2017单旋(LCT+set+思维)

    这题难道不是spaly裸题吗? 言归正传QWQ 一看到这个题目,其实第一反应是很懵X的 从来没有见过类似的题目啊,什么\(spaly\),单旋.QWQ很懵逼啊 不过,我们可以注意到这么一件事情,就是我 ...

  7. C#开发BIMFACE系列50 Web网页中使用jQuery加载模型与图纸

    BIMFACE二次开发系列目录     [已更新最新开发文章,点击查看详细] 在前一篇博客<C#开发BIMFACE系列49 Web网页集成BIMFACE应用的技术方案>中介绍了目前市场主流 ...

  8. 结对编程——带UI的小初高数学学习软件

    一.简介 本次项目要求: 1.所有功能通过图形化界面操作,可以是桌面应用,可以是网站(编程语言和技术不限): 2.用户注册功能.用户提供手机号码,点击注册将收到一个注册码,用户可使用该注册码完成注册: ...

  9. Kafka消息(存储)格式及索引组织方式

    要深入学习Kafka,理解Kafka的存储机制是非常重要的.本文介绍Kafka存储消息的格式以及数据文件和索引组织方式,以便更好的理解Kafka是如何工作的. Kafka消息存储格式 Kafka为了保 ...

  10. 关于takin-data,你想知道的都在这里(二)trace日志篇

    相信大家在使用takin的过程中都见到过压测过程中实时展示的请求流量明细和请求详情了吧,像这样: 还有这样: 这样的请求流量明细和调用链详情是怎么实现的呢,今天就带大家探究下. 在前面的启动命令篇(h ...