Java中二叉排序树
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中二叉排序树的更多相关文章
- Java中哈希表(Hashtable)是如何实现的
Java中哈希表(Hashtable)是如何实现的 Hashtable中有一个内部类Entry,用来保存单元数据,我们用来构建哈希表的每一个数据是Entry的一个实例.假设我们保存下面一组数据,第一列 ...
- java中的锁
java中有哪些锁 这个问题在我看了一遍<java并发编程>后尽然无法回答,说明自己对于锁的概念了解的不够.于是再次翻看了一下书里的内容,突然有点打开脑门的感觉.看来确实是要学习的最好方式 ...
- java中的字符串相关知识整理
字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- java中Action层、Service层和Dao层的功能区分
Action/Service/DAO简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. Action只负责管理,而Service负责实施. DAO只 ...
- Java中常用集合操作
一.Map 名值对存储的. 常用派生类HashMap类 添加: put(key,value)往集合里添加数据 删除: clear()删除所有 remove(key)清除单个,根据k来找 获取: siz ...
- java中的移位运算符:<<,>>,>>>总结
java中有三种移位运算符 << : 左移运算符,num << 1,相当于num乘以2 >> : 右移运算符,num >& ...
- 关于Java中进程和线程的详解
一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...
- Java中的进程和线程
Java中的进程与线程 一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是 ...
随机推荐
- BZOJ1835: [ZJOI2010]base 基站选址【线段树优化DP】
Description 有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di.需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci.如果在距离第i个村庄 ...
- 《DSP using MATLAB》Problem 2.4
生成并用stem函数画出这几个序列. 1.代码: %% ------------------------------------------------------------------------ ...
- 文件和I/O流
版权声明:本文为[博主](https://zhangkn.github.io)原创文章,未经博主同意不得转载.https://creativecommons.org/licenses/by-nc-sa ...
- Spring线程池ThreadPoolTaskExecutor配置及详情
Spring线程池ThreadPoolTaskExecutor配置及详情 1. ThreadPoolTaskExecutor配置 <!-- spring thread pool executor ...
- Java里的集合--主要区别
Collection 集合接口,指的是 java.util.Collection接口,是 Set.List 和 Queue 接口的超类接口. List: List是关注事物索引的列表. List中可以 ...
- 详解Oracle的几种分页查询语句
转载自:http://database.51cto.com/art/200904/118737.htm 分页查询格式: SELECT * FROM (SELECT A.*, ROWNUM RN FRO ...
- mysql安装过程及注意事项
1.1. 下载: 我下载的是64位系统的zip包: 下载地址:https://dev.mysql.com/downloads/mysql/ 下载zip的包: 下载后解压:D:\软件安装包\mysql- ...
- socket_简单报头
client--------------------- #!/usr/bin/python3# -*- coding: utf-8 -*-# @Time : 2018/6/6 14:53# @F ...
- uva-11111-栈
注意输入和输出的结果 -9 -7 -2 2 -3 -2 -1 1 2 3 7 9 -9 -7 -2 2 -3 -1 -2 2 1 3 7 9-9 -7 -2 2 -3 -1 -2 3 2 1 7 9- ...
- linux下创建具有root权限的账户
http://blog.chinaunix.net/uid-24631445-id-2981034.html