线索二叉树的理解和实现(Java)
线索二叉树的基本概念
我们按某种方式对二叉树进行遍历,将二叉树中所有节点排序为一个线性序列,在该序列中,除第一个结点外每个结点有且仅有一个直接前驱结点;除最后一个结点外每一个结点有且仅有一个直接后继结点。
在有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);
}
}
线索二叉树的理解和实现(Java)的更多相关文章
- 【Java】 大话数据结构(9) 树(二叉树、线索二叉树)
本文根据<大话数据结构>一书,对Java版的二叉树.线索二叉树进行了一定程度的实现. 另: 二叉排序树(二叉搜索树) 平衡二叉树(AVL树) 二叉树的性质 性质1:二叉树第i层上的结点数目 ...
- 【PHP数据结构】完全二叉树、线索二叉树及树的顺序存储结构
在上篇文章中,我们学习了二叉树的基本链式结构以及建树和遍历相关的操作.今天我们学习的则是一些二叉树相关的概念以及二叉树的一种变形形式. 完全二叉树 什么叫完全二叉树呢?在说到完全二叉树之前,我们先说另 ...
- Atitit 深入理解命名空间namespace java c# php js
Atitit 深入理解命名空间namespace java c# php js 1.1. Namespace还是package1 1.2. import同时解决了令人头疼的include1 1.3 ...
- 数据结构《9》----Threaded Binary Tree 线索二叉树
对于任意一棵节点数为 n 的二叉树,NULL 指针的数目为 n+1 , 线索树就是利用这些 "浪费" 了的指针的数据结构. Definition: "A binary ...
- 线索二叉树Threaded binary tree
摘要 按照某种遍历方式对二叉树进行遍历,可以把二叉树中所有结点排序为一个线性序列.在该序列中,除第一个结点外每个结点有且仅有一个直接前驱结点:除最后一个结点外每一个结点有且仅有一个直接后继结点.这 ...
- 遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化
遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...
- 理解和解决Java并发修改异常ConcurrentModificationException(转载)
原文地址:https://www.jianshu.com/p/f3f6b12330c1 理解和解决Java并发修改异常ConcurrentModificationException 不知读者在Java ...
- 树和二叉树->线索二叉树
文字描述 从二叉树的遍历可知,遍历二叉树的输出结果可看成一个线性队列,使得每个结点(除第一个和最后一个外)在这个线形队列中有且仅有一个前驱和一个后继.但是当采用二叉链表作为二叉树的存储结构时,只能得到 ...
- 图解中序遍历线索化二叉树,中序线索二叉树遍历,C\C++描述
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
随机推荐
- 使用twised实现一个EchoServer
ProtocolsProtocols描述了如何以异步的方式处理网络中断时间,HTTP.DNS已经IMAP是应用应用层协议中的例子,Protocols实现了IProtocol接口,它饱和如下的方法 ma ...
- C语言源字符集与执行字符集
参考: http://blog.csdn.net/yucan1001/article/details/7188267 http://blog.csdn.net/dbzhang800/article ...
- Pwdump v7.1
提取windows系统密码 和 hash值
- struts2下velocity做视图如何访问request,session等内置对象,如:原来webwork的$req
struts2下velocity做视图如何访问request,session等内置对象(转) velocity 内置对象 struts2 requestStruts2环境下用velocity做视图时访 ...
- spring aop记录用户的操作
1.命名空间 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.or ...
- linux每天一小步---rm命令详解
1 命令功能 rm命令用于删除文件或者目录,值得注意的是linux下的删除不弯曲等同于windows系统下的删除操作,linux系统下一旦删除了文件或者目录那么它将消失,而windows系统下我们还可 ...
- line-height:150% 和 line-height:1.5
line-height属性的细节与大多数CSS属性不同,line-height支持属性值设置为无单位的数字.有无单位在子元素继承属性时有微妙的不同. 有单位(包括百分比)与无单位之间的区别有单位时,子 ...
- .NET基础 (14)管理文件和文件夹的类型
管理文件和文件夹的类型1 如何操作文件和文件夹2 如何实现文件和文件夹的监控功能 管理文件和文件夹的类型1 如何操作文件和文件夹 .NET内建类中提供了FileInfo和DictionaryInfo两 ...
- 安装Greenplum-perfmon-web监控软件遇到的问题及解决
环境 Product Version Pivotal Greenplum (GPDB) 4.3.x Pivotal Greenplum Command Center (GPCC) Others ...
- 详解CSS盒模型
原文地址:http://luopq.com/2015/10/26/CSS-Box-Model/ 本文主要是学习CSS盒模型的笔记,总结了一些基本概念,知识点和细节. 一些基本概念 HTML的大多数元素 ...