一、介绍
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。
对于二叉排序树的任何一个非叶子结点,要求左子结点的值比当前结点的值小,右子结点的值比当前结点的值大。
特别说明:如果有相同的值,可以将该节点放在左子结点或右子结点
例
定义一个数组int[] array = {7, 3, 10, 1, 5, 9, 12}
插入一个结点2
插入效果如图
二、插入结点
思路分析
- 遍历二叉排序树找到要插入的结点的父结点。
- 判断要插入的结点是父结点的左子结点还是右子结点。
- 将结点进行插入。
若二叉排序树是一个空树,则直接将其插入的结点定义为根节点
代码实现
Node 结点基础代码
/**
* 创建node节点
*/
class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{value=" + value + '}';
}
/**
* 添加结点
*
* @param node 结点
*/
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 indexOrder() {
if (this.left != null) {
this.left.indexOrder();
}
System.out.println(this);
if (this.right != null) {
this.right.indexOrder();
}
}
/**
* 查找当前值所在的结点
*
* @param value 要查找的值
* @return 找到则返回该结点,否则返回null
*/
public Node searchNode(int value) {
//若要搜索的值 == 当前值 返回该结点
if (value == this.value) {
return this;
} else if (value < this.value) {
//若要搜索的值 < 当前值 向左子树递归查找
if (this.left == null) {
return null;
}
return this.left.searchNode(value);
} else {
//若要搜索的值 >= 当前值 向右子树递归查找
if (this.right == null) {
return null;
}
return this.right.searchNode(value);
}
}
/**
* 查找当前值所在的结点的父节点
*
* @param value 要查找的值
* @return 找到则返回该结点,否则返回null
*/
public Node searchParentNode(int value) {
//若当前节点就是要删除结点的父节点,则返回
boolean flag = (this.left != null && this.left.value == value) || (this.right != null && this.right.value == value);
if (flag) {
return this;
}
//若查找的值 < 当前结点的值,而且当前结点的左子结点不为空 则向左子树递归查找
if (value < this.value && this.left != null) {
return this.left.searchParentNode(value);
}
//若查找的值 >= 当前结点的值,而且当前结点的右子结点不为空 则向右子树递归查找
else if (value >= this.value && this.right != null) {
return this.right.searchParentNode(value);
} else {
return null;
}
}
}
BinarySortTree代码
class BinarySortTree {
private Node root;
/**
* 添加结点
*
* @param node
*/
public void add(Node node) {
if (root == null) {
root = node;
} else {
root.add(node);
}
}
}
三、删除结点
思路分析
- 第一种情况:
删除叶子节点 (比如:2, 5, 9, 12)
思路
- 需求先去找到要删除的结点 targetNode
- 找到targetNode 的 父结点 parent
- 确定 targetNode 是 parent的左子结点 还是右子结点
- 根据前面的情况来对应删除
左子结点 parent.left = null
右子结点 parent.right = null;
- 第二种情况: 删除只有一颗子树的节点 比如 {1}
思路
- 需求先去找到要删除的结点 targetNode
- 找到targetNode 的 父结点 parent
- 确定targetNode 的子结点是左子结点还是右子结点
- targetNode 是 parent 的左子结点还是右子结点
- 如果targetNode 有左子结点
5.1 如果 targetNode 是 parent 的左子结点
parent.left = targetNode.left;
5.2 如果 targetNode 是 parent 的右子结点
parent.right = targetNode.left; - 如果targetNode 有右子结点
6.1 如果 targetNode 是 parent 的左子结点
parent.left = targetNode.right;
6.2 如果 targetNode 是 parent 的右子结点
parent.right = targetNode.right
- 第三种情况 : 删除有两颗子树的节点. (比如:7,3,10 )
思路
- 需求先去找到要删除的结点 targetNode
- 找到targetNode 的 父结点 parent
- 从targetNode 的右子树找到最小的结点
- 用一个临时变量,将 最小结点的值保存 temp = 11
- 删除该最小结点
- targetNode.value = temp
代码实现
/**
* 创建二叉排序树
*/
class BinarySortTree {
/**
* 删除结点
*
* @param value
*/
public void deleteNode(int value) {
if (root == null) {
return;
}
// 1.先去找到要删除的结点 targetNode
Node targetNode = searchNode(value);
//判断targetNode有没有找到要删除的结点
if (targetNode == null) {
System.out.println("未找到要删除的结点");
return;
}
// 2.当前二叉排序树中只有根节点,将根节点删除即可
if (root.left == null && root.right == null) {
root = null;
return;
}
// 3.去找targetNode的父节点
Node parentNode = searchParentNode(value);
// 4.判断要删除的结点的类型
// 4.1 若删除的结点时叶子节点
if (targetNode.left == null && targetNode.right == null) {
// 判断当前结点是父节点的左子结点还是右子结点
// 4.1.1 当前结点时父节点的左子结点
if (parentNode.left != null && parentNode.left.value == value) {
parentNode.left = null;
}
// 4.1.1 当前结点时父节点的右子结点
else if (parentNode.right != null && parentNode.right.value == value) {
parentNode.right = null;
}
}
// 4.2 若删除的结点有两棵树
else if (targetNode.left != null && targetNode.right != null) {
// 4.2.1 删除最小值所在的结点
int minVal = delRightTreeMin(targetNode.right);
// 4.2.2 将最小值给当前结点
targetNode.value = minVal;
}
// 4.3 若删除的结点有一颗树
else {
// 4.3.1 若要删除的结点只有左子结点
if (targetNode.left != null) {
//未找到父节点
if (parentNode == null) {
root = targetNode.left;
return;
}
// 4.3.1.1 若targetNode 是parent的左子结点
if (parentNode.left.value == value) {
parentNode.left = targetNode.left;
}
// 4.3.1.2 若targetNode 是parent的右子结点
else {
parentNode.right = targetNode.left;
}
}
// 4.3.2 若要删除的结点只有右子结点
else if (targetNode.right != null) {
//未找到父节点
if (parentNode == null) {
root = targetNode.right;
return;
}
// 4.3.2.1 若targetNode 是parent的左子结点
if (parentNode.left.value == value) {
parentNode.left = targetNode.right;
}
// 4.3.2.2 若targetNode 是parent的右子结点
else {
parentNode.right = targetNode.right;
}
}
}
}
/**
* 删除右节点的最小值
*
* @return 被删除结点的最小值
*/
public int delRightTreeMin(Node node) {
Node target = node;
//循环查找左子结点,就会找到最小值
while (target.left != null) {
target = target.left;
}
//删除最小值
deleteNode(target.value);
return target.value;
}
/**
* 查找要删除的结点
*/
private Node searchNode(int value) {
if (root != null) {
return root.searchNode(value);
}
return null;
}
/**
* 查找要删除的结点的父节点
*/
private Node searchParentNode(int value) {
if (root != null) {
return root.searchParentNode(value);
}
return null;
}
}