当前位置:   article > 正文

【二叉搜索(排序)树】——一种高效查找的数据结构(清晰图解)_树查找算法 图解

树查找算法 图解

目录

二叉搜索树的概念及特点

一、二叉搜索树的构建及操作

1. 查找

2. 插入

3. 删除(重点)

二、性能分析及与Java类集的关系


二叉搜索树的概念及特点

二叉搜索树(Binary Search Tree,BST)又称二叉排序树,是一种常见的数据结构,它具有以下特点:

  1. 每个节点最多有两个子节点,分别称为左子节点和右子节点。
  2. 对于树中的任意节点,其左子树上所有节点的值都小于它的值,而右子树上所有节点的值都大于它的值。即它的左右子树也分别为二叉搜索树。
  3. 中序遍历二叉搜索树可以得到一个升序排列的序列。

由于以上特性,二叉搜索树常被用于实现动态集合的数据结构,其中查找、插入和删除操作的平均时间复杂度为 O(log n),其中 n 为树中节点的数量。

这些特性使得二叉搜索树在实际应用中非常有用,比如在数据库中用于索引、在编程语言中用于实现关联容器等。然而,需要注意的是,当二叉搜索树呈现不平衡状态时,其操作的时间复杂度可能会退化为 O(n),因此对于保持平衡和高效性能有一些其他的变体,比如 AVL树 (平衡二叉搜索树)、红黑树等。


一、二叉搜索树的构建及操作

二叉搜索树有三大主要操作:插入、查找和删除。它们的平均时间复杂度都为 O(log n),其中 n 为树中节点的数量。 

很显然二叉搜索树是一颗二叉树,根据所需操作及其数据结构,我们先列出代码整体结构:

  1. public class BinarySearchTree {
  2. public static class TreeNode {
  3. public int val;
  4. public TreeNode left;
  5. public TreeNode right;
  6. public TreeNode(int val) {
  7. this.val = val;
  8. }
  9. }
  10. public TreeNode root;
  11. //查找结点
  12. public TreeNode search(int val) {
  13. }
  14. //插入结点
  15. public boolean insert(int val) {
  16. }
  17. //删除结点
  18. public boolean remove(int val) {
  19. }
  20. //中序遍历二叉搜索树
  21. public void inorder(TreeNode root) {
  22. if (root == null) {
  23. return;
  24. }
  25. inorder(root.left);
  26. System.out.print(root.val + " ");
  27. inorder(root.right);
  28. }
  29. }

成员变量root为根节点。

根据前面二叉搜索树的特点,我们能够实现二叉树的三大操作。其中查找和插入比较简单,删除操作作为难点,分为多种情况。


1. 查找

若根节点(root)不为空:

        1.如果root的值==查找值,返回root。

        2.如果root的值 > 查找值,往左子树找。

        3.如果root的值 < 查找值,往右子树找。

若根节点(root)为空或遍历到null还没找到:

        返回null

代码如下:
  1. //查找结点
  2. public TreeNode search(int val) {
  3. TreeNode cur = root;
  4. while (cur != null) {
  5. if (val < cur.val) {
  6. cur = cur.left;
  7. } else if (val > cur.val) {
  8. cur = cur.right;
  9. } else {
  10. return cur;
  11. }
  12. }
  13. return null;
  14. }

2. 插入

如果树为空树,即根(root) == null,直接插入。
如果树不是空树:
        按照查找逻辑确定插入位置(相等不插入,返回),插入新结点。
        需同时记录当前遍历到结点的父节点(初始为null),最后根据父节点进行插入。
注意点:二叉搜索树的插入操作只会插入到当前为null的孩子结点。

代码如下:

  1. //插入结点
  2. public boolean insert(int val) {
  3. if (root == null) {
  4. root = new TreeNode(val);
  5. return true;
  6. }
  7. TreeNode parent = null;
  8. TreeNode cur = root;
  9. while (cur != null) {
  10. parent = cur;
  11. if (val < cur.val) {
  12. cur = cur.left;
  13. } else if (val > cur.val) {
  14. cur = cur.right;
  15. } else {
  16. return false;//相等不插入
  17. }
  18. }
  19. //循环走完,cur为null,cur的位置就是要插入的位置
  20. //判断cur在parent左边还是右边
  21. if (val < parent.val) {
  22. parent.left = new TreeNode(val);
  23. } else {
  24. parent.right = new TreeNode(val);
  25. }
  26. return true;
  27. }

3. 删除(重点)

设待删除结点为 cur, 待删除结点的双亲结点为 parent:
三种情况,每个情况又对应三种子情况
        1.cur.left == null
        2.cur.right == null
        3.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

1.3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.right

 下面这三种情况和前面三种非常相似,就不再画图了,自己画图更容易理解。

2.cur.right == null

        2.1. cur 是 root,则 root = cur.left
        2.2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left
        2.3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.left

3. cur.left != null && cur.right != null
        需要使用替换法进行删除。要想使以cur为根的子树删除cur后还满足二叉搜索树,需要找到一个结点值是比cur的左子树所有结点都大,比cur的右子树所有结点都小的值。有两个方案:
        3.1.在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题 —— 右子树找最小结点
        

        3.2.在它的左子树中寻找中序下的第一个结点(关键码最大),用它的值填补到被删除节点中,再来处理该结点的删除问题 —— 左子树找最大结点。
        

代码如下:

  1. //删除结点
  2. public boolean remove(int val) {
  3. TreeNode cur = root;
  4. TreeNode parent = null;
  5. while (cur != null) {
  6. if (val < cur.val) {
  7. parent = cur;
  8. cur = cur.left;
  9. } else if (val > cur.val) {
  10. parent = cur;
  11. cur = cur.right;
  12. } else {
  13. removeNode(parent, cur);//删除结点
  14. return true;
  15. }
  16. }
  17. //找不到该结点
  18. return false;
  19. }
  20. private void removeNode(TreeNode parent, TreeNode cur) {
  21. //三种情况:1.待删除结点cur.left为空
  22. // :2.cur.right为空
  23. // :3.cur的左右都不为空
  24. if (cur.left == null) {
  25. if (cur == root) {
  26. root = cur.right;
  27. } else if (cur == parent.left) {
  28. parent.left = cur.right;
  29. } else {
  30. parent.right = cur.right;
  31. }
  32. } else if (cur.right == null) {
  33. if (cur == root) {
  34. root = cur.left;
  35. } else if (cur == parent.left) {
  36. parent.left = cur.left;
  37. } else {
  38. parent.right = cur.left;
  39. }
  40. } else {
  41. //cur左右都不为空 找cur的 左树最大值 或 右树最小值 与cur进行替换
  42. //找左树最大值
  43. //findMaxOfLeftTree(cur);
  44. //找右树最小值
  45. findMinOfRightTree(cur);
  46. }
  47. }
  48. //找右树最小值
  49. private void findMinOfRightTree(TreeNode cur) {
  50. TreeNode node = cur.right;
  51. TreeNode p = cur;
  52. while (node.left != null) {
  53. p = node;
  54. node = node.left;
  55. }
  56. cur.val = node.val;
  57. //删除node 此时判断node是p的左树还是右树
  58. if (node == p.left) {
  59. p.left = node.right;
  60. } else {
  61. p.right = node.right;
  62. }
  63. }
  64. //找左树最大值
  65. private void findMaxOfLeftTree(TreeNode cur) {
  66. TreeNode node = cur.left;
  67. TreeNode p = cur;
  68. //找左树最大值(左树最右结点)
  69. while (node.right != null) {
  70. p = node;
  71. node = node.right;
  72. }
  73. cur.val = node.val;//替换
  74. //删除node 此时判断node是p的左结点还是右结点
  75. if (node == p.right) {
  76. p.right = node.left;
  77. } else {//没有结点
  78. p.left = node.left;
  79. }
  80. }

二、性能分析及与Java类集的关系

前面说过,二叉搜索树查找、插入和删除操作的平均时间复杂度都为 O(log n)。

1. 分析:

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有 n 个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:可能是完全二叉树,也有可能是单分支的一棵树。
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log2N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2
如果退化成单支树,二叉搜索树的性能就失去了,其操作的时间复杂度可能会退化为 O(n)。因此为了保持平衡和高效性能,就有了基于二叉搜索树的变体:AVL 树、红黑树等。
2. 与Java类集的关系:
TreeMap 和 TreeSet 即 Java 中利用搜索树实现的 Map 和 Set;实际上用的是红黑树,而红黑树是一棵近似平衡的 二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证。 因此,二叉搜索树是一种重要且用途广泛的数据结构。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/783349
推荐阅读
相关标签
  

闽ICP备14008679号