赞
踩
目录
二叉搜索树(Binary Search Tree,BST)又称二叉排序树,是一种常见的数据结构,它具有以下特点:
由于以上特性,二叉搜索树常被用于实现动态集合的数据结构,其中查找、插入和删除操作的平均时间复杂度为 O(log n),其中 n 为树中节点的数量。
这些特性使得二叉搜索树在实际应用中非常有用,比如在数据库中用于索引、在编程语言中用于实现关联容器等。然而,需要注意的是,当二叉搜索树呈现不平衡状态时,其操作的时间复杂度可能会退化为 O(n),因此对于保持平衡和高效性能有一些其他的变体,比如 AVL树 (平衡二叉搜索树)、红黑树等。
二叉搜索树有三大主要操作:插入、查找和删除。它们的平均时间复杂度都为 O(log n),其中 n 为树中节点的数量。
很显然二叉搜索树是一颗二叉树,根据所需操作及其数据结构,我们先列出代码整体结构:
- public class BinarySearchTree {
- public static class TreeNode {
- public int val;
- public TreeNode left;
- public TreeNode right;
-
- public TreeNode(int val) {
- this.val = val;
- }
- }
-
- public TreeNode root;
-
- //查找结点
- public TreeNode search(int val) {
-
- }
-
- //插入结点
- public boolean insert(int val) {
-
- }
-
- //删除结点
- public boolean remove(int val) {
-
- }
-
- //中序遍历二叉搜索树
- public void inorder(TreeNode root) {
- if (root == null) {
- return;
- }
- inorder(root.left);
- System.out.print(root.val + " ");
- inorder(root.right);
- }
- }
成员变量root为根节点。
根据前面二叉搜索树的特点,我们能够实现二叉树的三大操作。其中查找和插入比较简单,删除操作作为难点,分为多种情况。
若根节点(root)不为空:
1.如果root的值==查找值,返回root。
2.如果root的值 > 查找值,往左子树找。
3.如果root的值 < 查找值,往右子树找。
若根节点(root)为空或遍历到null还没找到:
返回null
- //查找结点
- public TreeNode search(int val) {
- TreeNode cur = root;
- while (cur != null) {
- if (val < cur.val) {
- cur = cur.left;
- } else if (val > cur.val) {
- cur = cur.right;
- } else {
- return cur;
- }
- }
- return null;
- }
如果树为空树,即根(root) == null,直接插入。如果树不是空树:按照查找逻辑确定插入位置(相等不插入,返回),插入新结点。需同时记录当前遍历到结点的父节点(初始为null),最后根据父节点进行插入。注意点:二叉搜索树的插入操作只会插入到当前为null的孩子结点。
代码如下:
- //插入结点
- public boolean insert(int val) {
- if (root == null) {
- root = new TreeNode(val);
- return true;
- }
- TreeNode parent = null;
- TreeNode cur = root;
- while (cur != null) {
- parent = cur;
- if (val < cur.val) {
- cur = cur.left;
- } else if (val > cur.val) {
- cur = cur.right;
- } else {
- return false;//相等不插入
- }
- }
- //循环走完,cur为null,cur的位置就是要插入的位置
- //判断cur在parent左边还是右边
- if (val < parent.val) {
- parent.left = new TreeNode(val);
- } else {
- parent.right = new TreeNode(val);
- }
- return true;
- }
设待删除结点为 cur, 待删除结点的双亲结点为 parent:三种情况,每个情况又对应三种子情况1.cur.left == null2.cur.right == null3.cur.left != null && cur.right != null
1.cur.left == null
1.1 cur 是 root,则 root = cur.right
1.2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
下面这三种情况和前面三种非常相似,就不再画图了,自己画图更容易理解。
2.cur.right == null
代码如下:
- //删除结点
- public boolean remove(int val) {
- TreeNode cur = root;
- TreeNode parent = null;
- while (cur != null) {
- if (val < cur.val) {
- parent = cur;
- cur = cur.left;
- } else if (val > cur.val) {
- parent = cur;
- cur = cur.right;
- } else {
- removeNode(parent, cur);//删除结点
- return true;
- }
- }
- //找不到该结点
- return false;
- }
-
- private void removeNode(TreeNode parent, TreeNode cur) {
- //三种情况:1.待删除结点cur.left为空
- // :2.cur.right为空
- // :3.cur的左右都不为空
- if (cur.left == null) {
- if (cur == root) {
- root = cur.right;
- } else if (cur == parent.left) {
- parent.left = cur.right;
- } else {
- parent.right = cur.right;
- }
- } else if (cur.right == null) {
- if (cur == root) {
- root = cur.left;
- } else if (cur == parent.left) {
- parent.left = cur.left;
- } else {
- parent.right = cur.left;
- }
- } else {
- //cur左右都不为空 找cur的 左树最大值 或 右树最小值 与cur进行替换
-
- //找左树最大值
- //findMaxOfLeftTree(cur);
- //找右树最小值
- findMinOfRightTree(cur);
- }
- }
-
- //找右树最小值
- private void findMinOfRightTree(TreeNode cur) {
- TreeNode node = cur.right;
- TreeNode p = cur;
- while (node.left != null) {
- p = node;
- node = node.left;
- }
- cur.val = node.val;
- //删除node 此时判断node是p的左树还是右树
- if (node == p.left) {
- p.left = node.right;
- } else {
- p.right = node.right;
- }
- }
-
- //找左树最大值
- private void findMaxOfLeftTree(TreeNode cur) {
- TreeNode node = cur.left;
- TreeNode p = cur;
- //找左树最大值(左树最右结点)
- while (node.right != null) {
- p = node;
- node = node.right;
- }
- cur.val = node.val;//替换
- //删除node 此时判断node是p的左结点还是右结点
- if (node == p.right) {
- p.right = node.left;
- } else {//没有结点
- p.left = node.left;
- }
- }
前面说过,二叉搜索树查找、插入和删除操作的平均时间复杂度都为 O(log n)。
1. 分析:
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。对有 n 个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:可能是完全二叉树,也有可能是单分支的一棵树。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。