二叉排序树
1、问题引入
先看一个需求
给你一个数列 (7, 3, 10, 12, 5, 1, 9),要求能够高效的完成对数据的查询和添加
解决方案分析
使用数组
数组未排序, 优点:直接在数组尾添加,速度快。 缺点:查找速度慢.
数组排序,优点:可以使用二分查找,查找速度快,缺点:为了保证数组有序,在添加新数据时,找到插入位 置后,后面的数据需整体移动,速度慢。
使用链式存储-链表
不管链表是否有序,查找速度都慢,添加数据速度比数组快,不需要数据整体移动。
使用二叉排序树
2、基本介绍
二叉排序树:BST: (Binary Sort(Search) Tree), 对于二叉排序树的 任何一个非叶子节点,要求 左子节点的值比当 前节点的值小, 右子节点的值比当前节点的值大。特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点比如针对前面的数据 (7, 3, 10, 12, 5, 1, 9) ,对应的二叉排序树为:
3、二叉排序树创建和遍历
3.1、问题分析
一个数组创建成对应的二叉排序树,并使用中序遍历二叉排序树,比如: 数组为 Array(7, 3, 10, 12, 5, 1, 9) , 创 建成对应的二叉排序树为 :
3.2、代码实现
public class BinarySortTreeDemo {
public static void main(String
[] args
) {
int[] arr
= {7,3,10,12,5,1,9};
BinarySortTree binarySortTree
= new BinarySortTree();
for (int i
= 0; i
< arr
.length
; i
++) {
Node node
= new Node(arr
[i
]);
binarySortTree
.add(node
);
}
binarySortTree
.infixOrder();
}
}
class BinarySortTree{
private Node root
;
public void add(Node node
){
if (root
== null
){
root
= node
;
}else {
root
.add(node
);
}
}
public void infixOrder(){
if (root
!= null
){
root
.infixOrder();
}else {
System
.out
.println("二叉树为空, 无法进行中序遍历~~");
}
}
}
class Node{
int value
;
Node left
;
Node right
;
public Node(int value
) {
this.value
= value
;
}
@Override
public String
toString() {
return "Node{" +
"value=" + value
+
'}';
}
public void add(Node node
){
if (node
== null
){
return;
}
if (node
.value
< this.value
){
if (this.left
== null
){
this.left
= node
;
}else {
this.left
.add(node
);
}
}else {
if (this.right
== null
){
this.right
= node
;
}else {
this.right
.add(node
);
}
}
}
public void infixOrder(){
if (this.left
!= null
){
this.left
.infixOrder();
}
System
.out
.println(this);
if (this.right
!= null
){
this.right
.infixOrder();
}
}
}
4、二叉排序树的删除
4.1、问题分析
二叉排序树的删除情况比较复杂,有下面三种情况需要考虑
删除叶子节点 (比如:2, 5, 9, 12)删除只有一颗子树的节点 (比如:1)删除有两颗子树的节点. (比如:7, 3,10 )
思路
(1
) 需求先去找到要删除的结点 targetNode
(2
) 找到 targetNode 的 父结点 parent
(3
) 确定 targetNode 是 parent 的左子结点 还是右子结点
(4
) 根据前面的情况来对应删除
左子结点 parent.left
= null
右子结点 parent.right
= null
;
思路
(1
) 需求先去找到要删除的结点 targetNode
(2
) 找到 targetNode 的 父结点 parent
(3
) 确定 targetNode 的子结点是左子结点还是右子结点
(4
) targetNode 是 parent 的左子结点还是右子结点
(5
) 如果 targetNode 有左子结点
5. 1 如果 targetNode 是 parent 的左子结点
parent.left
= targetNode.left
;
5.2 如果 targetNode 是 parent 的右子结点
parent.right
= targetNode.left
;
(6
) 如果 targetNode 有右子结点
6.1 如果 targetNode 是 parent 的左子结点
parent.left
= targetNode.right
;
6.2 如果 targetNode 是 parent 的右子结点
parent.right
= targetNode.right
思路
(1
) 需求先去找到要删除的结点 targetNode
(2
) 找到 targetNode 的 父结点 parent
(3
) 从 targetNode 的右子树找到最小的结点
(4
) 用一个临时变量,将 最小结点的值保存 temp
= 11
(5
) 删除该最小结点
(6
) targetNode.value
= temp
4.2、代码实现(完整)
public class BinarySortTreeDemo {
public static void main(String
[] args
) {
int[] arr
= {7,3,10,12,5,1,9,2};
BinarySortTree binarySortTree
= new BinarySortTree();
for (int i
= 0; i
< arr
.length
; i
++) {
Node node
= new Node(arr
[i
]);
binarySortTree
.add(node
);
}
System
.out
.println("中序遍历二叉排序树");
binarySortTree
.infixOrder();
binarySortTree
.delNode(2);
binarySortTree
.delNode(12);
binarySortTree
.delNode(3);
binarySortTree
.delNode(9);
binarySortTree
.delNode(7);
binarySortTree
.delNode(5);
binarySortTree
.delNode(10);
binarySortTree
.delNode(1);
binarySortTree
.infixOrder();
}
}
class BinarySortTree{
private Node root
;
public Node
search(int value
){
if (root
== null
){
return null
;
}else {
return root
.search(value
);
}
}
public Node
searchParent(int value
){
if (root
== null
){
return null
;
}else {
return root
.searchParent(value
);
}
}
public int delRightTreeMin(Node node
){
Node target
= node
;
while (target
.left
!= null
){
target
= target
.left
;
}
delNode(target
.value
);
return target
.value
;
}
public void delNode(int value
){
if (root
== null
){
return;
}else {
Node targetNode
= search(value
);
if (targetNode
== null
){
return;
}
if (root
.left
== null
&& root
.right
== null
){
root
= null
;
return;
}
Node parent
= searchParent(value
);
if (targetNode
.left
== null
&& targetNode
.right
== null
){
if ( parent
.left
!= null
&& targetNode
.value
== parent
.left
.value
){
parent
.left
= null
;
}else if (parent
.right
!= null
&& parent
.right
.value
== targetNode
.value
){
parent
.right
= null
;
}
}else if (targetNode
.left
!= null
&& targetNode
.right
!= null
){
int minVal
= delRightTreeMin(targetNode
.right
);
targetNode
.value
= minVal
;
}else {
if (targetNode
.left
!= null
){
if (parent
!= null
){
if (parent
.left
.value
== value
){
parent
.left
= targetNode
.left
;
}else {
parent
.right
= targetNode
.left
;
}
}else {
root
= targetNode
.left
;
}
}else {
if (parent
!= null
){
if (parent
.left
.value
== value
){
parent
.left
= targetNode
.right
;
}else {
parent
.right
= targetNode
.right
;
}
}else {
root
= targetNode
.right
;
}
}
}
}
}
public void add(Node node
){
if (root
== null
){
root
= node
;
}else {
root
.add(node
);
}
}
public void infixOrder(){
if (root
!= null
){
root
.infixOrder();
}else {
System
.out
.println("二叉树为空, 无法进行中序遍历~~");
}
}
}
class Node{
int value
;
Node left
;
Node right
;
public Node(int value
) {
this.value
= value
;
}
@Override
public String
toString() {
return "Node{" +
"value=" + value
+
'}';
}
public void add(Node node
){
if (node
== null
){
return;
}
if (node
.value
< this.value
){
if (this.left
== null
){
this.left
= node
;
}else {
this.left
.add(node
);
}
}else {
if (this.right
== null
){
this.right
= node
;
}else {
this.right
.add(node
);
}
}
}
public void infixOrder(){
if (this.left
!= null
){
this.left
.infixOrder();
}
System
.out
.println(this);
if (this.right
!= null
){
this.right
.infixOrder();
}
}
public Node
search(int value
){
if (value
== this.value
){
return this;
}else if (value
< this.value
){
if (this.left
== null
){
return null
;
}
return this.left
.search(value
);
}else {
if (this.right
== null
){
return null
;
}
return this.right
.search(value
);
}
}
public Node
searchParent(int value
){
if ((this.left
!= null
&& value
== this.left
.value
)||(this.right
!= null
&& value
== this.right
.value
)){
return this;
}else if (this.left
!= null
&& value
< this.value
){
return this.left
.searchParent(value
);
}else if (this.right
!= null
&& value
>= this.value
){
return this.right
.searchParent(value
);
}else {
return null
;
}
}
}