【Java】 大话数据结构(9) 树(二叉树、线索二叉树)
本文根据《大话数据结构》一书,对Java版的二叉树、线索二叉树进行了一定程度的实现。
另:
二叉树的性质
性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1)。
性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)。
性质3:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1。
证明提示:分支线总数=n0+n1+n2-1=n1+2×n2
性质4:具有n个节点的完全二叉树的深度为[log2n]+1。([ ]代表向下取整)
证明提示:假设深度为k,则有2{k-1} -1<n≤2{k} -1。
性质5:如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有
1.如果i=1,则节点是二叉树的根,无双亲,如果i>1,则其双亲节点为[i/2]
2.如果2i>n那么节点i没有左孩子(叶子结点),否则其左孩子为2i
3.如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1
二叉链表的定义代码
class BiTNode<E>{
E data;
BiTNode<E> lchild,rchild;
public BiTNode(E data) {
this.data=data;
this.lchild=null;
this.rchild=null;
}
}
public class BiTree<E> {
private BiTNode<E> root;
public BiTree() {
root=null;
}
...
}
二叉树的遍历
/*
* 前序遍历
*/
public void preOrder() {
preOrderTraverse(root);
System.out.println();
}
private void preOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
System.out.print(node.data);
preOrderTraverse(node.lchild);
preOrderTraverse(node.rchild);
} /*
* 中序遍历
*/
public void inOrder() {
inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
inOrderTraverse(node.lchild);
System.out.print(node.data);
inOrderTraverse(node.rchild);
} /*
* 后序遍历
*/
public void postOrder() {
postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
postOrderTraverse(node.lchild);
postOrderTraverse(node.rchild);
System.out.print(node.data);
}
二叉树的建立
《大话》一书中,6.9节关于二叉树的建立如下:

通过输入AB#D##C##,可以生成上述二叉树,其C语言的实现算法如下:


暂时能力有限,还不懂如何改为Java代码。
几点疑问:1.exit(OVERFLOW)不是很清楚什么意思;
2.代码中为char类型,如何用于泛型?
3.scanf()在Java中怎么实现?用scanner吗?程序如何知道输入完“AB#D##C##”就结束二叉树的构造呢?总的实现代码(包括main部分)是怎么样的?
以下为测试代码遍历的总体测试代码:
package BiTree;
class BiTNode<E>{
E data;
BiTNode<E> lchild,rchild;
public BiTNode(E data) {
this.data=data;
this.lchild=null;
this.rchild=null;
}
}
public class BiTree<E> {
private BiTNode<E> root;
public BiTree() {
//root=new BiTNode(null, null, null);
root=null;
}
/*
* 前序遍历
*/
public void preOrder() {
preOrderTraverse(root);
System.out.println();
}
private void preOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
System.out.print(node.data);
preOrderTraverse(node.lchild);
preOrderTraverse(node.rchild);
}
/*
* 中序遍历
*/
public void inOrder() {
inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
inOrderTraverse(node.lchild);
System.out.print(node.data);
inOrderTraverse(node.rchild);
}
/*
* 后序遍历
*/
public void postOrder() {
postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(BiTNode<E> node) {
if(node==null)
return;
postOrderTraverse(node.lchild);
postOrderTraverse(node.rchild);
System.out.print(node.data);
}
/*
* 6.9 二叉树的建立暂时不会,略
*/
public static void main(String[] args) {
BiTree<String> aBiTree = new BiTree<String>();
aBiTree.root=new BiTNode("A");
aBiTree.root.lchild=new BiTNode("B");
aBiTree.root.rchild=new BiTNode("C");
aBiTree.root.lchild.rchild=new BiTNode("D");
System.out.println("————前序————");
aBiTree.preOrder();
System.out.println("————中序————");
aBiTree.inOrder();
System.out.println("————后序————");
aBiTree.postOrder();
}
}
————前序————
ABDC
————中序————
BDAC
————后序————
DBCA
BiTree
线索二叉树

对一个有n个节点的二叉链表(如上图),整表存在2n个指针域,但分支线只有n-1条,说明空指针域的个数为2n-(n-1) = n+1个,浪费了很多的内存资源。
我们可以通过利用这些空指针域,存放节点在某种遍历方式下的前驱和后继节点的指针。我们把这种指向前驱和后继的指针成为线索,加上线索的二叉链表成为线索链表,对应的二叉树就成为“线索二叉树(Threaded Binary Tree)”,如下图所示。

线索二叉树的Java代码如下:
package BiThrTree; /**
* 线索二叉树
* 包含二叉树的中序线索化及其遍历
* @author Yongh
*
*/
class BiThrNode<E>{
E data;
BiThrNode<E> lChild,rChild;
boolean lTag,rTag;
public BiThrNode(E data) {
this.data=data;
//tag都先定义成左右孩子指针。
lTag=false; //其实把Tag定义为IsThread更好
rTag=false;
lChild=null;
rChild=null;
}
} public class BiThrTree<T> {
BiThrNode<T> root;
boolean link=false,thread=true; public BiThrTree() {
root=null;
} /*
* 中序线索化二叉树
* 即:在遍历的时候找到空指针进行修改。
*/
BiThrNode<T> pre; //线索化时记录的前一个结点 public void inThreading() {
inThreading(root);
}
private void inThreading(BiThrNode<T> p) {
if(p != null) {
inThreading(p.lChild);
if(p.lChild==null) {
p.lTag=thread;
p.lChild=pre;
}
if(pre!=null && pre.rChild==null) { //pre!=null一定要加上
pre.rTag=thread;
pre.rChild=p;
}
pre=p; //别忘了在这个位置加上pre=p
inThreading(p.rChild);
}
} /*
* 中序遍历二叉线索链表表示的二叉树(按后继方式)
* 书中添加了一个头结点,本程序中不含头结点
* 思路:先找到最左子结点
*/
public void inOrderTraverse() {
BiThrNode<T> p = root;
while(p!=null) {
while(p.lTag==link)
p=p.lChild; //找到最左子结点
System.out.print(p.data);
while(p.rTag==thread) { //不是if
p=p.rChild;
System.out.print(p.data);
}
p=p.rChild;
}
System.out.println();
} /*
* 中序遍历方法二(按后继方式)
* 参考别人的博客
*/
public void inOrderTraverse2() {
BiThrNode<T> node = root;
while(node != null && node.lTag==link) {
node = node.lChild;
}
while(node != null) {
System.out.print(node.data + ", ");
if(node.rTag==thread) {//如果右指针是线索
node = node.rChild; } else { //如果右指针不是线索,找到右子树开始的节点
node = node.rChild;
while(node != null && node.lTag==link) {
node = node.lChild;
}
}
}
System.out.println();
} public static void main(String[] args) {
BiThrTree<String> aBiThrTree = new BiThrTree<String>();
aBiThrTree.root=new BiThrNode<String>("A"); // A
aBiThrTree.root.lChild=new BiThrNode<String>("B"); // / \
aBiThrTree.root.lChild.lChild=new BiThrNode<String>("C"); // B D
aBiThrTree.root.rChild=new BiThrNode<String>("D"); // / / \
aBiThrTree.root.rChild.lChild=new BiThrNode<String>("E"); // C E F
aBiThrTree.root.rChild.rChild=new BiThrNode<String>("F");
aBiThrTree.inThreading();
aBiThrTree.inOrderTraverse();
aBiThrTree.inOrderTraverse2();
}
}
CBAEDF
C, B, A, E, D, F,
BiThrTree
推荐阅读:
线索二叉树原理及前序、中序线索化(Java版)(文中对线索二叉树的介绍和代码都比较清晰,且更加全面)。
赫夫曼树及其应用
带权路径长度WPL最小的二叉树称为最优二叉树,也称为赫夫曼树(Huffman Tree)。

赫夫曼编码:


推荐阅读:哈夫曼树(三)之 Java详解
【Java】 大话数据结构(9) 树(二叉树、线索二叉树)的更多相关文章
- 【PHP数据结构】完全二叉树、线索二叉树及树的顺序存储结构
在上篇文章中,我们学习了二叉树的基本链式结构以及建树和遍历相关的操作.今天我们学习的则是一些二叉树相关的概念以及二叉树的一种变形形式. 完全二叉树 什么叫完全二叉树呢?在说到完全二叉树之前,我们先说另 ...
- 树和二叉树->线索二叉树
文字描述 从二叉树的遍历可知,遍历二叉树的输出结果可看成一个线性队列,使得每个结点(除第一个和最后一个外)在这个线形队列中有且仅有一个前驱和一个后继.但是当采用二叉链表作为二叉树的存储结构时,只能得到 ...
- 从Java看数据结构之——树和他的操作集
写在前面 树这种数据结构在计算机世界中有广泛的应用,比如操作系统中用到了红黑树,数据库用到了B+树,编译器中的语法树,内存管理用到了堆(本质上也是树),信息论中的哈夫曼编码等等等等.而树的实现和他的操 ...
- Python与数据结构[3] -> 树/Tree[0] -> 二叉树及遍历二叉树的 Python 实现
二叉树 / Binary Tree 二叉树是树结构的一种,但二叉树的每一个节点都最多只能有两个子节点. Binary Tree: 00 |_____ | | 00 00 |__ |__ | | | | ...
- 线索二叉树的详细实现(C++)
线索二叉树概述 二叉树虽然是非线性结构,但二叉树的遍历却为二又树的结点集导出了一个线性序列.希望很快找到某一结点的前驱或后继,但不希望每次都要对二叉树遍历一遍,这就需要把每个结点的前驱和后继信息记录下 ...
- Java数据结构之树和二叉树
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- 数据结构之二叉树篇卷四 -- 二叉树线索化(With Java)
一.线索二叉树简介 二叉树本身是一种非线性结构,然而当你对二叉树进行遍历时,你会发现遍历结果是一个线性序列.这个序列中的节点存在前驱后继关系.因此,如何将这种前驱后继信息赋予给原本的二叉树呢?这就是二 ...
- 【Java】 大话数据结构(12) 查找算法(3) (平衡二叉树(AVL树))
本文根据<大话数据结构>一书及网络资料,实现了Java版的平衡二叉树(AVL树). 平衡二叉树介绍 在上篇博客中所实现的二叉排序树(二叉搜索树),其查找性能取决于二叉排序树的形状,当二叉排 ...
- 数据结构《9》----Threaded Binary Tree 线索二叉树
对于任意一棵节点数为 n 的二叉树,NULL 指针的数目为 n+1 , 线索树就是利用这些 "浪费" 了的指针的数据结构. Definition: "A binary ...
随机推荐
- 学习4__STM32--中断
Cortex-M处理器的NVIC接收中断请求各种源 > 从图中可看出,NVIC是一个外设中断的管理器,简化core的工作,控制着整个芯片的中断功能 > NVIC负责给外设中断分配优先级,使 ...
- Nginx反向代理1--基本介绍-虚拟主机
1 Nginx 1.1 什么是nginx Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师Igor Sysoev所开发, ...
- debian8.4 系统莫名没有声音
[http://www.linuxdiyf.com/viewarticle.php?id=437020 Debian8, 桌面环境是xfce4, 安装完成后发现前面板音频输出插孔正常,后面板的没声音. ...
- Python常用模块-时间模块(time&datetime)
Python常用模块-时间模块(time & datetime) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.初始time模块 #!/usr/bin/env pyth ...
- android编译时出现org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:compileDebugJavaWithJavac'.错误
android studio中使用terminal工具.在android studio最下面的底部菜单栏中有(如果没有那cmd中进入项目根目录后): 使用命令 gradlew compileDebu ...
- 文件通过svn updata更新不到,并且svn st显示被删除的解决办法
不知道什么原因导致某些文件丢失,svn updata更新后仍然没有找到,采用svn st 显示这些文件被删除,svn reslove 也解决不了,头疼了很久,最近突然解决了,具体步骤如下(已经过验证) ...
- SQL记录-PLSQL事务
PL/SQL事务 数据库事务是一个工作的原子单元,其可以由一个或多个相关的SQL语句组成.所谓的原子性就是数据库的修改所带来的构成事务的SQL语句可以集体被提交,即永久到数据库或从数据库中(撤消) ...
- bzoj千题计划256:bzoj2194: 快速傅立叶之二
http://www.lydsy.com/JudgeOnline/problem.php?id=2194 相乘两项的下标 的 差相同 那么把某一个反过来就是卷积形式 fft优化 #include< ...
- es6笔记(1) 概要
什么是ES6 ECMAScript 6.0 (简称ES6) 是继ECMAScript 5.1以后的javascript 语言的下一代标准,在2015年6月份发布. 他的目标是使javascript语言 ...
- E1. Array and Segments (Easy version)(暴力) && E2. Array and Segments (Hard version)(线段树维护)
题目链接: E1:http://codeforces.com/contest/1108/problem/E1 E2:http://codeforces.com/contest/1108/problem ...