一文搞懂——搜索树

小灰灰 2024-04-01 16:48 149阅读 0赞

目录

1.搜索树的定义

2.插入操作

3.查找操作

4.删除操作

5.性能分析

6.完整代码


二叉搜索树又称为二叉排序树,它具有以下性质

1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

3.它的左右子树也为二叉搜索树

以下就是一个二叉搜索树,每个节点的左节点小于父亲节的,右节点大于父亲节点。

0741d2a1f38e4477a5e5fd406b950c32.png

1.搜索树的定义

  1. class Node{
  2. public int val;
  3. public Node left;
  4. public Node right;
  5. public Node(int val){
  6. this.val = val;
  7. }
  8. }

2.插入操作

首先判断根节点是否为空,为空直接添加,不为空的话就利用“每个节点的左节点小于父亲节的,右节点大于父亲节点”这个特点进行判断,并进行插入。

  1. public boolean insert(int v){
  2. if(root == null){
  3. root = new Node(v);
  4. return true;
  5. }
  6. Node parent = null;
  7. Node cur = root;
  8. while(cur != null){
  9. if(cur.val > v){
  10. parent = cur;
  11. cur = cur.left;
  12. }else if (cur.val == v){
  13. return false;//不能有相同的数据
  14. }else {
  15. parent = cur;
  16. cur = cur.right;
  17. }
  18. }
  19. Node node = new Node(v);
  20. if(parent.val > v){
  21. parent.left = node;
  22. }else if(parent.val < v){
  23. parent.right = node;
  24. }
  25. return true;
  26. }

3.查找操作

对于某个元素的查找,利用“每个节点的左节点小于父亲节的,右节点大于父亲节点”,进行判断,直至找到目标节点。

  1. public Node Serach(int v){
  2. Node cur = root;
  3. while(cur != null) {
  4. if (cur.val > v) {
  5. cur = cur.left;
  6. } else if (cur.val == v) {
  7. return cur;
  8. } else {
  9. cur = cur.right;
  10. }
  11. }
  12. return null;
  13. }

4.删除操作

删除操作情况及其复杂。

设待删除结点为 cur, 待删除结点的双亲结点为 parent

  1. cur.left == null

  2. cur 是 root ,则 root = cur.right

  3. cur 不是 root , cur 是 parent.left ,则 parent.left = cur.right

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

  5. cur.right == null

  6. cur 是 root ,则 root = cur.left

  7. cur 不是 root , cur 是 parent.left ,则 parent.left = cur.left

  8. cur 不是 root , cur 是 parent.right ,则 parent.right = cur.left

  9. cur.left != null && cur.right != null

    需要使用替换法 进行删除,即在它的右子树中寻找中序下的第一个结点 ( 关键码最小 ) ,用它的值填补到被删除节点中,再来处理该结点的删除问题。

    public void remove(int v){

    1. Node cur = root;
    2. Node parent = null;
    3. while(cur != null){
    4. if(cur.val == v){
    5. removeNode(cur,parent);
    6. break;
    7. }else if(cur.val > v){
    8. parent = cur;
    9. cur = cur.left;
    10. }else {
    11. parent = cur;
    12. cur = cur.right;
    13. }
    14. }
    15. }
    16. public void removeNode(Node cur,Node parent){
    17. if(cur.left == null){
    18. if(cur == root){
    19. root = cur.right;
    20. }else if(cur == parent.left){
    21. parent.left = cur.right;
    22. }else{
    23. parent.right = cur.right;
    24. }
    25. }else if(cur.right == null){
    26. if(cur == root){
    27. root = cur.left;
    28. }else if(cur == parent.left){
    29. parent.left = cur.left;
    30. }else {
    31. parent.right = cur.left;
    32. }
    33. }else {
    34. Node targetParent = cur;
    35. Node target = cur.right;
    36. while(target.left != null){
    37. targetParent = target;
    38. target = target.left;
    39. }
    40. cur.val = target.val;
    41. if(target == targetParent.left){
    42. targetParent.left = target.right;
    43. }else {
    44. targetParent.right = target.right;
    45. }
    46. }
    47. }

5.性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

最优情况:二叉搜索树为完全二叉树,其平均比较次数为 log(2)(N);

最差情况:二叉搜索树为单支树,其平均比较次数为 N/2。

6.完整代码

  1. //节点定义
  2. class Node{
  3. public int val;
  4. public Node left;
  5. public Node right;
  6. public Node(int val){
  7. this.val = val;
  8. }
  9. }
  10. public class BinarySearchTree {
  11. public Node root = null;
  12. //搜索操作
  13. public Node Serach(int v){
  14. Node cur = root;
  15. while(cur != null) {
  16. if (cur.val > v) {
  17. cur = cur.left;
  18. } else if (cur.val == v) {
  19. return cur;
  20. } else {
  21. cur = cur.right;
  22. }
  23. }
  24. return null;
  25. }
  26. //插入操作
  27. public boolean insert(int v){
  28. if(root == null){
  29. root = new Node(v);
  30. return true;
  31. }
  32. Node parent = null;
  33. Node cur = root;
  34. while(cur != null){
  35. if(cur.val > v){
  36. parent = cur;
  37. cur = cur.left;
  38. }else if (cur.val == v){
  39. return false;//不能有相同的数据
  40. }else {
  41. parent = cur;
  42. cur = cur.right;
  43. }
  44. }
  45. Node node = new Node(v);
  46. if(parent.val > v){
  47. parent.left = node;
  48. }else if(parent.val < v){
  49. parent.right = node;
  50. }
  51. return true;
  52. }
  53. //删除操作
  54. public void remove(int v){
  55. Node cur = root;
  56. Node parent = null;
  57. while(cur != null){
  58. if(cur.val == v){
  59. removeNode(cur,parent);
  60. break;
  61. }else if(cur.val > v){
  62. parent = cur;
  63. cur = cur.left;
  64. }else {
  65. parent = cur;
  66. cur = cur.right;
  67. }
  68. }
  69. }
  70. //删除操作的具体实现
  71. public void removeNode(Node cur,Node parent){
  72. if(cur.left == null){
  73. if(cur == root){
  74. root = cur.right;
  75. }else if(cur == parent.left){
  76. parent.left = cur.right;
  77. }else{
  78. parent.right = cur.right;
  79. }
  80. }else if(cur.right == null){
  81. if(cur == root){
  82. root = cur.left;
  83. }else if(cur == parent.left){
  84. parent.left = cur.left;
  85. }else {
  86. parent.right = cur.left;
  87. }
  88. }else {
  89. Node targetParent = cur;
  90. Node target = cur.right;
  91. while(target.left != null){
  92. targetParent = target;
  93. target = target.left;
  94. }
  95. cur.val = target.val;
  96. if(target == targetParent.left){
  97. targetParent.left = target.right;
  98. }else {
  99. targetParent.right = target.right;
  100. }
  101. }
  102. }
  103. //中序遍历
  104. public void inOrder(Node root){
  105. if(root == null) return;
  106. inOrder(root.left);
  107. System.out.print(root.val+" ");
  108. inOrder(root.right);
  109. }
  110. }

测试用例:

  1. public static void main(String[] args) {
  2. int[] array = {10,8,19,3,9,4,7};
  3. BinarySearchTree binarySearchTree = new BinarySearchTree();
  4. for (int i = 0;i < array.length;i++){
  5. binarySearchTree.insert(array[i]);
  6. }
  7. binarySearchTree.inOrder(binarySearchTree.root);
  8. System.out.println();
  9. Node node = binarySearchTree.Serach(8);
  10. System.out.println(node.val);
  11. binarySearchTree.insert(15);
  12. binarySearchTree.inOrder(binarySearchTree.root);
  13. System.out.println();
  14. binarySearchTree.remove(9);
  15. binarySearchTree.inOrder(binarySearchTree.root);
  16. }

运行结果:

74d3413e640b4dc78ba06a6112bb2c03.png

发表评论

表情:
评论列表 (有 0 条评论,149人围观)

还没有评论,来说两句吧...

相关阅读

    相关 static(

    一、聊一聊static与JVM Java 把内存分为栈内存和堆内存,其中栈内存用来存放一些基本类型的变量、数组和对象的引用,堆内存主要存放一些对象。在 JVM 加载一个类的

    相关 ThreadPoolExecutor

    前言 线程池是Java中使用较多的并发框架,合理使用线程池,可以:降低资源消耗,提高响应速度,提高线程的可管理性。 本篇文章将从线程池简单原理,线程池的创建,线程池执行

    相关 Raft 算法

    一文搞懂Raft算法 正文 raft是工程上使用较为广泛的强一致性、去中心化、高可用的分布式协议。在这里强调了是在工程上,因为在学术理论界,最耀眼的还是大名鼎鼎的Pax

    相关 DDD

    最近看了很多和DDD相关的内容,这篇文章对DDD做一个总结,希望可以通过这篇文章不但知道什么是DDD,而且还可以知道如何实施DDD 一、什么是DDD DDD(领域驱动设