二叉排序树的介绍:
二叉排序树:BST: (Binary Sort(Search) Tree), 对于二叉排序树的 任何一个非叶子节点,要求 左子节点的值比当前节点的值小, 右子节点的值比当前节点的值大。
特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点。
比如针对前面的数据 (7, 3, 10, 12, 5, 1, 9) ,对应的二叉排序树为:
对删除结点的各种情况的思路分析:
第一种情况:删除叶子节点 (比如:2, 5, 9, 12)
思路:
(1) 需求先去找到要删除的结点 targetNode
(2) 找到 targetNode 的 父结点 parent
(3) 确定 targetNode 是 parent 的左子结点 还是右子结点
(4) 根据前面的情况来对应删除
左子结点 parent.left = null
右子结点 parent.right = null;
第二种情况: 删除只有一颗子树的节点 (比如 :1)
思路:
(1) 需要先去找到要删除的结点 targetNode
1.1 如果该节点只有一个左子节点
直接将左子节点的值赋值给父节点,然后删除左子节点
1.2 如果该节点只有一个右子节点
直接将右子节点的值赋值给父节点,然后删除右子节点
情况三 : 删除有两颗子树的节点. (比如:7, 3,10 )
思路:
(1) 需求先去找到要删除的结点 targetNode
(2) 找到 targetNode 的 父结点 parent
(3) 从 targetNode 的右子树找到最小的结点(也可以从左子树中找到最大的节点)
(4) 用一个临时变量,将最小结点的值保存 temp = 11
(5) 删除该最小结点
(6) targetNode.value = temp
先创建二叉排序树的节点对象:
public class Node {
public Integer value;
public Node left;
public Node right;
public Node(Integer 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;
return;
}
if (this.right == null){
this.right = node;
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);
}
}
}
//根据value寻找节点
public Node search(int value){
if (this.value == 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 && this.left.value == value) ||
(this.right != null && this.right.value == value) ){
return this;
}else {
//如果查找的值小于当前节点的值,而且当前节点有左子树
if (value < this.value && this.left != null){
return this.left.searchParent(value);//左递归
} else if (value > this.value && this.right != null) {
//如果查找的值大于当前节点的值,而且当前节点有右子树
return this.right.searchParent(value);//右递归
}else {
//没有找到父节点
return null;
}
}
}
//中序遍历
public void infixOrder(){
if (this.left != null){
this.left.infixOrder();
}
System.out.print(this.value + " ");
if (this.right != null){
this.right.infixOrder();
}
}
}
实现二叉排序树的基本操作:
package com.atguigu.binarySortTree;
/**
* 创建二叉排序树
*/
public class BinarySortTree {
private Node root;
//添加节点
public void add(Node node){
if (root == null){
root = node;
}else {
root.add(node);
}
}
//中序遍历
public void infixOrder(){
if (this.root == null){
System.out.println("二叉排序树为空");
}else {
this.root.infixOrder();
}
}
//搜索节点
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 void delete(int value){
Node temp;
if (root == null){
System.out.println("二叉排序树为空,无法删除");
return;
}
//先找到要删除的节点
temp = search(value);
//temp为null说明没找到
if (temp == null){
System.out.println("没有找到要删除的节点");
return;
}
//如果删除的节点没有子节点
if (temp.left == null && temp.right == null){
//找到当前节点的父节点
Node curParent = searchParent(temp.value);
//删除当前节点
if ( curParent.left != null && curParent.left.value == value){
curParent.left = null;
}else {
curParent.right = null;
}
}
//如果该节点只有一个左子节点
if (temp.left != null && temp.right == null){
//直接将左子节点的值赋值给父节点,然后删除左子节点
temp.value = temp.left.value;
temp.left = null;
}
//如果该节点只有一个右子节点
if (temp.left == null && temp.right != null){
//直接将右子节点的值赋值给父节点,然后删除右子节点
temp.value = temp.right.value;
temp.right = null;
}
//如果该节点有两个子节点
if (temp.left != null && temp.right != null){
//第一种方法:向右子树递归寻找出最小的节点权值,然后将该值赋给要删除的节点,再将找到的节点删除
//先将要删除的节点保存下来
Node targetNode = temp;
temp = temp.right;
while (true){
//找最小值要向左找
if (temp.left == null){
break;
}
temp = temp.left;
}
//找到权值最小的节点的父节点,就可以删除了
Node minParent = searchParent(temp.value);
//此时的temp就是找到的权值最小的节点
targetNode.value = temp.value;
//删除权值最小的节点
if (minParent == targetNode){
minParent.right = null;
}else {
minParent.left = null;
}
//第二种方法:向左子树递归寻找出最大的节点权值,然后将该值赋给要删除的节点,再将找到的节点删除,这里就不再实现了。
}
}
}
测试二叉排序树:
public class BinarySortTreeDemo {
public static void main(String[] args) {
//int[] arr = {76, 86, 33, 39, 85, 37, 12, 89, 99, 89, 94, 89, 39, 69, 25};
int[] arr = {7, 3, 10, 12, 5, 1, 9, 2};
//创建数组,将数组变成二叉排序树
//int[] arr = new int[15];
//创建二叉排序树
BinarySortTree binarySortTree = new BinarySortTree();
//随机生成0~100之间的数
for (int i = 0; i < arr.length; i++) {
//赋值
//arr[i] = (int) (Math.random() * 100);
//添加树的节点
binarySortTree.add(new Node(arr[i]));
}
System.out.println("遍历数组:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
System.out.println("中序遍历输出二叉排序树:");
binarySortTree.infixOrder();
//测试删除节点
System.out.println();
System.out.println("删除节点:");
binarySortTree.delete(5);
System.out.println("删除后再中序遍历:");
binarySortTree.infixOrder();
System.out.println();
System.out.println("删除节点:");
binarySortTree.delete(1);
System.out.println("删除后再中序遍历:");
binarySortTree.infixOrder();
System.out.println();
System.out.println("删除节点:");
binarySortTree.delete(10);
System.out.println("删除后再中序遍历:");
binarySortTree.infixOrder();
}
}