前言

在《大话数据结构》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. 深入浅出WPF-11.Template(模板)02

    模板 DataTemplate和ControlTemplate的关系 通过上面的内容,控件只是一个数据和行为的载体,是一个抽象的概念,至于它长什么样子,或者它的数据是怎么展示的,都是由模板生成的.决定 ...

  2. JVM-直接内存(Direct Memory)

    1.直接内存概述 直接内存不是虚拟机运行时数据区的一部分,也不是<Java虚拟机规范>中定义的内存区域. 直接内存是在Java堆外的,直接向系统申请的内存区间. 来源于NIO,通过存在堆中 ...

  3. 跳表--怎么让一个有序链表能够进行"二分"查找?

    对于一个有序数组,如果要查找其中的一个数,我们可以使用二分查找(Binary Search)算法,将它的时间复杂度降低为O(logn).那查找一个有序链表,有没有办法将其时间复杂度也降低为O(logn ...

  4. CQOI2021 退役记

    Day -1 晚上去了酒店然后就睡觉了. Day 1 进考场之前互相奶. 进了考场之后看题,发现T1很水(伏笔1,然后直接开始写 \(\Theta(n\log^2n)\)(二分+动态开点线段树),调了 ...

  5. python中冒泡排序代码实现

    1.冒泡排序代码如下图: #冒泡算法l=[12,4,56,10,6,2]for i in range(0,6): for j in range(i+1,6): if l[i]>l[j]: a=l ...

  6. PAT (Basic Level) Practice (中文)1022 D进制的A+B (20分)

    1022 D进制的A+B (20分) 输入两个非负 10 进制整数 A 和 B ( ≤ 2​30​​ −1),输出 A+B 的 D (1<D≤10)进制数. 输入格式: 输入在一行中依次给出 3 ...

  7. NXOpen.CAM.CAMSetup.CopyObjects的使用

    复制CAM对象 Public Function CopyObjects(ByVal view As NXOpen.CAM.CAMSetup.View, ByVal objectsToBeMoved() ...

  8. g++ 常用命令

    g++ --help

  9. git 修改最后一次提交

    git 修改最后一次提交 有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了. 此时,可以运行带有 --amend 选项的提交命令来重新提交:git commit --amend -m ...

  10. python socket zmq

    本篇博客将介绍zmq应答模式,所谓应答模式,就是一问一答,规则有这么几条 1. 必须先提问,后回答 2. 对于一个提问,只能回答一次 3. 在没有收到回答前不能再次提问 上代码,服务端: #codin ...