简介
二叉搜索树(BST)又称二叉查找树、二叉排序树,它或为一棵空树,或满足以下定义:
❶ 若左子树非空,则左子树上的所有结点的值都小于根结点的值
❷ 若右子树非空,则右子树上的所有结点的值都大于根结点的值
❸ 左、右子树也分别是一棵二叉搜索树
❹ 中序遍历的结果是一个递增的有序序列(重要性质)
二叉搜索树实现的功能有:
① 节点定义
② 插入结点
③ 构建二叉树
④ 中序遍历
⑤ 查找
⑥ 返回整棵树的最大最小值
⑦ 返回某个结点的直接前驱/直接后继
⑧ 删除结点(难点)
节点定义
二叉树都这么写 >_<
class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(){}
public TreeNode(int val) {
this.val = val;
}
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
插入结点
非常优美的递归写法!如果比根结点小则插入到左子树,如果比根结点大则插入到右子树。
private void insert(TreeNode root, int val) {
if (root == null) {
root = new TreeNode(val);
}
if (val < root.val) {
insert(root.left, val);
} else {
insert(root.right, val);
}
}
构建二叉树
调用上面的插入结点操作即可!
private void build(int[] arr) {
for (int i = 0; i < arr.length; i++) {
insert(root, arr[i]);
}
}
中序遍历
中序遍历的结果是一个递增的有序序列!
private void inOrder(TreeNode root) {
if (root != null) {
inOrder(root.left);
System.out.println(root.val);
inOrder(root.right);
}
}
查找
将二叉搜索树的结构性质体现的淋漓尽致!如果比根结点小则查左子树,如果比根结点大则查右子树,并递归进行。
private boolean search(TreeNode root, int target) {
if (root == null) {
return false;
}
if (root.val == target) {
return true;
}
if (target < root.val) {
return search(root.left, target);
} else {
return search(root.right, target);
}
}
private TreeNode searchNode(TreeNode root, int target) {
if (root == null) {
return null;
}
if (root.val == target) {
return root;
}
if (target < root.val) {
return searchNode(root.left, target);
} else {
return searchNode(root.right, target);
}
}
返回整棵树的最大最小值
查最小值,就是一直走左孩子直到尽头;查最大值,就是一直走右孩子直到尽头。
private TreeNode getMin(TreeNode root) {
if (root == null) {
return null;
}
if (root.left == null) {
return root;
} else {
return getMin(root.left);
}
}
private TreeNode getMax(TreeNode root) {
if (root == null) {
return null;
}
if (root.right == null) {
return root;
} else {
return getMax(root.right);
}
}
返回某个结点的直接前驱/直接后继
private TreeNode getPrecursor(TreeNode root, TreeNode node) {
if (node == null) {
return null;
}
if (root.left != null) {
// 如果左子树不为空,则直接前驱为左子树的最大值
return getMax(root.left);
} else {
// 如果左子树为空,则直接前驱为祖先,一直向上找直到祖先出现在左上
TreeNode precursor = getParentNode(root, node);
while (precursor != null && precursor.left == node) {
node = precursor;
precursor = getParentNode(root, node);
}
return precursor;
}
}
private TreeNode getSuccessor(TreeNode root, TreeNode node) {
if (node == null) {
return null;
}
if (root.right != null) {
// 如果右子树不为空,则直接后继为右子树的最小值
return getMin(root.right);
} else {
// 如果右子树为空,则直接后继为祖先,一直向上找直到祖先出现在右上
TreeNode successor = getParentNode(root, node);
while (successor != null && successor.right == node) {
node = successor;
successor = getParentNode(root, node);
}
return successor;
}
}
删除结点(难点)
private void delete(TreeNode root, int target) {
TreeNode deleteNode = searchNode(root, target);
TreeNode parentNode = getParentNode(root, deleteNode);
if (deleteNode.left == null && deleteNode.right == null) {
// 如果被删除结点是叶子结点,则直接删除
if (parentNode.left == deleteNode) {
parentNode.left = null;
} else {
parentNode.right = null;
}
} else if (deleteNode.left != null && deleteNode.right == null) {
// 如果被删除结点只有左子树,则让左子树直接替代被删除结点,即子承父业
if (parentNode.left == deleteNode) {
parentNode.left = deleteNode.left;
} else {
parentNode.right = deleteNode.left;
}
} else if (deleteNode.left == null && deleteNode.right != null) {
// 如果被删除结点只有右子树,则让右子树直接替代被删除结点,即子承父业
if (parentNode.left == deleteNode) {
parentNode.left = deleteNode.right;
} else {
parentNode.right = deleteNode.right;
}
} else {
// 如果被删除结点有左右两棵子树,则被删除结点的值被其直接后继(直接前驱)结点的值取代,并转换为对直接后继(直接前驱)结点的删除
TreeNode successor = getSuccessor(root, deleteNode);
delete(root, deleteNode.val);
deleteNode.val = successor.val;
}
}
☘️