• 哈希表的前置知识---二叉搜索树


    二叉搜索树

    概念

    二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 :
    • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
    • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
    • 它的左右子树也分别为二叉搜索树

       

    代码实现

    结点静态内部类

    1. public class BinarySearchTree {
    2. static class TreeNode {
    3. public int key;
    4. public TreeNode left;
    5. public TreeNode right;
    6. public TreeNode(int key) {
    7. this.key = key;
    8. }
    9. }
    10. public TreeNode root;
    11. }

    插入-- insert

    1. public boolean insert(int key) {
    2. if(this.root == null) {
    3. this.root = new TreeNode(key);
    4. return true;
    5. }
    6. TreeNode cur = this.root;
    7. TreeNode parent = null;
    8. //找到插入位置的父亲
    9. while(cur != null) {
    10. if(cur.key < key) {
    11. parent = cur;
    12. cur = cur.right;//往右走
    13. } else if(cur.key > key) {
    14. parent = cur;
    15. cur = cur.left;//往左走
    16. } else {
    17. //不能插入相同的元素
    18. return false;
    19. }
    20. }
    21. TreeNode node = new TreeNode(key);
    22. if(key > parent.key) {
    23. parent.right = node;
    24. } else {
    25. parent.left = node;
    26. }
    27. return true;
    28. }

    图解


      查找-- search

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

    查找函数相对比较简单,就是个二分查找。


    删除-- remove (难点)

    1. public boolean remove(int key) {
    2. TreeNode cur = root;
    3. TreeNode parent = null;
    4. while(cur != null) {
    5. if(cur.key > key) {
    6. parent = cur;
    7. cur = cur.left;
    8. } else if(cur.key < key) {
    9. parent = cur;
    10. cur = cur.right;
    11. } else {
    12. removeNode(parent, cur);
    13. return true;
    14. }
    15. }
    16. return false;
    17. }
    18. private void removeNode(TreeNode parent, TreeNode cur) {
    19. //1.左为空 2.右为空 3.都不为空
    20. if(cur.left == null) {
    21. if(cur == root) {
    22. root = cur.right;
    23. } else if(cur == parent.right) {
    24. parent.right = cur.right;
    25. } else {
    26. parent.left = cur.right;
    27. }
    28. } else if(cur.right == null) {
    29. if(cur == root) {
    30. root = cur.left;
    31. }else if(cur == parent.left) {
    32. parent.left = cur.left;
    33. } else {
    34. parent.right = cur.left;
    35. }
    36. } else {
    37. TreeNode targetParent = cur;
    38. TreeNode target = cur.right;
    39. //可以在待删除结点的左子树找一个最大值将其覆盖,也可以在待删除结点的右子树找一棵最小的值将其覆盖,最后删除替罪羊
    40. while(target.left != null) {
    41. targetParent = target;
    42. target = target.left;
    43. }
    44. cur.key = target.key;
    45. //判断替罪羊是targetParent的左孩子还是右孩子
    46. if(target == targetParent.left) {
    47. targetParent.left = target.right;
    48. } else {
    49. targetParent.right = target.right;
    50. }
    51. }
    52. }

    思路

    分情况讨论:设待删除结点为 cur ,待删除结点为 parent

    1.cur.left == null

    • cur == root
    • cur == parent.left
    • ccur == parent.right

    2.cur.right == null

    • cur == root
    • cur == parent.left;
    • cur == parent.right

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

    • 替换法(难点)

    画图解释替换法!

    情况二和情况一类似

     替换法

     替换法分析

    当带删除元素key有左右孩子的时候,直接把key删除是不现实的,因为你根本不知到key下面的结构是什么,就算知道,调整起来也无从下手,所以我们需要借助替换法来实现,既可以选择key的左子树中的最大值进行替换,也可以选择key的右子树中最小值进行替换,因为这样才能保证二叉搜索树的结构不被破坏。


    检查插入 / 删除后是否还是一棵二叉搜索树-- 中序遍历

    下图中序遍历的结果为:0,1,2,3,4,5,6,7,8,9

     代码实现

    1. public List<Integer> inOrder(TreeNode root) {
    2. List<Integer> list = new ArrayList<>();
    3. if(root == null) {
    4. return list;
    5. }
    6. List<Integer> left = inOrder(root.left);
    7. list.addAll(left);//左
    8. list.add(root.key);//中
    9. List<Integer> right = inOrder(root.right);
    10. list.addAll(right);//右
    11. return list;
    12. }

    咱们在对二叉搜索树进行CURD操作时,就可以通过调用中序遍历的调试和打印来判断是否正确!

    本期博客就到这里了,下期再见!!!

  • 相关阅读:
    「贪心笔记」通过最少操作次数使得数组的和相等
    IPKISS i3.PCell 模块
    10.5 认识XEDParse汇编引擎
    解决WPF+Avalonia在openKylin系统下默认字体问题
    单窗口单IP适合炉石传说游戏么?
    数据的处理包括哪些内容
    QList类迭代器详解
    (六)centos7案例实战——sonarQube安装及springboot项目集成sonarQube完成代码质量检查
    kworker隔离绑定
    剑指 Offer II 092. 翻转字符 / 剑指 Offer II 093. 最长斐波那契数列
  • 原文地址:https://blog.csdn.net/xaiobit_hl/article/details/125461081