【概述】

对于一个有 n 个结点的二叉链表,每个结点指向左右孩子的两个指针域,故共有 2n 个指针域,而 n 个结点的二叉树共有 n-1 条分支,即存在 2n-(n-1)=n+1 个空指针域,白白浪费了资源。

另一方面,在二叉链表上,只能知道每个结点的左右孩子结点的地址,而不知道某个结点的前驱和后继,要想知道,必须对二叉树进行遍历,以后每次想要知道时,都要遍历一次,这无疑浪费了时间。

综合以上两个方面,可以考虑利用空地址,存放指向结点在某种遍历次序下的前驱与后继,将指向前驱与后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树

【实现类】

线索化的实质就是将二叉链表中的空指针改为指向前驱或后继的线索,因此其存储结构相较于二叉链表有了更改

typedef enum{link,thread} Tag;//link=0表示指向左右孩子指针,thead=1表示指向前驱或后继的线索
template<class T>
struct Node{T data;//数据域Node<T> *lchild,rchild;//指针域Tag ltag,rtag;//标志域
};

对二叉树以某种次序遍历使其变为线索二叉树的过程称为线索化,由于二叉树的遍历分为前序、中序、后序、层序四种,那么相应的,在建立线索二叉树时,依据遍历次序的不同,也同样分为四种:

  • 前序线索二叉树
  • 中序线索二叉树
  • 后序线索二叉树
  • 层序线索二叉树

以上四种线索二叉树只是在线索化时的顺序有所不同,以下以中序线索二叉树为例

template<class T>
class ThreadTree{
public:ThreadTree();//构造函数,建立中序线索链表~ThreadTree();//析构函数,释放各结点空间Node<T> * findNext(Node<T> *bt);//查找结点bt的后继void inOrder();//中序遍历
private:Node<T> *root;//指向线索链表的头指针Node<T> * creat(Node<T> *bt);//构造函数调用void inThread(Node<T> *bt,Node<T> *pre);//构造函数调用
};

【构造函数】

构造函数的功能是建立一个中序线索链表,实质上就是将二叉树中的空指针改为指向前驱或后继的线索,而前驱或后继信息只有在遍历该二叉树时才能得到,因此建立线索链表应先建立一个二叉链表,然后在遍历的过程中修改空指针建立线索链表。

template<class T>
ThreadTree<T>::ThreadTree(){//构造函数root=creat(root);//建立带线索标志的二叉链表Node<T> *pre=NULL;//当前访问结点的前驱结点inThread(root,pre);//遍历二叉链表,建立线索
}
template<class T>
Node<T>* ThreadTree<T>::creat(Node<T> *bt){//建立带线索标志的二叉链表char ch;cin>>ch;if(ch=='#')//生成空树bt=NULL;else{bt=new Node<T>;bt->data=ch;bt->ltag=link;//左标志bt->rtag=link;//右标志bt->lchild=creat(bt->lchild);//递归建立左子树bt->rchild=creat(bt->rchild);//递归建立右子树}
}template<class T>
void ThreadTree<T>::inThread(Node<T> *bt,Node<T> *pre){//中序线索化if(root!=NULL){inThread(bt->lchild,pre);//递归左子树线索化if(bt->lchild!=NULL){//没有左孩子bt->ltag=thread;//前驱线索bt->lchild=pre;//左孩子指针执行前驱}if(pre->rchild!=NULL){//没有右孩子pre->rtag=thread;//后继线索pre->rchild=bt;//右孩子指向后继}pre=bt;//保持pre指向bt的前驱inThread(bt->rchild,pre);//递归右子树线索化}
}

【查找后继结点】

首先判断当前结点是否已有线索,若已有,则可直接得到后继,若没有,则要寻找当前结点的右孩子的最左下结点

template<class T>
Node<T> * ThreadTree<T>::findNext(Node<T> *bt){//查找结点bt的后继Node<T> *q;//后继if(bt->rtag==thread)//已有线索,直接得到后继结点q=bt->rchild;else{q=bt->rchild;//工作指针q指向bt的右孩子while(q->ltag==link)//查找最左下结点q=q->lchild;}return q;
}

【遍历操作】

对线索链表进行中序遍历操作时,只要寻找到中序序列的第一个结点,然后依次访问其后继即可

template<class T>
void ThreadTree<T>::inOrder(){//中序遍历if(root==NULL)return;else{Node<T> *p;p=root;while(p->ltag==link)//寻找中序遍历序列的第一个结点p=p->lchild;cout<<p->data;while(p->rchild!=NULL){//当结点p存在后继,依次访问其后继p=findNext(p);cout<<p->data;}}
}

理论基础 —— 二叉树 —— 线索链表相关推荐

  1. 线索二叉树(线索链表遍历,二叉树线索化)

    一,基本概念 线索二叉树,即在二叉链表的基础上,将二叉链表的空指针域指向其前驱节点和后继节点 线索:将二叉链表中的空指针域指向前驱结点和后继结点的指针被称为线索 线索化:使二叉链表中结点的空链域存放其 ...

  2. 理论基础 —— 二叉树 —— 三叉链表

    [三叉链表] 在二叉链表的存储方式下,从某结点出发可以直接访问到它的孩子结点,但要找到某个结点的父节点需要从根节点开始搜索,最坏情况下,需要遍历整个二叉链表. 而三叉链表,在二叉链表的基础上加了一个指 ...

  3. 线索二叉树(基于链表存储树结点)

    有以下场景 如果使用中序遍历,那么得到的顺序是:HDIBEAFCG,可以得知A的前驱结点为E,后继结点为F.但是,这种关系的获得是建立在完成遍历后得到的.如果我们每次想得到某个节点的前驱或者后继,都要 ...

  4. 理论基础 —— 二叉树

    [二叉树的定义] 二叉树( binary tree)是 n 个结点的有限集合,该集合或为空集(空二叉树),或由一个根结点与两棵互不相交的,称为根结点的左子树.右子树的二叉树构成. 二叉树的特点是: 每 ...

  5. 二叉树线索化(C语言)

    二叉树线索化 前言: 二叉树线索化主要是将二叉树按遍历的顺序存放于链表中,生成一个特定顺序的链表,访问该链表相当于遍历二叉树,此操作可便于在遍历的每一次操作中,可获取当前结点前驱或后继结点的数据信息 ...

  6. 数据结构—二叉树线索化(线索化的先序、中序、后序遍历)

    1.线索二叉树基本概念 二叉树是一种非线性结构,遍历二叉树几乎都是通过递归或者用栈辅助实现非递归的遍历.用二叉树作为存储结构时,取到一个节点,只能获取节点的左孩子和右孩子,不能直接得到节点的任一遍历序 ...

  7. 【数据结构Note5】- 树和二叉树(知识点超细大全-涵盖常见算法 排序二叉树 线索二叉树 平衡二叉树 哈夫曼树)

    文章目录 5.1 树和二叉树引入 5.1.1 树的概念 5.1.2 树的表示 5.1.3 树中基本术语 5.2 二叉树 5.2.1 概念 5.2.2 二叉树的性质 5.2.3 特殊的二叉树 5.2.4 ...

  8. 将搜索二叉树转换为链表_将给定的二叉树转换为双链表(DLL)

    将搜索二叉树转换为链表 Given a Binary tree and we have to convert it to a Doubly Linked List (DLL). 给定二叉树,我们必须将 ...

  9. 数据结构二叉树线索化

      线索化二叉树指的是将二叉树中的结点进行逻辑意义上的"重排列",使其可以线性的方式访问每一个结点.二叉树线索化之后每个结点都有一个线性下标,通过这个下标可以快速访问结点,而不需要 ...

最新文章

  1. 我在兰亭这三年之AutoDiff自动化测试框架
  2. ISME:沈农栾军波组揭示水平转移基因的功能
  3. 终极解决方案:Emacs+Slime+Lisp启动错误:Polling /tmp/slime.50
  4. android adapter 按钮隐藏 第一个无效_Android开发规范
  5. couchbase_具有Couchbase,Java EE和WildFly的CRUD Java应用程序
  6. Java static用法代码讲解
  7. 关于 shell 脚本编程的10 个最佳实践
  8. python爬虫之js链接跳转抓取_Python爬虫获取页面所有URL链接过程详解
  9. HTML页面打印功能js代码,JavaScript_js实现页面打印功能实例代码(附去页眉页脚功能代码),复制代码 代码如下: html - phpStudy...
  10. 面向对象设计的设计原则
  11. fatal error C1010: 是否忘记了向源中添加“#include stdafx.h”?
  12. Ubuntu18.04无法连接向日葵服务器的问题及解决
  13. js一键批量打印_前端连接打印机批量打印pdf格式的文件
  14. 嘉兴 机器人仓库 菜鸟_菜鸟在嘉兴推出全新智能仓,宣布将在双11启用超级机器人仓群...
  15. 「游戏建模」3DMAX渲染慢的解决小技巧
  16. 多用途互联网邮件扩展--MIME类型简介
  17. 输入法框无法正常显示问题
  18. 数据分析与预测(二)——pandas 函数read_csv解析
  19. Nelder Mead算法推荐阅读博文
  20. 2023 车险计算器微信小程序源码

热门文章

  1. 多播委托(multicast delegate)
  2. 重磅盘点!2018年更受欢迎的技术干货,来来回回也就看了几十遍吧
  3. 不懂这37个数据中心术语,怎么混数据圈饭局!
  4. STM32之串口原理
  5. 深入理解MySQL底层架构,看这一篇文章就够了!
  6. 让你的Mac电脑高效起来,推荐几个yyds的命令行工具
  7. 不想被时代抛弃,就别远离一线
  8. “互联网从此没有 BAT”
  9. 分布领域驱动设计(DDD):领域接口化设计式缓存的选择
  10. 可能是全网最通俗易懂的微服务架构改造解读