线索化二叉树

在一些项目中需要频繁的遍历二叉树,但是二叉树的遍历比单链表的遍历复杂多了,并且递归总是会有额外开销。。。

能不能像链表那样方便的快速遍历二叉树呢?

线索化二叉树指的是将二叉树中的结点进行逻辑意义上的“重排列”,使其可以线性的方式访问每一个结点。

二叉树线索化之后每个结点都有一个线性下标,通过这个下标可以快速访问结点,而不需要遍历二叉树。

这个感觉很像组织链表,但是大家要知道组织链表结点之间的先后关系是没有任何逻辑关系的,只是为了插入、删除等操作方便。

那么我们应该怎样线索化二叉树呢?方法有二:

线索化方法1:

利用结点中的空指针域,使其指向后继结点。这也是教科书式的方法,许多教科书都会这么讲。

算法思想:

1.初始化位置指针p = NULL;

2.前序遍历二叉树:

2.1.若p不为空,将p->left指向当前结点,并将p置为NULL;

2.2.若当前结点的左子树为空时,将p指向当前结点。

由以上算法我们可知,线索化的实质就是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历才

能得到,因此线索化的过程即为在遍历的过程中修改空指针的过程。

实现代码如下:

// 通过空指针线索化二叉树
void thread_via_left(BTreeNode* root, BTreeNode** pp)
{// 入口参数合法性检查OKif( (root != NULL) && (pp != NULL) ){// 若pp不为空,将pp->left指向当前结点,并将pp置为NULLif( *pp != NULL ){(*pp)->left = root;*pp = NULL;}// 若当前结点的左子树为空时,将pp指向当前结点if( root->left == NULL ){*pp = root;}// 递归线索化(遍历)左右子树thread_via_left(root->left, pp);thread_via_left(root->right, pp);}
}

既然是前序遍历,首先就得有前序遍历的框架,即1.访问根结点中的数据;2.前序遍历左子树;3.前序遍历右子树。

线索化方法2

利用线性表保存二叉树的遍历顺序。此方法异常简单。

算法思想:(感谢国嵌嵌入式工作者们)

1.初始化顺序表s1;

2.前序遍历二叉树,遍历过程中将当前结点插入顺序表s1。

实现代码如下:

// 通过顺序表线索化二叉树
void thread_via_list(BTreeNode* root, SeqList* list)
{// 入口参数合法性检查OKif( (root != NULL) && (list != NULL) ){// 在顺序表尾部插入顺序表,访问根结点数据SeqList_Insert(list, (SeqListNode*)root, SeqList_Length(list));// 线索化(前序遍历)左子树thread_via_list(root->left, list);// 线索化(前序遍历)右子树thread_via_list(root->right, list);}
}

测试验证代码如下:

int main(int argc, char *argv[])
{// 创建二叉树BTree* tree = BTree_Create();// 定义二叉树结点指针BTreeNode* current = NULL;BTreeNode* p = NULL;// 定义顺序表变量SeqList* list = NULL;// 定义循环变量int i = 0;// 定义二叉树内容struct Node n1 = {{NULL, NULL}, 'A'};struct Node n2 = {{NULL, NULL}, 'B'};struct Node n3 = {{NULL, NULL}, 'C'};struct Node n4 = {{NULL, NULL}, 'D'};struct Node n5 = {{NULL, NULL}, 'E'};struct Node n6 = {{NULL, NULL}, 'F'};// 插入二叉树BTree_Insert(tree, (BTreeNode*)&n1, 0, 0, 0);BTree_Insert(tree, (BTreeNode*)&n2, 0x00, 1, 0);BTree_Insert(tree, (BTreeNode*)&n3, 0x01, 1, 0);BTree_Insert(tree, (BTreeNode*)&n4, 0x00, 2, 0);BTree_Insert(tree, (BTreeNode*)&n5, 0x02, 2, 0);BTree_Insert(tree, (BTreeNode*)&n6, 0x02, 3, 0);// 显示整体二叉树printf("Full Tree: \n");BTree_Display(tree, printf_data, 4, '-');printf("Thread via List:\n");// 验证顺序表线索化二叉树list = SeqList_Create(BTree_Count(tree));thread_via_list(BTree_Root(tree), list);for(i=0; i<SeqList_Length(list); i++){printf("%c, ", ((struct Node*)SeqList_Get(list, i))->v);}printf("\n");// 验证结点空指针线索化二叉树printf("Thread via Left:\n");current = BTree_Root(tree);thread_via_left(current, &p);while( current != NULL ){printf("%c, ", ((struct Node*)current)->v);current = current->left;}printf("\n");// 销毁二叉树BTree_Destroy(tree);return 0;
}

通过上面代码比较发现,利用结点空指针线索化的方法会破坏树的结构,同时,利用结点空指针线索化二叉树之后不能够再恢

复。当然上面的问题可以通过在树结点中加入一个线索化指针而得以解决,然而线索化指针的加入又会浪费内存空间,不够灵

活。链表线索化方法不会破化树的结构,不需要线索化时销毁链表即可;链表线索化方法可以很容易的以任何一种遍历顺序对二

叉树进行线索化 。

有的人会问第一种线索化二叉树是否可以实现其他遍历方法来实现,当然可以,不过由于会破坏二叉树结构,并且不能在复位且

会浪费内存空间,所以不再讲述。

线索化二叉树整体实现代码:线索化二叉树代码C实现

数据结构之线索化二叉树相关推荐

  1. 数据结构2:中序线索化二叉树为什么要通过pre设置后继结点

    在听尚硅谷韩顺平老师课程的时候这个地方没有理解,先把java中序线索化二叉树代码附上: private HeroNode pre = null;//在递归线索化,pre总是保留前一个结点 /**** ...

  2. 数据结构: 线索化二叉树

    public class ThreadedBinaryTreeDemo {public static void main(String[] args) {// 先创建一棵二叉树ThreadedBina ...

  3. 数据结构 - 线索化二叉树(线索化与遍历)

    !!(这里我debug很久才理解过来)** 这里8的前驱为null,所以8的leftType=1,但是6是没有后继的或者说后继为null但是rightType为0(因为后继是在下一个节点来进行连接的, ...

  4. 数据结构-线索化二叉树

    文章目录 1.什么是线索二叉树 2.中序线索化二叉树 2.1 中序线索化二叉树实现 2.2 中序线索化二叉树遍历实现 3.先序线索化二叉树 3.1 先序线索化二叉树实现 3.2 先序线索化二叉树遍历实 ...

  5. 数据结构与算法(java):树-二叉树(二叉查找树(BST)、线索化二叉树、哈夫曼树、平衡二叉树【AVL】、二叉树的前中后序遍历)

    二叉树 1.定义 二叉树 就是度不超过2的树(每个结点最多只有两个子结点).如图 2.特殊二叉树 满二叉树 当二叉树的每一个层的结点树都达到最大值,则这个二叉树就是满二叉树. 完全二叉树 叶结点只能出 ...

  6. node 获取表单数据 为空_程序员:数据结构和算法,中序线索化二叉树

    1.中序线索化二叉树   创建如上的二叉树,线索化二叉树时,根据指定的遍历方式得到的节点的访问顺序,一个节点前面的节点,叫做前驱节点,一个节点后面的节点,叫做后继节点.   线索化二叉树的规则:   ...

  7. Java实现前中后序线索化二叉树以及遍历

    文章目录 一.线索化二叉树的原理 二.构建线索化二叉树 三.代码实现线索二叉树 一.线索化二叉树的原理 在前面介绍二叉树的文章中提到,二叉树可以使用两种存储结构:顺序存储和链式存储,在使用链式存储时, ...

  8. java线索二叉树的实现_JAVA递归实现线索化二叉树

    JAVA递归实现线索化二叉树 基础理论 首先,二叉树递归遍历分为先序遍历.中序遍历和后序遍历. 先序遍历为:根节点+左子树+右子树 中序遍历为:左子树+根节点+右子树 后序遍历为:左子树+右子树+根节 ...

  9. 线索化二叉树,中序建立线索,带线索中序遍历,删除,c/c++描述

      二叉树的叶节点的两个指针都没有利用,一些分支节点也可能有一个指针指向NULL,这些指针造成了程序在内存空间上的浪费,但这些叶节点也必不可省.所以我们可以把这些指向NULL的指针,重新赋值,左指针则 ...

最新文章

  1. shell脚本[] [[]] -n -z 的含义解析
  2. 20150206--JS巩固与加强4-02
  3. 使用循环链表实现一个通讯录的管理程序_【LeetCode链表题型总结】
  4. cnn可视化 感受野(receptive field)可视化
  5. C# combobox SelectedText值为空
  6. java线程间通信 实例_JAVA-初步认识-第十四章-线程间通信-示例
  7. 东南大学微型计算机期末,12级东南大学微机期中试卷
  8. Java 8中用java.time.LocalDate全面代替老旧的Date,Calendar类
  9. printf函数重定向
  10. prometheus 筛选不同的cpu核心
  11. qt测试代码运行时间
  12. 线性同余算法 (LCG)
  13. c++超详细基础教程(快速入门)
  14. Java类和对象 详解(二)
  15. 车联网信息服务数据——采集合规性——行业标准解读
  16. php扩展-ioncube组件的安装方法_最新Phpstudy 安装 Ioncube Loader扩展方法分享
  17. Python小项目(学生成绩管理系统)7.排序、显示部分
  18. C/C++:无法打开.obj文件
  19. python关键词对联_使用百度 AI 进行智能写诗 智能春联
  20. 最新版Audition 2023(Au2023) win/mac音频编辑器

热门文章

  1. java将图片写入pdf
  2. pytorch修改tensor的维度(修改为任意维度,或单纯的增减维度)
  3. pandas使用dataframe读写mysql数据库
  4. pytorch 构造读取数据的工具类 Dataset 与 DataLoader (pytorch Data学习一)
  5. docker导入与导出容器
  6. vm linux数据恢复,VMWARE虚拟机数据恢复
  7. php sqlserver08001,PHP连接sqlserver2008,怎么连接指定ip地址上的数据库
  8. python3 pygame 坦克自动移动
  9. 如何把开源项目发布到Jcenter
  10. ubuntu nginx php问题研究