一、二叉树

二叉树指的是每个节点最多只能有两个子树的有序树。通常左边的子树被称为“左子树”(left subtree),右边的子树被称为右子树。

二叉树的每个节点最多只有2棵子树,二叉树的子树次序不能颠倒。

二、顺序存储二叉树的实现

 package com.ietree.basic.datastructure.tree.binarytree;

 /**
* Created by ietree
* 2017/5/1
*/
public class ArrayBinTree<T> { // 使用数组来记录该树的所有节点
private Object[] datas;
private int DEFAULT_DEEP = 8;
// 保存该树的深度
private int deep;
private int arraySize; // 以默认的深度创建二叉树
public ArrayBinTree() {
this.deep = DEFAULT_DEEP;
this.arraySize = (int) (Math.pow(2, deep) - 1);
datas = new Object[arraySize];
} // 以指定深度创建二叉树
public ArrayBinTree(int deep) {
this.deep = deep;
this.arraySize = (int) Math.pow(2, deep) - 1;
datas = new Object[arraySize];
} // 以指定深度、指定节点创建二叉树
public ArrayBinTree(int deep, T data) {
this.deep = deep;
this.arraySize = (int) Math.pow(2, deep) - 1;
datas = new Object[arraySize];
datas[0] = data;
} /**
* 为指定节点添加子节点
*
* @param index 需要添加子节点的父节点的索引
* @param data 新子节点的数据
* @param left 是否为左节点
*/
public void add(int index, T data, boolean left) {
if (datas[index] == null) {
throw new RuntimeException(index + "处节点为空,无法添加子节点");
}
if (2 * index + 1 >= arraySize) {
throw new RuntimeException("树底层的数组已满,树越界异常");
}
// 添加左子节点
if (left) {
datas[2 * index + 1] = data;
} else {
datas[2 * index + 2] = data;
}
} // 判断二叉树是否为空
public boolean empty() {
// 根据根元素判断二叉树是否为空
return datas[0] == null;
} // 返回根节点
public T root() {
return (T) datas[0];
} // 返回指定节点(非根结点)的父节点
public T parent(int index) {
return (T) datas[(index - 1) / 2];
} // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
public T left(int index) {
if (2 * index + 1 >= arraySize) {
throw new RuntimeException("该节点为叶子节点,无子节点");
}
return (T) datas[index * 2 + 1];
} // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
public T right(int index) {
if (2 * index + 1 >= arraySize) {
throw new RuntimeException("该节点为叶子节点,无子节点");
}
return (T) datas[index * 2 + 2];
} // 返回该二叉树的深度
public int deep(int index) {
return deep;
} // 返回指定节点的位置
public int pos(T data) {
// 该循环实际上就是按广度遍历来搜索每个节点
for (int i = 0; i < arraySize; i++) {
if (datas[i].equals(data)) {
return i;
} }
return -1;
} public String toString() {
return java.util.Arrays.toString(datas);
} }

测试类:

 package com.ietree.basic.datastructure.tree.binarytree;

 /**
* Created by ietree
* 2017/5/1
*/
public class ArrayBinTreeTest { public static void main(String[] args) { ArrayBinTree<String> binTree = new ArrayBinTree<String>(4, "根");
binTree.add(0, "第二层右子节点", false);
binTree.add(2, "第三层右子节点", false);
binTree.add(6, "第四层右子节点", false);
System.out.println(binTree); } }

程序输出:

[根, null, 第二层右子节点, null, null, null, 第三层右子节点, null, null, null, null, null, null, null, 第四层右子节点]

三、二叉树的二叉链表存储

二叉链表存储的思想是让每个节点都能“记住”它的左、右两个子节点。为每个节点增加left、right两个指针,分别引用该节点的左、右两个子节点。

 package com.ietree.basic.datastructure.tree.binarytree;

 /**
* Created by ietree
* 2017/5/1
*/
public class TwoLinkBinTree<E> { public static class TreeNode { Object data;
TreeNode left;
TreeNode right; public TreeNode() { } public TreeNode(Object data) {
this.data = data;
} public TreeNode(Object data, TreeNode left, TreeNode right) {
this.data = data;
this.left = left;
this.right = right;
} } private TreeNode root; // 以默认的构造器创建二叉树
public TwoLinkBinTree() {
this.root = new TreeNode();
} // 以指定根元素创建二叉树
public TwoLinkBinTree(E data) {
this.root = new TreeNode(data);
} /**
* 为指定节点添加子节点
*
* @param parent 需要添加子节点的父节点的索引
* @param data 新子节点的数据
* @param isLeft 是否为左节点
* @return 新增的节点
*/
public TreeNode addNode(TreeNode parent, E data, boolean isLeft) { if (parent == null) {
throw new RuntimeException(parent + "节点为null, 无法添加子节点");
}
if (isLeft && parent.left != null) {
throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
}
if (!isLeft && parent.right != null) {
throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
} TreeNode newNode = new TreeNode(data);
if (isLeft) {
// 让父节点的left引用指向新节点
parent.left = newNode;
} else {
// 让父节点的left引用指向新节点
parent.right = newNode;
}
return newNode;
} // 判断二叉树是否为空
public boolean empty() {
// 根据元素判断二叉树是否为空
return root.data == null;
} // 返回根节点
public TreeNode root() {
if (empty()) {
throw new RuntimeException("树为空,无法访问根节点");
}
return root;
} // 返回指定节点(非根节点)的父节点
public E parent(TreeNode node) {
// 对于二叉树链表存储法,如果要访问指定节点的父节点必须遍历二叉树
return null;
} // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
public E leftChild(TreeNode parent) {
if (parent == null) {
throw new RuntimeException(parent + "节点为null,无法添加子节点");
}
return parent.left == null ? null : (E) parent.left.data;
} // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
public E rightChild(TreeNode parent) {
if (parent == null) {
throw new RuntimeException(parent + "节点为null,无法添加子节点");
}
return parent.right == null ? null : (E) parent.right.data;
} // 返回该二叉树的深度
public int deep() {
// 获取该树的深度
return deep(root);
} // 这是一个递归方法:每一棵子树的深度为其所有子树的最大深度 + 1
private int deep(TreeNode node) {
if (node == null) {
return 0;
}
// 没有子树
if (node.left == null && node.right == null) {
return 1;
} else {
int leftDeep = deep(node.left);
int rightDeep = deep(node.right);
// 记录其所有左、右子树中较大的深度
int max = leftDeep > rightDeep ? leftDeep : rightDeep;
// 返回其左右子树中较大的深度 + 1
return max + 1;
} } }

测试类:

 package com.ietree.basic.datastructure.tree.binarytree;

 /**
* Created by ietree
* 2017/5/1
*/
public class TwoLinkBinTreeTest { public static void main(String[] args) { TwoLinkBinTree<String> binTree = new TwoLinkBinTree<String>("根节点");
// 依次添加节点
TwoLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二层左节点", true);
TwoLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二层右节点", false);
TwoLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三层左节点", true);
TwoLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三层右节点", false);
TwoLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四层左节点", true); System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
System.out.println(binTree.deep()); } }

程序输出:

tn2的左子节点:第三层左节点
tn2的右子节点:第三层右节点
4

四、二叉树的三叉链表存储

三叉链表存储方式是对二叉链表的一种改进,通过为树节点增加一个parent引用,可以让每个节点都能非常方便的访问其父节点,三叉链表存储的二叉树即可方便地向下访问节点,也可方便地向上访问节点。

 package com.ietree.basic.datastructure.tree.binarytree;

 /**
* Created by ietree
* 2017/5/1
*/
public class ThreeLinkBinTree<E> { public static class TreeNode { Object data;
TreeNode left;
TreeNode right;
TreeNode parent; public TreeNode() { } public TreeNode(Object data) {
this.data = data;
} public TreeNode(Object data, TreeNode left, TreeNode right, TreeNode parent) {
this.data = data;
this.left = left;
this.right = right;
this.parent = parent;
} } private TreeNode root; // 以默认的构造器创建二叉树
public ThreeLinkBinTree() {
this.root = new TreeNode();
} // 以指定根元素创建二叉树
public ThreeLinkBinTree(E data) {
this.root = new TreeNode(data);
} /**
* 为指定节点添加子节点
*
* @param parent 需要添加子节点的父节点的索引
* @param data 新子节点的数据
* @param isLeft 是否为左节点
* @return 新增的节点
*/
public TreeNode addNode(TreeNode parent, E data, boolean isLeft) { if (parent == null) {
throw new RuntimeException(parent + "节点为null, 无法添加子节点");
}
if (isLeft && parent.left != null) {
throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
}
if (!isLeft && parent.right != null) {
throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
} TreeNode newNode = new TreeNode(data);
if (isLeft) {
// 让父节点的left引用指向新节点
parent.left = newNode;
} else {
// 让父节点的left引用指向新节点
parent.right = newNode;
}
// 让新节点的parent引用到parent节点
newNode.parent = parent;
return newNode;
} // 判断二叉树是否为空
public boolean empty() {
// 根据元素判断二叉树是否为空
return root.data == null;
} // 返回根节点
public TreeNode root() {
if (empty()) {
throw new RuntimeException("树为空,无法访问根节点");
}
return root;
} // 返回指定节点(非根节点)的父节点
public E parent(TreeNode node) {
if (node == null) {
throw new RuntimeException("节点为null,无法访问其父节点");
}
return (E) node.parent.data;
} // 返回指定节点(非叶子)的左子节点,当左子节点不存在时返回null
public E leftChild(TreeNode parent) {
if (parent == null) {
throw new RuntimeException(parent + "节点为null,无法添加子节点");
}
return parent.left == null ? null : (E) parent.left.data;
} // 返回指定节点(非叶子)的右子节点,当右子节点不存在时返回null
public E rightChild(TreeNode parent) {
if (parent == null) {
throw new RuntimeException(parent + "节点为null,无法添加子节点");
}
return parent.right == null ? null : (E) parent.right.data;
} // 返回该二叉树的深度
public int deep() {
// 获取该树的深度
return deep(root);
} // 这是一个递归方法:每一棵子树的深度为其所有子树的最大深度 + 1
private int deep(TreeNode node) {
if (node == null) {
return 0;
}
// 没有子树
if (node.left == null && node.right == null) {
return 1;
} else {
int leftDeep = deep(node.left);
int rightDeep = deep(node.right);
// 记录其所有左、右子树中较大的深度
int max = leftDeep > rightDeep ? leftDeep : rightDeep;
// 返回其左右子树中较大的深度 + 1
return max + 1;
} } }

测试类:

 package com.ietree.basic.datastructure.tree.binarytree;

 /**
* Created by ietree
* 2017/5/1
*/
public class ThreeLinkBinTreeTest { public static void main(String[] args) { ThreeLinkBinTree<String> binTree = new ThreeLinkBinTree<String>("根节点");
// 依次添加节点
ThreeLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二层左节点", true);
ThreeLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二层右节点", false);
ThreeLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三层左节点", true);
ThreeLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三层右节点", false);
ThreeLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四层左节点", true); System.out.println("tn2的左子节点:" + binTree.leftChild(tn2));
System.out.println("tn2的右子节点:" + binTree.rightChild(tn2));
System.out.println(binTree.deep()); } }

程序输出:

tn2的左子节点:第三层左节点
tn2的右子节点:第三层右节点
4

Java中二叉树存储结构实现的更多相关文章

  1. 存储结构与邻接矩阵,深度优先和广度优先遍历及Java实现

    如果看完本篇博客任有不明白的地方,可以去看一下<大话数据结构>的7.4以及7.5,讲得比较易懂,不过是用C实现 下面内容来自segmentfault 存储结构 要存储一个图,我们知道图既有 ...

  2. 【Java数据结构学习笔记之一】线性表的存储结构及其代码实现

    应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有"同属于一个集合"的关系 线性结构:数据元素之间存在一个对一个的关系 树形结构:数据元素之间存在一个对多个关 ...

  3. Java队列存储结构及实现

    一.队列(Queue) 队列是一种特殊的线性表,它只允许在表的前段(front)进行删除操作,只允许在表的后端(rear)进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头. 对于一个队 ...

  4. 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  5. Java中Map<Key, Value>存储结构根据值排序(sort by values)

    需求:Map<key, value>中可以根据key, value 进行排序,由于 key 都是唯一的,可以很方便的进行比较操作,但是每个key 对应的value不是唯一的,有可能出现多个 ...

  6. Java数据结构——树的三种存储结构

    (转自http://blog.csdn.net/x1247600186/article/details/24670775) 说到存储结构,我们就会想到常用的两种存储方式:顺序存储和链式存储两种. 先来 ...

  7. java资料——顺序存储结构和链式存储结构(转)

    顺序存储结构 主要优点 节省存储空间,随机存取表中元素 缺    点 插入和删除操作需要移动元素 在计算机中用一组地址连续的存储单元依次存储线性表的各个数据元素,称作线性表的顺序存储结构. 顺序存储结 ...

  8. Java栈之链式栈存储结构实现

    一.链栈 采用单链表来保存栈中所有元素,这种链式结构的栈称为链栈. 二.栈的链式存储结构实现 package com.ietree.basic.datastructure.stack; /** * 链 ...

  9. Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构

    Atitit.数据索引 的种类以及原理实现机制 索引常用的存储结构 1. 索引的分类1 1.1. 按照存储结构划分btree,hash,bitmap,fulltext1 1.2. 索引的类型  按查找 ...

随机推荐

  1. annexb模式

    h264有两种封装,一种是annexb模式,传统模式,有startcode,SPS和PPS是在ES中一种是mp4模式,一般mp4 mkv会有,没有startcode,SPS和PPS以及其它信息被封装在 ...

  2. 【BZOJ】1696: [Usaco2007 Feb]Building A New Barn新牛舍(贪心)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1696 原题要求min(sum{|x-xi|+|y-yi|}),且一定要看题:“没有两头牛的吃草位置是 ...

  3. 『Spring.NET+NHibernate+泛型』框架搭建之DAO(三)★

    本节内容介绍Nhibernate所封装的数据库訪问层.只是我增加了泛型进行封装.大概思路:首先,我们有一个接口层,另一个相应的实现层.在接口层中我们先定义一个父接口,父接口中定义每个接口都可能会用到的 ...

  4. cocos2dx --- 富文本的使用 RichText

    在实际工作中,有非常多地方会使用 富文本,这里仅仅介绍最简单的富文本用法: 是由cocostudio 提供的 RichText: 直接贴代码,再分析: //这里測试富文本控件 ui::RichText ...

  5. 多线程编程(三)--创建线程之Thread VS Runnable

    前面写过一篇基础的创建多线程的博文: 那么本篇博文主要来对照一下这两种创建线程的差别. 继承Thread类: 还拿上篇博客的样例来说: 四个线程各自卖各自的票,说明四个线程之间没有共享,是独立的线程. ...

  6. 转:Socket服务器整体架构概述

    Socket服务器主要用于提供高效.稳定的数据处理.消息转发等服务,它直接决定了前台应用程序的性能.我们先从整体上认识一下Socket服务器,Socket服务器从架构上一般分为:网络层.业务逻辑层.会 ...

  7. 【openwrt+arduion】案例

    http://www.geek-workshop.com/thread-4950-1-1.html http://www.guokr.com/article/319356/ http://www.gu ...

  8. 终端利用ssh登录远程服务器

    第一步: 安装ssh:yum  install ssh 第二步: 启动ssh服务:service sshd start 第三步: 连接远程服务器: ssh -p 端口号 用户名@ip地址      然 ...

  9. Vim相关优化和配置

    升级pythonwget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgztar -xvf Python-3.6.5.tgzcd Pyt ...

  10. 数据库为什么要用B+树结构--MySQL索引结构的实现(转)

    B+树在数据库中的应用 { 为什么使用B+树?言简意赅,就是因为: 1.文件很大,不可能全部存储在内存中,故要存储到磁盘上 2.索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数(为什么使用B-/ ...