二叉排序树定义
一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
【注】:以上的三种定义在不同的数据结构教材中均有不同的定义方式 但是都是正确的 在开发时需要根据不 同的需求进行选择
删除节点策略
removeA():
当待删除的节点有左右子树时,将其左子树加入到右子节点,其右子节点作为 parent的新子树
removeB():
当待删除的节点有左右子树时,将右子树的最小节点(也可以选左子树的最大节点)作为 parent的新子节点
Java代码
这里使用了lombok插件支持
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
// 测试类,removeA()
class TestA {
public static void main(String[] args) {
Integer[] a = new Integer[]{6, 4, 9, 7, 2, 5, 3, 8, 1, 0};
BinarySortTree<Integer> sortTree = new BinarySortTree<>(a);
sortTree.infixOrder();
System.out.println("sortTree = " + sortTree);
for (Integer integer : a) {
System.out.println("removeA = " + integer);
// 输出根节点
sortTree.removeA(integer);
sortTree.infixOrder();
System.out.println("sortTree = " + sortTree);
}
}
}
// 测试类,removeb()
class TestB {
public static void main(String[] args) {
Integer[] a = new Integer[]{6, 4, 9, 7, 2, 5, 3, 8, 1, 0};
BinarySortTree<Integer> sortTree = new BinarySortTree<>(a);
sortTree.infixOrder();
System.out.println("sortTree = " + sortTree);
for (Integer integer : a) {
sortTree.removeB(integer);
System.out.println("removeB = " + integer);
sortTree.infixOrder();
System.out.println("sortTree = " + sortTree);
}
}
}
/**
* Desc: 二叉排序树
*
* @author pikachu
* @date: 2022/8/19 11:21
*/
@Data
@NoArgsConstructor
public class BinarySortTree<E extends Comparable<E>> {
private Node root;
public BinarySortTree(E[] data) {
for (E item : data) {
add(item);
}
}
/**
* Desc: 添加新元素 data
*
* @author pikachu
*/
public void add(E data) {
if (root == null) {
root = new Node<>(data);
} else {
root.add(new Node<>(data));
}
}
/**
* Desc: 移除元素data(如果存在)
*
* @param data 待移除的元素
* @author pikachu
*/
public void removeA(E data) {
if (root == null) {
System.out.println("Tree is empty");
} else {
root.removeA(root, new Node<>(data));
}
}
/**
* Desc:
*
* @param data 待移除的元素
* @author pikachu
*/
public void removeB(E data) {
if (root == null) {
System.out.println("Tree is empty");
} else {
root.removeB(root, new Node<>(data));
}
}
/**
* Desc: 中序遍历该子树(从小到大输出)
*
* @author pikachu
*/
public void infixOrder() {
if (root == null) {
System.out.println("Tree is empty");
} else {
root.infixOrder();
System.out.println();
}
}
@Override
public String toString() {
return root == null ? "Tree is empty" : "root : " + root.data;
}
@Data
private class Node<E extends Comparable<E>> {
private Node<E> left;
private Node<E> right;
private E data;
private Node(E data) {
this.data = data;
}
/**
* Desc: 将 node加入到当前节点 this
*
* @param node 待加入节点
* @author pikachu
*/
private void add(Node<E> node) {
if (node.data.compareTo(this.data) <= 0) {
if (this.left != null) {
this.left.add(node);
} else {
this.left = node;
}
} else {
if (this.right != null) {
this.right.add(node);
} else {
this.right = node;
}
}
}
/**
* Desc:移除preNode的子树中的node节点(如果存在),
* 当待删除的节点有左右子树时,将其左子树加入到右子节点,其右子节点作为 parent的新子树
*
* @param parent 当前节点的父节点
* @param delNode 待移除的节点
* @author pikachu
*/
private void removeA(Node parent, Node delNode) {
// 1.delNode < this,往左子树查找删除;若左子树为空则结束
if (delNode.data.compareTo(this.data) < 0) {
if (this.left != null) {
this.left.removeA(this, delNode);
}
}
// 2.delNode > this,往右子树查找删除;若右子树为空则结束
else if (delNode.data.compareTo(this.data) > 0) {
if (this.right != null) {
this.right.removeA(this, delNode);
}
}
// 3.delNode = this 找到待删除的节点 this
else if (delNode.data.compareTo(this.data) == 0) {
// 3.1 this.right不为空,以this.right为新子树的根节点,将不为空的this.left加入该子树
if (this.right != null) {
if (this.left != null) {
this.right.add(this.left);
}
// 3.1.1 待删除节点 this为 parent 左子节点
if (parent.left == this) {
parent.left = this.right;
}
// 3.1.2 待删除节点 this为 parent 右子节点
else if (parent.right == this) {
parent.right = this.right;
}
// 3.1.3 删除树中的根节点
else {
root = this.right;
}
}
// 3.2 this.right为空,类推
else {
if (parent.left == this) {
parent.left = this.left;
} else if (parent.right == this) {
parent.right = this.left;
} else {
root = this.left;
}
}
}
}
/**
* Desc:移除preNode的子树中的node节点(如果存在),
* 当待删除的节点有左右子树时,将右子树的最小节点作为 parent的新子节点
*
* @param parent 当前节点的父节点
* @param delNode 待删除节点
* @author pikachu
*/
private void removeB(Node<E> parent, Node<E> delNode) {
// 1.delNode < this,往左子树查找删除;若左子树为空则结束
if (delNode.data.compareTo(this.data) < 0) {
if (this.left != null) {
this.left.removeB(this, delNode);
}
}
// 2.delNode > this,往右子树查找删除;若右子树为空则结束
else if (delNode.data.compareTo(this.data) > 0) {
if (this.right != null) {
this.right.removeB(this, delNode);
}
}
// 3.delNode = this 找到待删除的节点 this
else if (delNode.data.compareTo(this.data) == 0) {
// 3.1 this.right不为空,在 this.right的子树中寻找最小节点 rightMinNode,作为新子树的根节点
if (this.right != null) {
Node<E> preNode = this;
Node<E> rightMinNode = preNode.right;
while (rightMinNode.left != null) {
preNode = rightMinNode;
rightMinNode = rightMinNode.left;
}
//
if (preNode.right != rightMinNode) {
preNode.left = rightMinNode.right;
} else {
preNode.right = preNode.right.right;
}
this.data = rightMinNode.data;
}
// 3.2 this.right为空
else {
if (this == parent.right) {
parent.right = this.left;
} else if (this == parent.left) {
parent.left = this.left;
}
// 3.2.1 删除树中根节点
else {
root = root.left;
}
}
}
}
/**
* Desc:
* 中序遍历二叉排序树后刚好从小到大输出
*
* @author pikachu
*/
private void infixOrder() {
if (this.left != null) {
this.left.infixOrder();
}
System.out.print(this.data + " -> ");
if (this.right != null) {
this.right.infixOrder();
}
}
@Override
public String toString() {
return this.data.toString();
}
}
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class Emp implements Comparable<Emp> {
private int no;
private String name;
@Override
public int compareTo(Emp o) {
return this.no - o.no;
}
}
运行测试
若存在疏漏,欢迎指正。