一、链式存储结构

由于顺序存储二叉树的空间利用率较低,因此二叉树一般都采用链式存储结构,用链表结点来存储二叉树中的每个结点。在二叉树中,结点结构通过包括若干数据域和若干指针域,二叉链表至少包含3个域:数据域 data、左指针域 lchild和右指针域 rchild,如下图所示:

其中,n 个结点的二叉链表中含有 n+1 [ 2n-(n-1)=n+1 ] 个空指针域

二、线索二叉树

传统的二叉链表仅能体现出一种父子关系,不能直接得到结点在遍历中的前驱或后继。引入线索二叉树正是为了加快查找结点前驱和后继的速度。

规定:若无左子树,令 lchild指向其前驱结点;若无右子树,令rchild执行指向其后继结点。增加两个标志域标识是指向左/右孩子还是指向前驱/后继。

其标志位含义如下:

这种加上线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。根据线索性质的不同, 线索二叉树可分为前序线索二叉树、 中序线索二叉树和后序线索二叉树三种。

1.1、中序线索二叉树
1.1.1 中序线索二叉树的构造

设置结点pre指向刚刚访问过的结点,结点node指向正在访问的结点,即pre指向node的前驱。在遍历过程中,检查node的左指针是否为空,若为空就将它指向pre;检查pre的右指针是否为空,若为空就将它指向node。

public static void inthreadNode(Node node) {if(node==null) {//结点为空无法线索化return;}//线索化左子树inthreadNode(node.getLeft());//线索化当前结点if(node.getLeft()==null) {node.setLeft(pre);//让当前结点的左指针指向前驱结点node.setLtag(1);//修改当前结点的左指针的类型,指向前驱结点}if(pre!=null&&pre.getRight()==null) {pre.setRight(node);//让前驱结点的右指针指向当前结点pre.setRtag(1);//修改当前结点的右指针的类型,指向后继结点}pre=node;//每处理一个结点后,让当前结点成为刚刚访问过的结点//线索化右子树inthreadNode(node.getRight());}

1.1.2 中序线索二叉树的遍历

因为线索化后, 各个结点指向有变化, 因此原来的遍历方式不能使用, 需要使用新的方式遍历线索化二叉树。中序线索二叉树的结点中隐含了线索二叉树的前驱和后继信息。在对其遍历时,需要找到第一个具有前驱结点的左结点,然后依次找结点的后继。在中序线索二叉树中找结点后继的规律是:若其右标志为1,则右链为线索,指示其后继,否则遍历右子树中第一个访问的结点(右子树中最左下的结点)为其后继。

public static void inthreadlist(Node node) {node=root;//存储当前遍历的结点,从root开始while(node!=null) {while(node.getLtag()==0) {node=node.getLeft();}System.out.println(node);//打印当前结点while(node.getRtag()==1) {//获取到当前结点的后继结点node=node.getRight();System.out.println(node);}node=node.getRight();//依次替换遍历的结点}}

1.1.3 中序线索二叉树完整代码

package Tree;public class InThreadedBinaryTree {public static void main(String[] args) {Node root=new Node(7,"A");//创建二叉树Node a=new Node(4,"B");Node b=new Node(9,"C");Node c=new Node(2,"D");Node d=new Node(5,"E");Node e=new Node(8,"F");Node f=new Node(11,"G");Node g=new Node(1,"H");Node h=new Node(3,"I");Node i=new Node(10,"J");Node j=new Node(12,"K");root.setLeft(a);root.setRight(b);a.setLeft(c);a.setRight(d);b.setLeft(e);b.setRight(f);c.setLeft(g);c.setRight(h);f.setLeft(i);f.setRight(j);inThreadBinaryTree thread=new inThreadBinaryTree(root);inThreadBinaryTree.inthreadNode(root);//创建中序线索二叉树inThreadBinaryTree.inthreadlist(root);//遍历中序线索二叉树}
}class Node{private int data;private String name;private Node left;//默认nullprivate Node right;//默认null//若ltag == 0,说明指向的是左子树;ltag == 1,指向的是前驱结点//若rtag == 0,说明指向的是右子树;rtag == 1,指向的是后继结点private int ltag;private int rtag;public Node(int data,String name) {this.data=data;this.name=name;}public int getData() {return data;}public void setData(int data) {this.data = data;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Node getLeft() {return left;}public void setLeft(Node left) {this.left = left;}public Node getRight() {return right;}public void setRight(Node right) {this.right = right;}public int getLtag() {return ltag;}public void setLtag(int ltag) {this.ltag = ltag;}public int getRtag() {return rtag;}public void setRtag(int rtag) {this.rtag = rtag;}@Overridepublic String toString() {//重写toString方法return "Node [data=" + data + ", name=" + name + "]";}
}//中序线索化二叉树(左->根->右)
class inThreadBinaryTree{private static Node root;private static Node pre=null;//pre表示刚刚访问过的结点,即前一个结点public inThreadBinaryTree(Node root) {//inThreadBinaryTree构造函数this.root=root;}public static void inthreadNode(Node node) {if(node==null) {//结点为空无法线索化return;}//线索化左子树inthreadNode(node.getLeft());//线索化当前结点if(node.getLeft()==null) {node.setLeft(pre);//让当前结点的左指针指向前驱结点node.setLtag(1);//修改当前结点的左指针的类型,指向前驱结点}if(pre!=null&&pre.getRight()==null) {pre.setRight(node);//让前驱结点的右指针指向当前结点pre.setRtag(1);//修改当前结点的右指针的类型,指向后继结点}pre=node;//每处理一个结点后,让当前结点成为刚刚访问过的结点//线索化右子树inthreadNode(node.getRight());}//中序线索化二叉树的遍历(遍历次序和中序遍历保持一致)public static void inthreadlist(Node node) {node=root;//存储当前遍历的结点,从root开始while(node!=null) {while(node.getLtag()==0) {node=node.getLeft();}System.out.println(node);//打印当前结点while(node.getRtag()==1) {//获取到当前结点的后继结点node=node.getRight();System.out.println(node);}node=node.getRight();//依次替换遍历的结点}}
}

运行结果:

Node [data=1, name=H]
Node [data=2, name=D]
Node [data=3, name=I]
Node [data=4, name=B]
Node [data=5, name=E]
Node [data=7, name=A]
Node [data=8, name=F]
Node [data=9, name=C]
Node [data=10, name=J]
Node [data=11, name=G]
Node [data=12, name=K]

该实例的二叉树图如下图所示:

2.1、前序线索二叉树和后序线索二叉树

二叉树的链式存储结构(线索二叉树)相关推荐

  1. C语言手写二叉树(链式存储结构)

    C语言手写二叉树(链式存储结构) 二叉树结构 二叉树基本运算 代码 图例(main函数执行过程如下:) 阶段I 阶段II 阶段III 阶段IV 阶段V 先序遍历输出过程 二叉树结构 二叉树可以用顺序存 ...

  2. 二叉树的链式存储结构--二叉链表

    1 二叉树的链式存储结构 //二叉链表的结点结构定义typedef int TElemType; typedef struct BiTNode {TElemType data;struct BiTNo ...

  3. 【数据结构】 实验报告10 顺序、链式存储结构的二叉树递归遍历、层次遍历求高度

    一.实验目的和要求 (源码在最后) 要求: 两种及以上存储结构(建议 顺序存储结构和链式存储结构各一).两种及以上方法(建议 递归遍历和层次遍历方法各一).分析各代码性能. 抽象数据类型(二叉树)独立 ...

  4. 二叉树的链式存储结构

    文章目录 前言 正文 总结 前言 上一节讲了二叉树的顺序存储,通过学习你会发现,其实二叉树并不适合用数组存储,因为并不是每个二叉树都是完全二叉树,普通二叉树使用顺序表存储或多或多会存在空间浪费的现象. ...

  5. (数据结构)二叉树的链式存储结构

    二叉树的顺序存储的缺点 因为并不是每个二叉树都是完全二叉树,普通二叉树使用顺序表存储或多或少会存在空间浪费的现象 图 1 普通二叉树的转化 如上图 1,普通二叉树里只有二个元素,最好的存储方式当然是开 ...

  6. 数据结构(C语言版)严蔚敏->二叉树(链式存储结构)的构造及其几种遍历方式(先序、中序、后序、层次)和线索二叉树

    二叉树每个节点至多只有两棵子树(即二叉树中不存在度大于2的节点),并且二叉树的子树有左右之分,其次序不能任意颠倒. 1. 二叉树 二叉树一般采用链式存储结构,用链表节点来存储二叉树中每个节点.在二叉树 ...

  7. 在链式存储结构建立二叉树排序树

    #include <stdlib.h> #include <stdio.h>//定义树 typedef struct node{ //树的结点int data;struct n ...

  8. c语言二叉树链式存储,C语言 二叉树的链式存储实例

    二叉树的链式存储 实现二叉树的基本操作:建立.遍历.计算深度.结点数.叶子数等. 输入C,先序创建二叉树,#表示空节点: 输入H:计算二叉树的高度: 输入L:计算二叉树的叶子个数: 输入N:计算二叉树 ...

  9. 线性表-链式存储结构

    3.6 线性表的链式存储结构 3.6.1 顺序存储结构不足的解决办法 前面我们讲的线性表的顺序存储结构.它是有缺点的,最大的缺点就是插入和删除时需要移动大量元素,这显然就需要耗费时间.能不能想办法解决 ...

最新文章

  1. java script valueof_Javascript new Date().valueOf()的作用与时间戳由来详解
  2. 前端组件库 - 搭建web app常用的样式/组件等收集列表(移动优先)
  3. Python class 类中 __init__ 函数
  4. php new对象 调用函数,关于JS中new调用函数的原理介绍
  5. tomcat开启SSL8443端口的方法
  6. 一套代码同时支持.NET Framework和.NET Core
  7. 看到一个暴强的翻译,闲的蛋疼,写个c#版的
  8. asp.NET自定义服务器控件内部细节系列教程一
  9. c 实现走迷宫流程图_c语言迷宫问题程序功能介绍.设计思路.数据结构设计及用法说明程序结构(流程图).各模块的功能及程序说明....
  10. java list 比较相同的元素_java list 比较相同的元素 | 学步园
  11. jQuery练手之滑动出现效果
  12. 【PID优化】基于matlab粒子群和遗传算法PID控制器优化设计【含Matlab源码 1311期】
  13. 鸟哥的Linux私房菜-服务器架设篇
  14. 朋友圈加粗字体数字_如何让你的朋友圈骚到脱颖而出?
  15. mysql如何成祖_明成祖朱棣原是藩王,成为皇帝以后是如何解决的藩王问题?
  16. 10个超强英语学习资源网站,学霸们都在用!
  17. 什么是iBeacon?
  18. 平行板电容的公式推导
  19. 地球物理勘探技术类毕业论文文献有哪些?
  20. 【Java并发编程实战】 5.5.1章节 闭锁 CountDownLatch 实现

热门文章

  1. MATLAB找圆心之路
  2. 【iCore3双核心板】【4.3寸液晶驱动板爆照!】
  3. 用Python分析了地震数据,最近地震也太太太频繁了吧?!
  4. 电线曲挠试验机的发展 洛克仪器Labverse
  5. DevExpress破解版下载
  6. django+haystack+elasticsearch优化查询效率
  7. Acrobat pro 快捷键设置
  8. 生成csv文件打开列变成科学计数法
  9. 人岗智能匹配系统(中)
  10. Linux系统中如何实现虚拟机的远程控制