线索二叉树的基本概念

我们按某种方式对二叉树进行遍历,将二叉树中所有节点排序为一个线性序列,在该序列中,除第一个结点外每个结点有且仅有一个直接前驱结点;除最后一个结点外每一个结点有且仅有一个直接后继结点。

在有N个节点的二叉树中需要利用N+1个空指针添加线索,这是因为在N个节点的二叉树中,每个节点有2个指针,所以一共有2N个指针,除了根节点以外,每一个节点都有一个指针从它的父节点指向它,所以一共使用了N-1个指针,所以剩下2N-(N-1)也就是N+1个空指针;

我们利用这些空指针域来存放指向该节点的直接前驱或是直接后继的指针,则可由此信息直接找到在该遍历次序下的前驱结点或后继结点,从而比递归遍历提高了遍历速度,节省了建立系统栈所使用的存储空间;

这些被重新利用起来的空指针就被称为线索(Thread),加上了这些线索的二叉树就是线索二叉树

根据线索性质的不同,线索二叉树可以分为前序线索二叉树,中序线索二叉树,后序线索二叉树。

记node指向二叉链表中的一个结点,以下是建立线索的规则:

(1)如果node的左指针域为空,则存放指向某种遍历序列中该结点的前驱结点,这个结点称为node的前驱;

(2)如果node的右指针域为空,则存放指向中序遍历序列中该结点的后继结点。这个结点称为node的后继;

代码实现

修改二叉树节点数据结构,节点类:

package 线索二叉树;

public class ClueNode {

	private Object data;
private ClueNode left;
private ClueNode right;
private boolean leftIsThread;
private boolean rightIsThread; public ClueNode(Object data) {
this.data = data;
this.left = null;
this.right = null;
this.leftIsThread = false;
this.rightIsThread = false;
} public ClueNode(Object data, ClueNode left, ClueNode right, boolean leftIsThread, boolean rightIsThread) {
this.data = data;
this.left = left;
this.right = right;
this.leftIsThread = leftIsThread;
this.rightIsThread = rightIsThread;
} public Object getData() {
return this.data;
}
public void setData(Object data ) {
this.data = data;
}
public ClueNode getLeft() {
return left;
} public void setLeft(ClueNode left)
{
this.left = left;
} public boolean isLeftIsThread()
{
return leftIsThread;
} public void setLeftIsThread(boolean leftIsThread)
{
this.leftIsThread = leftIsThread;
} public ClueNode getRight()
{
return right;
} public void setRight(ClueNode right)
{
this.right = right;
} public boolean isRightIsThread()
{
return rightIsThread;
} public void setRightIsThread(boolean rightIsThread)
{
this.rightIsThread = rightIsThread;
} public boolean equals(Object o) {
if(o instanceof ClueNode) {
ClueNode clue = (ClueNode)o;
return (clue.getData() == this.data) ? true : false;
}
else return false;
} }

线索二叉树类:

package 线索二叉树;

public class ClueForkTree {

	private ClueNode preNode;

	//根据数组构建完全二叉树
public static ClueNode createClueForkTree(Object[] array, int index) {
ClueNode node = null;
if(index < array.length) {
node = new ClueNode(array[index]);
ClueNode left = createClueForkTree(array, index * 2 + 1);
ClueNode right = createClueForkTree(array, index * 2 + 2);
node.setLeft(left);
node.setRight(right);
return node;
}
else return null;
} //中序线索化二叉树
public void inThReading(ClueNode node) {
if(node == null) return; inThReading(node.getLeft()); if(node.getLeft() == null) {
node.setLeft(preNode);
node.setLeftIsThread(true);
} if(preNode != null && preNode.getRight() == null) {
preNode.setRight(node);
preNode.setRightIsThread(true);
}
preNode = node; inThReading(node.getRight());
} //中序按后继方式遍历线索二叉树
public void inThreadList(ClueNode node) {
while(node != null && !node.isLeftIsThread()) {
node = node.getLeft();
} while(node != null) {
System.out.print(node.getData() + ","); if(node.isRightIsThread()) {
node = node.getRight();
}
else {
node = node.getRight();
while(node != null && !node.isLeftIsThread()) {
node = node.getLeft();
}
}
}
} //中序按前驱方式遍历线索二叉树
public void inPreThreadList(ClueNode node) {
while(node.getRight() != null && !node.isRightIsThread()) {
node = node.getRight();
}
while(node != null) {
System.out.print(node.getData() + ",");
if(node.isLeftIsThread()) {
node = node.getLeft();
}
else {
node = node.getLeft();
while(node.getRight() != null && !node.isRightIsThread()) {
node = node.getRight();
}
}
}
} //前序线索化二叉树
public void inThFrontReading(ClueNode node) {
if(node == null) return; if(node.getLeft() == null) {
node.setLeft(preNode);
node.setLeftIsThread(true);
} if(preNode != null && preNode.getRight() == null) {
preNode.setRight(node);
preNode.setRightIsThread(true);
} preNode = node;
if(!node.isLeftIsThread()) {
inThFrontReading(node.getLeft());
} if(!node.isRightIsThread()) {
inThFrontReading(node.getRight());
} } //前序按后继方式进行遍历二叉树
public void preThreadList(ClueNode node) {
while(node != null) {
while(!node.isLeftIsThread()) {
System.out.print(node.getData() + ",");
node = node.getLeft();
}
System.out.print(node.getData() + ",");
node = node.getRight(); }
} public static void main(String[] args) {
String[] array = {"A", "B", "C", "D", "E", "F", "G", "H"};
ClueNode root = createClueForkTree(array, 0);
ClueForkTree tree = new ClueForkTree();
tree.inThReading(root);
System.out.println("中序按后继节点遍历线索二叉树结果:");
tree.inThreadList(root); System.out.println("\n中序按前驱节点遍历线索二叉树结果:");
tree.inPreThreadList(root); ClueNode root1 = createClueForkTree(array, 0);
tree.inThFrontReading(root1);
tree.preNode = null;
System.out.println("\n前序按后继节点遍历线索二叉树结果:");
tree.preThreadList(root1); }
}

最新文章

  1. iOS 状态栏隐藏显示
  2. 邓博泽 java最全的DateUtil工具类
  3. JDBC的一些基础提交语句回顾
  4. Office 365 SharePoint 使用Charts Web Part
  5. bidi(双向文字)与RTL布局总结
  6. 加载的过程中图片变形了? --教你自定义自动适配图片宽高比的RatioLayout
  7. Java 读取Properties文件时应注意的路径问题
  8. Mecanim 动作复用示例
  9. php小知识点
  10. windows客户端连接到samba服务器(如何使用samba)
  11. UGUI Text控件
  12. [Leetcode][Python]47: Permutations II
  13. 引用(ajaxfileupload.js) ajaxfileupload.js报这错jQuery.handleError is not a function
  14. 一键搜索之Win10锁屏壁纸
  15. TS流文件
  16. windows无法安装msi文件
  17. Linux Rsyslog日志集中管理
  18. Centos 中 service iptables stop 失败
  19. android 工具大集合
  20. DAY5 基本数据类型及内置方法

热门文章

  1. 系统批量运维管理器pexpect详解
  2. 5- 如何把MyEclipse中的web项目导入到Eclipse中运行
  3. php多进程pcntl学习(采集新浪微博)
  4. 如何安装JDeveloper
  5. [模板]tarjan缩点+拓扑排序
  6. Laravel 5.4 实现无限级分类
  7. [OS] 修改屏幕分辨率(用Remote Desktop Connection 或者 用工具:Remote Desktop Connection Manager)
  8. Caffe 议事(三):从零开始搭建 ResNet 之 网络的搭建(中)
  9. sqlserver2012 清除日志
  10. Chrome Console API 参考