• 二叉搜索树


    目录

    二叉搜索树

    操作-查找

    操作-插入

    操作-删除

    性能分析


    二叉搜索树

    二叉搜索树又称二叉排序树,它要么是一棵空树,要么是具有以下性质的二叉树:

    • 若它的左子树不为空,则左子树上所有结点的值都小于根节点的值
    • 若它的右子树不为空,则右子树上所有结点的值都大于根节点的值
    • 它的左右子树也分别为二叉搜索树

    如图就是一棵二叉搜索树.

    下面,我们来实现几个二叉搜索树的操作.

    操作-查找

    查找val是否在当前搜索树当中,根据二叉搜索树的特点,如果根节点的val == 查找val,则直接返回根节点;如果根节点的val > 查找val,就去根节点的左子树里去找;如果根节点的val < 查找的val,就去根节点的右子树里去找,以此类推,没找到就返回null.

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

    操作-插入

    1. public boolean insert(int key){
    2. //根节点为空,就直接插入到根节点的位置
    3. if (root == null){
    4. root = new TreeNode(key);
    5. return true;
    6. }
    7. //parent用来记录cur的prev
    8. TreeNode parent = null;
    9. TreeNode cur = root;
    10. //cur==null就说明要进行插入了
    11. while(cur != null){
    12. //当前节点的值大于key,就往当前节点的左子树走
    13. if (cur.val > key){
    14. parent = cur;
    15. cur = cur.left;
    16. }else if (cur.val < key){
    17. parent = cur;
    18. cur = cur.right;
    19. }else {
    20. //插入相同的元素直接返回false
    21. return false;
    22. }
    23. }
    24. //代码走到这里cur==null
    25. //此时比较key和parent的val大小来判断
    26. //往左子树插入还是右子树插入
    27. TreeNode node = new TreeNode(key);
    28. if (parent.val > key){
    29. parent.left = node;
    30. }else {
    31. parent.right = node;
    32. }
    33. return true;
    34. }

    操作-删除

    删除的逻辑比较复杂,分为多种情况.

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

    1.cur.left == null

    • cur是root,则root = cur.right
    • cur不是root,cur是parent的left.则parent.left=cur.right
    • cur不是root,cur是parent.right,则parent.right=cur.right

    2.cur.right == null

    • cur是root,则root = cur.left
    • cur不是root,cur是parent的right,则parent.right=cur.left
    • cur不是root,cur是parent的left,则parent.left = cur.left

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

    此种情况,要使用替罪羊法进行删除.即在它的右子树中找到最左边的结点(cur右边最小的结点)或者是在它的左子树中找到最右边的结点(cur左边最大的结点),用找到的值来填补到待删除结点中,此时问题就转换为删除替罪结点了.

    比如要删除12.我们要找到9或者是13来代替12,然后在将9或者13删除掉.

    因为9或者13的特殊性,9没有右子树,13没有左子树,所有9或者13的删除就可以使用前两种情况.

    1. public void remove(int key){
    2. TreeNode parent = null;
    3. TreeNode cur = root;
    4. while(cur != null){
    5. if (cur.val == key){
    6. removeNode(parent,cur);
    7. return;
    8. }else if (cur.val < key){
    9. parent = cur;
    10. cur = cur.right;
    11. }else {
    12. parent = cur;
    13. cur = cur.left;
    14. }
    15. }
    16. }
    17. private void removeNode(TreeNode parent,TreeNode cur){
    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. TreeNode target = cur.right;
    36. TreeNode targetParent = cur;
    37. while (target.left != null){
    38. targetParent = target;
    39. target = target.left;
    40. }
    41. cur.val = target.val;
    42. if (targetParent.left == target){
    43. targetParent.left = target.right;
    44. }else {
    45. //待删除节点的右边可能没有左子树
    46. //此时cur.right就是替罪羊
    47. targetParent.right = target.right;
    48. }
    49. }
    50. }

    性能分析

    最优情况下,二叉搜索树为完全二叉树,其平均比较次数为logN

    最坏情况下,二叉搜索树退化为单支树,其平均比较次数为N/2

  • 相关阅读:
    Mysql中校对集utf8_unicode_ci与utf8_general_ci的区别
    火车卖票---Ticketer类
    PMP最新考纲难在哪里?面对新教材的来袭,我该怎么计划考试?
    对某钓鱼样本分析
    代码随想录图论 第二天 | 695. 岛屿的最大面积 1020. 飞地的数量
    Qt获取屏幕(桌面)的大小或分辨率
    Go语言网络编程(socket编程)WebSocket编程
    MySQL索引&事务
    Linux搭建我的世界MC服务器 【Minecraft外网联机教程】
    【毕业设计】基于javaEE+SSH+SqlServer的商品供应管理系统设计与实现(毕业论文+程序源码)——商品供应管理系统
  • 原文地址:https://blog.csdn.net/m0_62360856/article/details/132792456