• 二叉搜索树的基本操作 || TreeMap和TreeSet介绍


    目录

    前言:

    二叉搜索树的插入

    代码实现

    二叉搜索树的查找

    代码实现

    二叉搜索树的删除

    代码实现

    TreeMap介绍

    源码展现

     TreeSet介绍

    源码展现

     小结:


    前言:

    😄现在很多地方都需要去查找某个数据,那么查找的效率就显得尤为重要了。二叉搜索树是一颗左孩子比父亲小,右孩子比父亲大的一棵树。那么在这个基础上查找某个数据,一次比较就可以排除一半数据,效率是相当高的。

    二叉搜索树的插入

    😯拿到一个数据,首先判断根节点是否为空,如果为空就往根节点处插入。否则依次向下比较,比它大就往右走,比它小都往左走。直到走到叶子节点,就可以插入了。这个时候需记录这个叶子节点,然后去判断往右边还是左边插入数据。

    代码实现

    1. public boolean insert(int val) {
    2. if(root == null) {
    3. TreeNode newNode = new TreeNode(val);
    4. root = newNode;
    5. return true;
    6. }
    7. TreeNode cur = root;
    8. TreeNode prev = null;
    9. while(cur != null) {
    10. if(val > cur.val) {
    11. prev = cur;
    12. cur = cur.right;
    13. }else if(val < cur.val) {
    14. prev = cur;
    15. cur = cur.left;
    16. }else {
    17. return false;
    18. }
    19. }
    20. //最终可能在左面和右面插入
    21. TreeNode newNode = new TreeNode(val);
    22. if(val < prev.val) {
    23. prev.left = newNode;
    24. }else {
    25. prev.right = newNode;
    26. }
    27. return true;
    28. }

    二叉搜索树的查找

    😃定义cur去遍历二叉树。首先判断cur处位置的val值是否和需查找值一致,如果一致则直接返回这个节点,否则就去判断cur该往左还是右走。如果cur为空,则说明二叉树遍历完成,也没有找到目标值,返回null。

    代码实现

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

    二叉搜索树的删除

    🎈我们可以想到要删除树中的某一个节点,需连将这个节点的上一个节点和下一个节点连接起来。所以定义前后指针prev,cur去遍历树。当cur找到后去删除这个节点。

    🎈删除树中的某一个节点,如果这个节点的左右都不为空,或者这个节点的左树为空,又或者这个节点的右树为空。它们的删除方法都不相同。因此我们将这些可能都枚举出来,逐个去判断。

    🎈左树为空的情况,如果要删除的节点为根节点,直接调整根节点为它的右子树。如果要删除的节点在上一个节点的右边,直接连接上一个节点的right到这个节点的right。如果要删除的节点在上一个节点的左边,连接上一个节点left到这个节点的right。

    🎈右树为空的情况,如果要删除的节点为根节点,直接调整根节点为它的左子树。如果要删除的节点在上一个节点的右边,直接连接上一个节点的right到这个节点的left。如果要删除的节点在上一个节点的左边,连接上一个节点left到这个节点的left。

    🎈如果要删除节点的左右都不为空,不论怎样去连接都会打破树的结构,因此提出替罪羊式删除法。在这个节点左树中找到最大值,或者右树中找到最小值,就可以替换这个节点的值,保证这颗树依然维持二叉搜索树的结构特点。那么就只需要删除左树中的最大值或者右树中的最小值(替罪羊)。当在右树中找到最小的值,替换完成后。删除这个节点时,这个节点可能在上一个节点的左边,也可能在右边(右树只有一个节点)。在左边就直接连接上一个节点的left到这个节点right。在右边就直接连接上一个节点right到这个节点的right。

    代码实现

    1. public boolean remove(int val) {
    2. TreeNode cur = root;
    3. TreeNode prev = null;
    4. while(cur != null) {
    5. if(val > cur.val) {
    6. prev = cur;
    7. cur = cur.right;
    8. }else if(val < cur.val) {
    9. prev = cur;
    10. cur = cur.left;
    11. }else {
    12. removeNode(prev, cur);
    13. return true;
    14. }
    15. }
    16. return false;
    17. }
    18. private void removeNode(TreeNode prev, TreeNode cur) {
    19. //删除分为三种情况
    20. //左树为空 右树为空 左右树都不为空
    21. if(cur.left == null) {
    22. //可能删除根节点 可能删除prev的右节点 可能删除prev的左节点
    23. if(cur == root) {
    24. root = root.right;
    25. }else if(cur == prev.right) {
    26. prev.right = cur.right;
    27. }else {
    28. prev.left = cur.right;
    29. }
    30. }else if(cur.right == null) {
    31. if(cur == root) {
    32. root = root.left;
    33. }else if(cur == prev.right) {
    34. prev.right = cur.left;
    35. }else {
    36. prev.left = cur.left;
    37. }
    38. }else {
    39. //替罪羊式删除法
    40. //左树中找最大的/右树中找最小的
    41. //就可以替换要被删除的元素,接下来只需删除左面最大或者右面最小的节点
    42. TreeNode target = cur.right;
    43. TreeNode targetParent = cur;
    44. while(target.left != null) {
    45. targetParent = target;
    46. target = target.left;
    47. }
    48. cur.val = target.val;
    49. //最终要删除的节点可能在targetParent左和右
    50. if(target == targetParent.left) {
    51. targetParent.left = target.right;
    52. }else {
    53. targetParent.right = target.right;
    54. }
    55. }
    56. }

    TreeMap介绍

    🪖TreeMap的底层是一颗红黑树,红黑树是建立在二叉搜索树结构上的。由于搜索树在极端情况下它的单分支会很长,这样就会增加查找的效率。在这个基础上提出的AVL树,将它的单分支进行旋转。由于可能旋转的次数会很多,又在这个基础上提出了红黑树。

    🪖TreeMap中数据存储,是按照键值对的方式去存储(key - val)。由于搜索树中不会存在相同的数据,即TreeMap中的key是唯一的。如果插入相同的key会更新其原来key的val值,那么相应的key是不可以修改的,但是val值可以修改。

    🪖TreeMap是实现map接口的,相对于Iterable接口这个接口是独立的。可以调用entrySet方法将TreeMap中的(key - val)取出来为Entry类型,存储到set集合当中去组织。也可以调用keySet或者values方法可以单独将key或者val取出来,分别存储到set集合或者collection集合当中去组织。

    🪖由于TreeMap底层是红黑树,那么它的key是必须具有比较性。如果提供比较器优先调用比较器,否则实现Comparable接口重写compareTo方法。key不能为null,因为null无法比较,否则会抛NullPointerException异常。

    源码展现

     

     

     

     TreeSet介绍

    🤞TreeSet只存储key。它底层是用TreeMap实现的,只是所有的val值都是Object对象。TreeSet是实现set接口的,它是在Iterable接口下。

    🤞那么相应的TreeSet底层也是红黑树,key值也就是唯一的,不可以添加相同的key。它的key也需具有可比较性。TreeSet具有天然去重的功能。

    源码展现

     

     

     

     

     小结:

    🐵在学习一些集合时,我们在理解的基础上可以去看一些源码,这样也会加深对其的理解性。

  • 相关阅读:
    原生JS实现视频截图
    若依前后端分离项目部署
    详解设计模式:简单工厂模式
    哪些因素取决于产品设计中的质量?
    QT不同子类间共享变量,教你简单、规范的方法
    如何用Xshell向Linux服务器上传文件//使用xshell通过串口传送数据,直接使用第五部就可以了,自己测试OK
    天锐绿盾 | 如何防止开发部门源代码泄露、外泄?
    Allegro基本规则设置指导书之Same Net Spacing规则设置
    Bit.Store:熊市漫漫,稳定Staking产品或成主旋律
    Redis -- Nosql
  • 原文地址:https://blog.csdn.net/weixin_62353436/article/details/127419371