线索化二叉树的实现(思路分析)
线索二叉树: Threaded BinaryTree
我们先来看一个问题:(通过这个问题我们来引入我们将要进行讲解的线索化二叉树):
问题: 将数列{1,3,6,8,10,14}构成一颗二叉树(如下图)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FDAl4vk0-1667387750530)(E:\非凡英才\数据结构(java)]\数据结构图解\线索化二叉树(问题引入).png)
问题分析:
- 当我们对上面的二叉树进行中序遍历的时候,数列为{8,3,10,1,6,14}
- 但是6,8,10,14这几个结点的左右指针并没有完全的利用上(这四个结点都有指针是空缺的,也就是这几个结点都有左右指针指向null的情况)
- 如果我们希望充分的利用各个节点的左右指针,让各个节点可以指向自己前后的结点,这个时候要如何做? --> 这个时候就要使用到我们的线索化二叉树
线索化二叉树的基本介绍:
- n个结点的二叉链表(二叉树)中有n+1个空指针域,利用二叉链表中的空指针域存放指向结点在某种遍历次序之下的前序和后继结点的指针(这种附加的指针就称之为: 线索)
- 为什么n个结点的二叉树中就会有n+1个空指针域?
- 公式2n - (n - 1) :
- 那么公式中的2n是什么? —> 这里公式中的2n就是我们这里n个结点的二叉树中总共有多少个指针域,每个结点都有两个指针域,所以一共有n个结点那么自然就是一共有2n个指针域
- 那么公式中的n-1又是什么? --> 这里公式中的n- 1其实就是含有n个结点的二叉树中被使用的指针域的个数, 我们每两个结点之间就需要使用某个结点的某一个指针域进行一个连接, 这个时候有n个结点,那么自然就是需要n- 1个指针域进行连接了
- 所以最终这个公式的含义其实就是: 总指针域个数 - 已经使用的指针域的个数 =空指针域的个数
- 这种加了线索的二叉链表称之为: 线索链表,相应的二叉树称之为线索二叉树(Threaded BinaryTree),根据线索的性质的不同线索二叉树可以分为: 前序线索二叉树 , 中序线索二叉树, 后序线索二叉树
- 一个节点的前一个节点我们就称之为当前节点的前驱结点
- 但是要注意 : 这里的前驱结点和后继结点都是相对于在某种遍历次序之下而说的, 不同的遍历方式之下的结点的相对位置不同
- 一个节点的后一个节点我们就称之为当前节点的后继结点
这里我们给出一个中序线索化二叉树的实例图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wQ5vTdiI-1667387750531)(E:\非凡英才\数据结构(java)]\数据结构图解\二叉树中序线索化实例.png)
思路分析:
我们以中序线索化二叉树为例
-
首先我们要知道我们要完成当前节点连接到对应的前驱和后继,这个时候我们肯定是要使用两个指针来完成( 这里我们使用一个node和一个pre)
- 我们使用node开始的时候指向我们的第一个遍历到的结点,让pre开始的时候指向null
-
我们先向左遍历二叉树
-
如果node此时的左指针为null,此时就将node的左指针指向前驱pre, 如果pre右指针为null,此时就将pre指向的结点的右指针指向后继node
-
向右递归右子树
当线索化二叉树之后,二叉树结点属性left 和 right就有了两种状态:
-
left
①指向的是左子树或者左子节点
②指向的是前驱结点
-
right
①指向的是右子树或者右子节点
②指向的是后继结点
所以我们要给结点类设置两个属性: leftType和rightType,用这两个属性标记我们的结点的left和rihgt是指向子树(或者子节点)还是指向了前驱(或者后继)结点
补充:
(以中序为例:)其实我们可以发现: 中序线索化二叉树也罢,中序查找也罢,或者是中序的什么操作也罢,都是在中序遍历的基础上进行一些二外的操作, 所以我们掌握了遍历的操作只会我们就掌握了对应的很多操作的写法
补充二:
(以中序为例: )其实中序线索化二叉树就是将对应的有空指针域的节点的左空指针域指向当前节点中序遍历下的前驱结点, 将对应的有空指针域的结点的右空指针域指向此节点中序遍历下的后继结点