二叉排序树
二叉排序树: (Binary Sort Tree),对于二叉排序树的任何一个非叶子节点,要求左子节点的值小于等于当前节点的值,右子节点的值大于等于当前节点的值。
将序列 {7, 3, 10, 12, 5, 1, 9, 2} 构造成而二叉排序树举例说明:
添加操作
步骤:
- 添加 7 :7 作为根结点
- 添加 3 :3 比 7 小且 7 的左子节点为空,作为 7 的左子节点
- 添加 7 :10 比 7 大且 7 的右子节点为空,作为 7 的右子节点
- 添加 7 :12 比 7 大,又比 10 大且 10 的右子节点为空,作为 10 的右子节点
- 添加 7 :5 比 7 小,放在 7 的左边,又比 3 大且 3 的右子节点为空,作为 3 的右子节点
- 添加 7 :1 比 7 小,放在 7 的左边,又比 3 小且 3 的左子节点为空,作为 3 的左子节点
- 添加 7 :9 比 7 大,放在 7 的右边,又比 10 小且 10 的左子节点为空,作为 10 的左子节点。
- 添加 7 :2 比 7 小,放在 7 的左边,又比 3 小,放在 3 的左边,又比 1 大且 1 的右子节点为空,作为 1 的右子节点。
删除操作
二叉排序树的删除情况比较复杂,有下面三种情况需要考虑
-
删除叶子节点(比如:2, 5, 9, 12)
(1) 需求先去找到要删除的结点 targetNode
(2) 找到 targetNode 的父结点 targetparentNode
(3) 如果 targetNode 是 targetparentNode 的左子结点就 targetparentNode.left = null,如果是右子结点就 targetparentNode.right = null -
删除只有一颗子树的节点(比如: 1)
2.1 先找到要删除的结点 targetNode
2.2 找到 targetNode 的父结点 targetparentNode
2.3 确定 targetNode 的子结点是左子结点还是右子结点
2.4 targetNode 是 targetparentNode 的左子结点还是右子结点
2.5 如果 targetNode 的子结点是左子结点:
2.5.1 如果 targetNode 是 targetparentNode 的左子结点 targetparentNode.left = targetNode.left
2.5.2 如果 targetNode 是 targetparentNode 的右子结点 targetparentNode.right = targetNode.left
2.6 如果 targetNode 的子结点是右子结点
2.6.1 如果 targetNode 是 targetparentNode 的左子结点targetparentNode.left = targetNode.right
2.6.2如果 targetNode 是 targetparentNode 的右子结点 targetparentNode.right = targetNode.right -
删除有两颗子树的节点.(比如:7, 3,10 )
3.1 先找到要删除的结点 targetNode
3.2 找到 targetNode 的父结点 targetparentNode
3.3 从 targetNode 的右子树找到最小的结点
3.4 删除该最小结点并将值赋值给 targetNode.value
结点
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return 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 Node search(int value) {
if (this.value == value) {
return this;
} else if (value < this.value) { // 左子树递归查找
if (this.left != null) {
return this.left.search(value);
} else { // 找不到该结点
return null;
}
} else { // 右子树递归查找
if (this.right != null) {
return this.right.search(value);
} else { // 找不到该结点
return null;
}
}
}
// 查找要删除的结点的父节点
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);
if (this.right != null) {
this.right.infixOrder();
}
}
}
二叉排序树
class BinarySortTree {
private Node root;
// 向二叉排序树中添加结点法
public void add(Node node) {
if (root != null) {
root.add(node);
} else {
root = node;
}
}
// 查找要删除的结点
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);
}
}
/**
* @description: 删除右子树最小的结点
* @Param: node 以 node 为根节点的树中最小的值
*/
public int delRightTreeMin(Node node) {
Node temp = node;
while (temp.left != null) { // 找最小的值
temp = temp.left;
}
delNode(temp.value); // 删除这个最小的结点
return temp.value; // 返回这个最小的结点的 value
}
// 删除结点
public void delNode(int value) {
if (root == null) {
return;
}
// 不是空树
// 找到要删除的结点
Node targeNode = search(value);
// 如果没有找到要删除的结点
if (targeNode == null) {
return;
}
// 如果要删除的结点是唯一的结点
if (root.left == null && root.right == null) {
root = null;
return;
}
// 找到要删除的结点的父节点
Node targeParentNode = searchParent(value);
// 如果要删除的结点是叶子结点
if (targeNode.left == null && targeNode.right == null) {
if (targeParentNode.left == targeNode) { // 如果要删除的结点是左子结点
targeParentNode.left = null;
} else { // 如果要删除的结点是右子结点
targeParentNode.right = null;
}
} else if (targeNode.left != null && targeNode.right != null) { // 如果要删除的结点有两个子结点
// 此处当前结点替换为右子树中最小值并删除右子树中最小值,也可以替换为左子树中最大值并删除左子树最大值
targeNode.value = delRightTreeMin(targeNode.right);
} else { // 如果要删除的结点只有一个子结点
// 如果删除的结点只有左子树
if (targeNode.left != null) {
if (targeParentNode == null) { // 如果是根结点, 直接移动根结点
root = targeNode.left;
return;
}
if (targeParentNode.left == targeNode) { // 如果该结点是父节点的左结节点
targeParentNode.left = targeNode.left;
} else { // 如果该结点是父节点的右结节点
targeParentNode.right = targeNode.left;
}
} else { // 如果删除的结点只有右子树
if (targeParentNode == null) { // 如果是根结点, 直接移动根结点
root = targeNode.right;
return;
}
if (targeParentNode.left == targeNode) { // 如果该结点是父节点的左结节点
targeParentNode.left = targeNode.right;
} else { // 如果该结点是父节点的右结节点
targeParentNode.right = targeNode.right;
}
}
}
}
// 中序遍历
public void infixOrder() {
if (root != null) {
root.infixOrder();
} else {
System.out.println("空树");
}
}
}
二叉排序树演示
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++) {
binarySortTree.add(new Node(arr[i]));
}
/* 该二叉排序树大致如下
7
* *
3 10
* * * *
1 5 9 12
*
2
*/
System.out.println("-------------------中序遍历--------------------");
binarySortTree.infixOrder();
System.out.println();
// 删除叶子结点
binarySortTree.delNode(12);
System.out.println("---------------删除叶子结点 12 -----------------");
binarySortTree.infixOrder();
System.out.println();
// 删除只有一个子结点的结点
binarySortTree.delNode(1);
System.out.println("------------删除只有一个子结点的结点 1 -----------");
binarySortTree.infixOrder();
System.out.println();
// 删除有两个子结点的结点
binarySortTree.delNode(3);
System.out.println("------------删除有两个子结点的结点 3 -------------");
binarySortTree.infixOrder();
System.out.println();
// 删除根结点
binarySortTree.delNode(7);
System.out.println("---------------删除根结点 7 -------------------");
binarySortTree.infixOrder();
System.out.println();
// 全部删除
binarySortTree.delNode(2);
binarySortTree.delNode(5);
binarySortTree.delNode(9);
binarySortTree.delNode(10);
System.out.println("----------------全部删除-----------------------");
binarySortTree.infixOrder();
}
}
运行结果
-----------------中序遍历------------------
1 2 3 5 7 9 10 12
-----------------删除叶子结点 12 ------------------
1 2 3 5 7 9 10
-----------------删除只有一个子结点的结点 1 ------------------
2 3 5 7 9 10
-----------------删除有两个子结点的结点 3 ------------------
2 5 7 9 10
-----------------删除根结点 7 ------------------
2 5 9 10
-----------------全部删除------------------
空树