• 一文搞懂——搜索树


    目录

    1.搜索树的定义

    2.插入操作

    3.查找操作

    4.删除操作

    5.性能分析

    6.完整代码


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

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

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

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

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

    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
                    1. cur 是 root ,则 root = cur.right
                    2. cur 不是 root cur parent.left ,则 parent.left = cur.right
                    3. cur 不是 root cur parent.right ,则 parent.right = cur.right
            2. cur.right == null
                    1. cur 是 root ,则 root = cur.left
                    2. cur 不是 root cur parent.left ,则 parent.left = cur.left
                    3. cur 不是 root cur parent.right ,则 parent.right = cur.left
            3. cur.left != null && cur.right != null
            需要使用替换法 进行删除,即在它的右子树中寻找中序下的第一个结点 ( 关键码最小 ) ,用它的值填补到被删除节点中,再来处理该结点的删除问题。
    1. public void remove(int v){
    2. Node cur = root;
    3. Node parent = null;
    4. while(cur != null){
    5. if(cur.val == v){
    6. removeNode(cur,parent);
    7. break;
    8. }else if(cur.val > v){
    9. parent = cur;
    10. cur = cur.left;
    11. }else {
    12. parent = cur;
    13. cur = cur.right;
    14. }
    15. }
    16. }
    17. public void removeNode(Node cur,Node parent){
    18. if(cur.left == null){
    19. if(cur == root){
    20. root = cur.right;
    21. }else if(cur == parent.left){
    22. parent.left = cur.right;
    23. }else{
    24. parent.right = cur.right;
    25. }
    26. }else if(cur.right == null){
    27. if(cur == root){
    28. root = cur.left;
    29. }else if(cur == parent.left){
    30. parent.left = cur.left;
    31. }else {
    32. parent.right = cur.left;
    33. }
    34. }else {
    35. Node targetParent = cur;
    36. Node target = cur.right;
    37. while(target.left != null){
    38. targetParent = target;
    39. target = target.left;
    40. }
    41. cur.val = target.val;
    42. if(target == targetParent.left){
    43. targetParent.left = target.right;
    44. }else {
    45. targetParent.right = target.right;
    46. }
    47. }
    48. }

    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. }

    运行结果:

     

  • 相关阅读:
    .NET混合开发解决方案7 WinForm程序中通过NuGet管理器引用集成WebView2控件
    网络安全漏洞分析之远程代码执行
    Linux 学习笔记(5-6)
    QClipboard
    Qt之Windows Server 2012 R2不支持openssl
    Linux 网络之ss
    远程工作面临减薪,该何去何从?谷歌员工陷入焦虑
    wininet,winhttp,xmlhttprequest,各版本区别 《转》
    mac系统安装搭载Windows系统虚拟机方法教程
    mysql中的三大日志
  • 原文地址:https://blog.csdn.net/m0_57950108/article/details/127776071