package com.ietree.basic.datastructure.tree;

 import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue; /**
* Created by ietree
* 2017/5/1
*/
public class SortedBinTree<T extends Comparable> { static class Node { Object data;
Node parent;
Node left;
Node right; public Node(Object data, Node parent, Node left, Node right) {
this.data = data;
this.parent = parent;
this.left = left;
this.right = right;
} public String toString() {
return "[data=" + data + "]";
} public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj.getClass() == Node.class) {
Node target = (Node) obj;
return data.equals(target.data) && left == target.left && right == target.right && parent == target.parent;
}
return false;
} } private Node root; // 两个构造器用于创建排序二叉树
public SortedBinTree() {
root = null;
} public SortedBinTree(T o) {
root = new Node(o, null, null, null);
} // 添加节点
public void add(T ele) {
// 如果根节点为null
if (root == null) {
root = new Node(ele, null, null, null);
} else {
Node current = root;
Node parent = null;
int cmp = 0;
// 搜索合适的叶子节点,以该叶子节点为父节点添加新节点
do {
parent = current;
cmp = ele.compareTo(current.data);
// 如果新节点的值大于当前节点的值
if (cmp > 0) {
// 以右子节点作为当前节点
current = current.right;
} else {
// 如果新节点的值小于当前节点的值
// 以左节点作为当前节点
current = current.left;
}
}
while (current != null);
// 创建新节点
Node newNode = new Node(ele, parent, null, null);
// 如果新节点的值大于父节点的值
if (cmp > 0) {
// 新节点作为父节点的右子节点
parent.right = newNode;
} else {
// 如果新节点的值小于父节点的值
// 新节点作为父节点的左子节点
parent.left = newNode;
}
}
} // 删除节点
public void remove(T ele) {
// 获取要删除的节点
Node target = getNode(ele);
if (target == null) {
return;
}
// 左、右子树为空
if (target.left == null && target.right == null) {
// 被删除节点是根节点
if (target == root) {
root = null;
} else {
// 被删除节点是父节点的左子节点
if (target == target.parent.left) {
// 将target的父节点的left设为null
target.parent.left = null;
} else {
// 将target的父节点的right设为null
target.parent.right = null;
}
target.parent = null;
}
} else if (target.left == null && target.right != null) {
// 左子树为空,右子树不为空
// 被删除节点是根节点
if (target == root) {
root = target.right;
} else {
// 被删除节点是父节点的左子节点
if (target == target.parent.left) {
// 让target的父节点的left指向target的右子树
target.parent.left = target.right;
} else {
// 让target的父节点的right指向target的右子树
target.parent.right = target.right;
}
// 让target的右子树的parent指向target的parent
target.right.parent = target.parent;
}
} else if (target.left != null && target.right == null) {
// 左子树不为空,右子树为空
// 被删除节点是根节点
if (target == root) {
root = target.left;
} else {
// 被删除节点是父节点的左子节点
if (target == target.parent.left) {
// 让target的父节点的left指向target的左子树
target.parent.left = target.left;
} else {
// 让target的父节点的right指向target的左子树
target.parent.right = target.left;
}
// 让target的左子树的parent指向target的parent
target.left.parent = target.parent;
}
} else {
// 左、右子树都不为空
// leftMaxNode用于保存target节点的左子树中值最大的节点
Node leftMaxNode = target.left;
// 搜索target节点的左子树中值最大的节点
while (leftMaxNode.right != null) {
leftMaxNode = leftMaxNode.right;
}
// 从原来的子树中删除leftMaxNode节点
leftMaxNode.parent.right = null;
// 让leftMaxNode的parent指向target的parent
leftMaxNode.parent = target.parent;
// 被删除节点是父节点的左子节点
if (target == target.parent.left) {
// 让target的父节点的left指向leftMaxNode
target.parent.left = leftMaxNode;
} else {
// 让target的父节点的right指向leftMaxNode
target.parent.right = leftMaxNode;
}
leftMaxNode.left = target.left;
leftMaxNode.right = target.right;
target.parent = target.left = target.right = null;
}
} // 根据给定的值搜索节点
public Node getNode(T ele) {
// 从根节点开始搜索
Node p = root;
while (p != null) {
int cmp = ele.compareTo(p.data);
// 如果搜索的值小于当前p节点的值
if (cmp < 0) {
// 向左子树搜索
p = p.left;
} else if (cmp > 0) {
// 如果搜索的值大于当前p节点的值
// 向右子树搜索
p = p.right;
} else {
return p;
}
}
return null;
} // 广度优先遍历
public List<Node> breadthFirst() { Queue<Node> queue = new ArrayDeque<Node>();
List<Node> list = new ArrayList<Node>();
if (root != null) {
// 将根元素入“队列”
queue.offer(root);
}
while (!queue.isEmpty()) {
// 将该队列的“队尾”的元素添加到List中
list.add(queue.peek());
Node p = queue.poll();
// 如果左子节点不为null,将它加入“队列”
if (p.left != null) {
queue.offer(p.left);
}
// 如果右子节点不为null,将它加入“队列”
if (p.right != null) {
queue.offer(p.right);
}
}
return list;
} }

测试类:

 package com.ietree.basic.datastructure.tree;

 /**
* Created by ietree
* 2017/5/1
*/
public class SortedBinTreeTest { public static void main(String[] args) { SortedBinTree<Integer> tree = new SortedBinTree<Integer>(); // 添加节点
tree.add(5);
tree.add(20);
tree.add(10);
tree.add(3);
tree.add(8);
tree.add(15);
tree.add(30); System.out.println(tree.breadthFirst());
// 删除节点
tree.remove(20);
System.out.println(tree.breadthFirst()); } }

程序输出:

[[data=5], [data=3], [data=20], [data=10], [data=30], [data=8], [data=15]]
[[data=5], [data=3], [data=15], [data=10], [data=30], [data=8]]

采用广度优先法则来遍历排序二叉树得到的不是有序序列,采用中序遍历来遍历排序二叉树才可以得到有序序列。

Java中二叉排序树的更多相关文章

  1. Java中哈希表(Hashtable)是如何实现的

    Java中哈希表(Hashtable)是如何实现的 Hashtable中有一个内部类Entry,用来保存单元数据,我们用来构建哈希表的每一个数据是Entry的一个实例.假设我们保存下面一组数据,第一列 ...

  2. java中的锁

    java中有哪些锁 这个问题在我看了一遍<java并发编程>后尽然无法回答,说明自己对于锁的概念了解的不够.于是再次翻看了一下书里的内容,突然有点打开脑门的感觉.看来确实是要学习的最好方式 ...

  3. java中的字符串相关知识整理

    字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...

  4. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  5. java中Action层、Service层和Dao层的功能区分

    Action/Service/DAO简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. Action只负责管理,而Service负责实施. DAO只 ...

  6. Java中常用集合操作

    一.Map 名值对存储的. 常用派生类HashMap类 添加: put(key,value)往集合里添加数据 删除: clear()删除所有 remove(key)清除单个,根据k来找 获取: siz ...

  7. java中的移位运算符:<<,>>,>>>总结

    java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >& ...

  8. 关于Java中进程和线程的详解

    一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...

  9. Java中的进程和线程

     Java中的进程与线程 一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是 ...

随机推荐

  1. POI2015题解

    POI2015题解 吐槽一下为什么POI2015开始就成了破烂波兰文题目名了啊... 咕了一道3748没写打表题没什么意思,还剩\(BZOJ\)上的\(14\)道题. [BZOJ3746][POI20 ...

  2. socket编程---UDP

    头文件 #include <sys/types.h> #include <sys/socket.h> 函数原型 int sendto (int s, const void *b ...

  3. 使用ntp从时间同步服务器更新centos系统时间的方法

    CentOS系统时间同步的步骤如下: 复制代码 代码如下: cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtimentpdate us.pool.ntp ...

  4. VS2013编译64位OpenSSL(附32位)

    安装ActivePerl 这个没什么好说的,直接运行msi即可. 编译OpenSSL 1.使用Visual Studio Tool中的“VS2013 x64 本机工具命令提示”来打开控制台:也可以打开 ...

  5. redis3.0自带集群配置

    参考 http://redis.readthedocs.org/en/latest/topic/cluster-tutorial.html http://yindashan.github.io/blo ...

  6. Call to your teacher

    链接:https://www.nowcoder.net/acm/contest/76/F来源:牛客网 Call to your teacher 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/ ...

  7. Java之解压流(ZipInputStream)

    一.ZipInputStream相对于ZipOutputStream而言,使用上面简单的多了,相对的,既然存在压缩流,就会存在,解压的方式. 二.解压文件,流的使用过程中也是很常用的,在读取文件,根据 ...

  8. 【Codeforces】Educational Codeforces Round 46(Contest 1000)

    题目 传送门:QWQ A:Codehorses T-shirts 题意: 给定一些字符串表示去年和今年的衣服型号大小( XL XXL M...... ),要求用最少的次数把去年的衣服大小改成今年需要的 ...

  9. Autofac log4net Integration Module

    log4net Integration Module While there is no specific assembly for log4net support, you can easily i ...

  10. Spring batch学习 (1)

    Spring Batch 批处理框架 埃森哲和Spring Source研发 主要解决批处理数据的问题,包含并行处理,事务处理机制等.具有健壮性 可扩展,和自带的监控功能,并且支持断点和重发.让程序员 ...