• 【数据结构】二分搜索树


    目录

    一、二分搜索树

    1.1什么是二分搜索树

    1.2创建一个二分搜索树

    (1)二分搜索树的内部构建

    (2)插入操作

    (3)判断一个val值是否存在

     (4)按照节点的深度先序遍历打印BST

     (5)关于最小值

    (6)关于最大值

    (7)删除任意结点


    HashMap底层基于哈希表(数组+链表)的实现。

    TreeMap底层基于二分搜索平衡树的实现(BeeTree)。

    一、二分搜索树

    1.1什么是二分搜索树

    右基础BST没有结构上的特点,他是一个二叉树,每个结点的值大于其左右左子树的结点值,小于其右子树的结点值,左子树<树根<右子树。

    存储的元素必须具备可比较性。

    (1)二分搜索树的中序遍历:能得到一个完全升序的数组(有序数组)

    (2)在BST查找一个元素是否存在,其实就是一个二分查找,时间复杂度为O(logn)走到空树还没找到,说明该元素不存在。BST在实际的生产工作中有着广泛应用。

    1.2创建一个二分搜索树

    (1)二分搜索树的内部构建

    和正常的二叉树是相通的,创建一个size来记录长度,root作为根节点。

    然后TreeNode类中有val表示该节点的值,left表示左子树,right表示右子树。

    1. public class MyBinarySearchTree {
    2. private int size;
    3. private TreeNode root;
    4. private static class TreeNode{
    5. int val;
    6. TreeNode left ;
    7. TreeNode right;
    8. public TreeNode(int val) {
    9. this.val = val;
    10. }
    11. }
    12. }

    (2)插入操作

    插入之后的新节点一定是叶子结点,不断比较当要插入的值和树根的大小关系,不断走左右子树,如果值比左子树小就走左子树,值比右子树大就走右子树。直到走到null,就构造新节点放入带插入元素的值。

    1. public void add(int val){
    2. root = add(root,val);
    3. }
    4. private TreeNode add(TreeNode root, int val) {
    5. if(root==null){
    6. size++;
    7. return new TreeNode(val);
    8. }
    9. if(val>root.val){
    10. root.right = add(root.right,val);
    11. }
    12. if(val
    13. root.left = add(root.left,val);
    14. }
    15. return root;
    16. }

    (3)判断一个val值是否存在

     判断则创建一个递归,两个终止条件当走到最后root==null,则证明这个二叉搜索树中不包含该val值,则返回false。另一种是当root.val == val,则找到了这个该元素返回true即可。

    然后如果值比左子树小就递归左子树,值比右子树大就递归右子树。

    1. public Boolean contains(int val){
    2. return contains(root,val);
    3. }
    4. private Boolean contains(TreeNode root, int val) {
    5. if(root==null){
    6. return false;
    7. }
    8. if(root.val == val){
    9. return true;
    10. }
    11. if(val
    12. return contains(root.left,val);
    13. }else{
    14. return contains(root.right,val);
    15. }
    16. }
    1. public static void main(String[] args) {
    2. MyBinarySearchTree bst = new MyBinarySearchTree();
    3. bst.add(41);
    4. bst.add(28);
    5. bst.add(58);
    6. bst.add(15);
    7. System.out.println(bst.contains(58));
    8. System.out.println(bst.contains(22));
    9. }

     (4)按照节点的深度先序遍历打印BST

    主要就是运用二叉树的先序遍历,然后再根据深度加上--。

    1. public String toString() {
    2. StringBuilder sb = new StringBuilder();
    3. generateBSTSting(root,0,sb);
    4. return sb.toString();
    5. }
    6. private void generateBSTSting(TreeNode root, int depth, StringBuilder sb) {
    7. if(root==null){
    8. sb.append(generateHeightString(depth)).append("NULL\n");
    9. return ;
    10. }
    11. sb.append(generateHeightString(depth)).append(root.val).append("\n");
    12. generateBSTSting(root.left,depth+1,sb);
    13. generateBSTSting(root.right,depth+1,sb);
    14. }
    15. private String generateHeightString(int depth){
    16. StringBuilder sb = new StringBuilder();
    17. for (int i = 0; i < depth; i++) {
    18. sb.append("--");
    19. }
    20. return sb.toString();
    21. }
    1. public static void main(String[] args) {
    2. MyBinarySearchTree bst = new MyBinarySearchTree();
    3. bst.add(41);
    4. bst.add(28);
    5. bst.add(58);
    6. bst.add(15);
    7. bst.add(33);
    8. bst.add(50);
    9. System.out.println(bst.toString());
    10. }

     (5)关于最小值

    最小值位于左子树的最左侧,一路向左走,碰到第一个root.left == null的结点,root即为最小值结点。输出最小值时直接返回该root即可。

    如果是删除最小值,那么就需要创建一个TreeNode类型的right存储root.right然后将root.left = root = null,再将树的结点个数size--最后返回right。

    1. public int min(){
    2. if (size == 0) {
    3. throw new NoSuchElementException("bst is empty!no min");
    4. }
    5. TreeNode min = findMinNode(root);
    6. return min.val;
    7. }
    8. public int removeMin(){
    9. if (size == 0) {
    10. throw new NoSuchElementException("bst is empty!cannot removeMin");
    11. }
    12. TreeNode minNode = findMinNode(root);
    13. root = removeMin(root);
    14. return minNode.val;
    15. }
    16. private TreeNode removeMin(TreeNode root) {
    17. if(root.left==null){
    18. TreeNode right = root.right;
    19. root.left = root.right = root = null;
    20. size--;
    21. return right;
    22. }
    23. root.left = removeMin(root.left);
    24. return root;
    25. }
    26. private TreeNode findMinNode(TreeNode root) {
    27. if(root.left==null){
    28. return root;
    29. }
    30. return findMinNode(root.left);
    31. }
    1. public static void main(String[] args) {
    2. MyBinarySearchTree bst = new MyBinarySearchTree();
    3. bst.add(41);
    4. bst.add(28);
    5. bst.add(58);
    6. bst.add(15);
    7. bst.add(33);
    8. bst.add(50);
    9. System.out.println(bst.toString());
    10. System.out.println(bst.removeMin());
    11. System.out.println(bst.min());
    12. System.out.println(bst.toString());
    13. }

    (6)关于最大值

    最大值位于右子树的最右侧,一路向右走,碰到第一个root.right == null的结点,root即为最大值结点。

    输出最大值和删除最大值和最小值几乎是相同的。

    1. public int max() {
    2. if (size == 0) {
    3. throw new NoSuchElementException("bst is empty!no max!");
    4. }
    5. TreeNode maxNode = findMaxNode(root);
    6. return maxNode.val;
    7. }
    8. private TreeNode findMaxNode(TreeNode root) {
    9. if(root.right==null){
    10. return root;
    11. }
    12. return findMaxNode(root.right);
    13. }
    14. public int removeMax() {
    15. if (size == 0) {
    16. throw new NoSuchElementException("bst is empty!cannot remove max!");
    17. }
    18. TreeNode maxNode = findMaxNode(root);
    19. root = removeMax(root);
    20. return maxNode.val;
    21. }
    22. private TreeNode removeMax(TreeNode root) {
    23. if(root.right==null){
    24. TreeNode left = root.left;
    25. root.left = root = null;
    26. size--;
    27. return left;
    28. }
    29. root.right = removeMax(root.right);
    30. return root;
    31. }
    1. public static void main(String[] args) {
    2. MyBinarySearchTree bst = new MyBinarySearchTree();
    3. bst.add(41);
    4. bst.add(28);
    5. bst.add(58);
    6. bst.add(15);
    7. bst.add(33);
    8. bst.add(50);
    9. System.out.println(bst.toString());
    10. System.out.println(bst.removeMax());
    11. System.out.println(bst.toString());
    12. System.out.println(bst.max());
    13. }

    (7)删除任意结点

    首先在public的remove方法中判断一下这个key值是否存在,存在则能删除则调用remove(root,key),不存在则直接返回false即可。

    在private的remove方法中有四种情况,第一种是root==null,则直接返回null值。第二种是root.val==key,也就是我们找到了需要删除的结点,这时又分为三种情况,如果他的左节点为空,那么直接将右节点补上即可。如果右节点为空那么直接将左节点补上即可。剩下一种情况便是左右节点都不为空,即选择右子树中最小的结点进行填补,在下面的画图中会讲解。

    然后当root.valkey调用root.left = remove(root.left,key)即可。

    当我们进行一次一个的遍历,root.val == key时,开始进行右子树中最小节点填补的操作。

     我们需要先行创建一个TreeNode类型的successor变量来存储findMinNode(root.right)中找到的最小值节点。

     然后使successor.right = removeMin(root.right),即删除最小节点后的root的右子树(在这里为空。)

     然后让successor.left = root.left。让successor左节点连接上root的左节点。

     再使root的左右节点以及本身置空 root.left = root.right = root = null。最后返回return successor即可,让他与前面的节点连接上。

    1. public boolean remove(int key) {
    2. if(!contains(key)){
    3. return false;
    4. }else{
    5. root = remove(root,key);
    6. return true;
    7. }
    8. }
    9. private TreeNode remove(TreeNode root, int key) {
    10. if(root==null){
    11. return null;
    12. }
    13. if(root.val==key){
    14. if(root.left==null){
    15. TreeNode right = root.right;
    16. root.right = root = null;
    17. size--;
    18. return right;
    19. }else if(root.right==null){
    20. TreeNode left = root.left;
    21. root.left = root = null;
    22. size--;
    23. return left;
    24. }else{
    25. TreeNode successor = findMinNode(root.right);
    26. successor.right = removeMin(root.right);
    27. successor.left = root.left;
    28. root.left = root.right = root = null;
    29. return successor;
    30. }
    31. }else if(root.val
    32. root.right = remove(root.right,key);
    33. }else {
    34. root.left = remove(root.left,key);
    35. }
    36. return root;
    37. }
    1. public static void main(String[] args) {
    2. MyBinarySearchTree bst = new MyBinarySearchTree();
    3. bst.add(41);
    4. bst.add(28);
    5. bst.add(58);
    6. bst.add(15);
    7. bst.add(33);
    8. bst.add(50);
    9. System.out.println(bst.toString());
    10. System.out.println(bst.remove(28));
    11. System.out.println(bst.toString());
    12. }

  • 相关阅读:
    3D建模师为了让甲方爸爸过稿,还可以这么做,就是在赚血汗钱啊
    四十二、路由层
    【C++】详解priority_queue(优先级队列)与函数对象
    UI高度自适应的修改方案
    数据看板是什么?
    openEuler快速入门-openEuler系统安装&openGauss数据库安装
    如何在debian上实现一键恢复操作系统?
    JavaWeb--06Vue组件库Element
    运营商大数据,三网融合大数据,联通大数据,移动大数据
    c语言贪吃蛇项目的实现
  • 原文地址:https://blog.csdn.net/m0_50987960/article/details/128154706