【数据结构&算法】二叉排序树

树系列:

一、前言

最近在深入了解MySQL索引,发现MySQL索引主要用B+树实现的。本人对树这种数据结构,一直以来掌握都是模棱两可的状态,现在希望通过写一个关于树的专题系列,来掌握树这种数据结构,为深入了解MySQL索引打下基础,做到心中有"树"。

二、定义

二叉排序树(Binary Sort(Search) Tree) 也叫二叉搜索树

  • 若左子树不空,则左子树上所有结点的值均小于它的根结点的值
  • 若右子树不空,则右子树上所有结点的值均大于它的根结点的值
  • 左、右子树也分别为二叉排序树
  • 二叉排序树也可以是一个空树

在这里插入图片描述

三、类结构

public class BinarySortTree<K extends Comparable<? super K>, V> {
    private Node root;

    private class Node {
        private K key;
        private V value;
        private Node left;
        private Node right;

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {
            return "Node{" + "value=" + value + '}';
        }
    }
}

四、插入

思路:

  • 若二叉树为空,则首先单独生成根结点。
  • 首先执行查找算法,找出被插结点的父亲结点。
  • 判断被插结点是其父亲结点的左结点或者右结点,将被插结点作为叶子结点插入。

注意:新插入的结点总是叶子结点。

   public void add(K key, V value) {
        Node node = new Node(key, value);
        if (this.root == null) {
            this.root = node;
            return;
        }
        this.add(this.root, node);
    }

    private void add(Node root, Node node) {
        if (node.key.compareTo(root.key) < 0) {
            if (root.left == null) {
                root.left = node;
            } else {
                add(root.left, node);
            }
        } else {
            if (root.right == null) {
                root.right = node;
            } else {
                add(root.right, node);
            }
        }
    }

五、查找

思路:

  • 如果二叉排序树为空,返回null
  • 如果根结点的键等于要查找的键,返回根结点的值
  • 否则,递归的在子树中查找,如果要查找的键小于根结点的键在左子树中查找,反之在右子树中查找

效率:
查找效率和二叉树的高度有关,最好的情况是,即由n个结点构成的高度为
⌊log2n⌋+1的二叉排序树,效率为O(log2n)。

在这里插入图片描述
最坏的情况是单向生长的二叉排序树,即n个结点高度为n的二叉排序树,其效率为O(n)
在这里插入图片描述

 public V get(K key) {
        if (this.root == null) {
            return null;
        }
        Node node = getNode(this.root, key);
        if (node == null) {
            return null;
        }
        return node.value;
    }
    private Node getNode(Node root, K key) {
        if (root == null) {
            return null;
        }
        if (root.key.compareTo(key) == 0) {
            return root;
        }
        if (root.key.compareTo(key) > 0) {
            return getNode(root.left, key);
        } else {
            return getNode(root.right, key);
        }
    }

六、删除

思路:
二叉排序树的删除相对麻烦点,分为三种情况

  • 删除的是叶子结点
  • 删除的结点只有左子树/右子树
  • 删除结点左右子树都存在
public boolean delete(K key) {
        if (this.root == null) {
            return false;
        }
        Node targetNode = getNode(this.root, key);
        if (targetNode == null) {
            return false;
        }
        Node parentNode = getParentNode(this.root, key);

        //删除的是叶子结点
        if (targetNode.left == null && targetNode.right == null) {
            //只有根结点
            if (parentNode == null) {
                this.root = null;
                return true;
            }
            if (parentNode.left != null && parentNode.left.key.compareTo(targetNode.key) == 0) {
                parentNode.left = null;
                return true;
            }
            if (parentNode.right != null && parentNode.right.key.compareTo(targetNode.key) == 0) {
                parentNode.right = null;
                return true;
            }
        }
        //删除的结点只有左子树
        if (targetNode.left != null && targetNode.right == null) {
            if (parentNode == null) {
                this.root = targetNode.left;
                return true;
            }
            //删除结点是父结点的左结点
            if (parentNode.left != null && parentNode.left.key.compareTo(targetNode.key) == 0) {
                parentNode.left = targetNode.left;
                return true;
            }
            //删除结点是父结点的右结点
            if (parentNode.right != null && parentNode.right.key.compareTo(targetNode.key) == 0) {
                parentNode.right = targetNode.left;
                return true;
            }
        }
        //删除的结点只有右子树
        if (targetNode.right != null && targetNode.left == null) {
            if (parentNode == null) {
                this.root = targetNode.right;
                return true;
            }
            if (parentNode.left != null && parentNode.left.key.compareTo(targetNode.key) == 0) {
                parentNode.left = targetNode.right;
                return true;
            }
            if (parentNode.right != null && parentNode.right.key.compareTo(targetNode.key) == 0) {
                parentNode.right = targetNode.right;
                return true;
            }
        }
        //删除结点左右子树都存在
        if (targetNode.right != null && targetNode.left != null) {
            //从右子树早到最小的结点
            Node minNode = getMinNode(targetNode.right);
            //删除minNode
            delete(minNode.key);
            targetNode.key = minNode.key;
            targetNode.value = minNode.value;
        }
        return false;
    }
    
    //查找当前结点
   private Node getNode(Node root, K key) {
        if (root == null) {
            return null;
        }
        if (root.key.compareTo(key) == 0) {
            return root;
        }
        if (root.key.compareTo(key) > 0) {
            return getNode(root.left, key);
        } else {
            return getNode(root.right, key);
        }
    }
    
    //查找父结点
     private Node getParentNode(Node root, K key) {
        if (root == null) {
            return null;
        }
        if (root.left != null) {
            if (root.left.key.compareTo(key) == 0) {
                return root;
            }
            if (root.key.compareTo(key) > 0) {
                return getParentNode(root.left, key);
            }
        }
        if (root.right != null) {
            if (root.right.key.compareTo(key) == 0) {
                return root;
            }
            if (root.key.compareTo(key) < 0) {
                return getParentNode(root.right, key);
            }
        }
        return null;
    }
   //查找左子树值最小的结点,也就是叶子结点
    private Node getMinNode(Node node) {
        Node targetNode = node;
        while (targetNode.left != null) {
            targetNode = targetNode.left;
        }
        return targetNode;
    }

七、全部代码

public class BinarySortTree<K extends Comparable<? super K>, V> {
    private Node root;

    private class Node {
        private K key;
        private V value;
        private Node left;
        private Node right;

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "key=" + key +
                    ", value=" + value +
                    '}';
        }
    }

    /**
     * 添加结点
     * @param key
     * @param value
     */
    public void add(K key, V value) {
        Node node = new Node(key, value);
        if (this.root == null) {
            this.root = node;
            return;
        }
        this.add(this.root, node);
    }

    private void add(Node root, Node node) {
        if (node.key.compareTo(root.key) < 0) {
            if (root.left == null) {
                root.left = node;
            } else {
                add(root.left, node);
            }
        } else {
            if (root.right == null) {
                root.right = node;
            } else {
                add(root.right, node);
            }
        }
    }

    /**
     * 获取值
     * @param key
     * @return
     */
    public V get(K key) {
        if (this.root == null) {
            return null;
        }
        Node node = getNode(this.root, key);
        if (node == null) {
            return null;
        }
        return node.value;
    }

    /**
     * 获取当前结点
     * @param root
     * @param key
     * @return
     */
    private Node getNode(Node root, K key) {
        if (root == null) {
            return null;
        }
        if (root.key.compareTo(key) == 0) {
            return root;
        }
        if (root.key.compareTo(key) > 0) {
            return getNode(root.left, key);
        } else {
            return getNode(root.right, key);
        }
    }

    /**
     * 获取父结点
     * @param root
     * @param key
     * @return
     */
    private Node getParentNode(Node root, K key) {
        if (root == null) {
            return null;
        }
        if (root.left != null) {
            if (root.left.key.compareTo(key) == 0) {
                return root;
            }
            if (root.key.compareTo(key) > 0) {
                return getParentNode(root.left, key);
            }
        }
        if (root.right != null) {
            if (root.right.key.compareTo(key) == 0) {
                return root;
            }
            if (root.key.compareTo(key) < 0) {
                return getParentNode(root.right, key);
            }
        }
        return null;
    }

    /**
     * 查找左子树值最小的结点,也就是叶子结点
     * @param node
     * @return
     */
    private Node getMinNode(Node node) {
        Node targetNode = node;
        while (targetNode.left != null) {
            targetNode = targetNode.left;
        }
        return targetNode;
    }

    /**
     * 删除结点
     * @param key
     * @return
     */
    public boolean delete(K key) {
        if (this.root == null) {
            return false;
        }
        Node targetNode = getNode(this.root, key);
        if (targetNode == null) {
            return false;
        }
        Node parentNode = getParentNode(this.root, key);

        //删除的是叶子结点
        if (targetNode.left == null && targetNode.right == null) {
            //只有根结点
            if (parentNode == null) {
                this.root = null;
                return true;
            }
            if (parentNode.left != null && parentNode.left.key.compareTo(targetNode.key) == 0) {
                parentNode.left = null;
                return true;
            }
            if (parentNode.right != null && parentNode.right.key.compareTo(targetNode.key) == 0) {
                parentNode.right = null;
                return true;
            }
        }
        //删除的结点只有左子树
        if (targetNode.left != null && targetNode.right == null) {
            if (parentNode == null) {
                this.root = targetNode.left;
                return true;
            }
            //删除结点是父结点的左结点
            if (parentNode.left != null && parentNode.left.key.compareTo(targetNode.key) == 0) {
                parentNode.left = targetNode.left;
                return true;
            }
            //删除结点是父结点的右结点
            if (parentNode.right != null && parentNode.right.key.compareTo(targetNode.key) == 0) {
                parentNode.right = targetNode.left;
                return true;
            }
        }
        //删除的结点只有右子树
        if (targetNode.right != null && targetNode.left == null) {
            if (parentNode == null) {
                this.root = targetNode.right;
                return true;
            }
            if (parentNode.left != null && parentNode.left.key.compareTo(targetNode.key) == 0) {
                parentNode.left = targetNode.right;
                return true;
            }
            if (parentNode.right != null && parentNode.right.key.compareTo(targetNode.key) == 0) {
                parentNode.right = targetNode.right;
                return true;
            }
        }
        //删除结点左右子树都存在
        if (targetNode.right != null && targetNode.left != null) {
            //从右子树早到最小的结点
            Node minNode = getMinNode(targetNode.right);
            //删除minNode
            delete(minNode.key);
            targetNode.key = minNode.key;
            targetNode.value = minNode.value;
        }
        return false;
    }

    /**
     * 前序遍历
     */
    public void preOrder() {
        if (this.root == null) {
            return;
        }
        preOrder(this.root);
    }

    private void preOrder(Node node) {
        System.out.println(node);
        if (node.left != null) {
            preOrder(node.left);
        }
        if (node.right != null) {
            preOrder(node.right);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉排序树是一种二叉树数据结构,也称为二叉查找树或二叉搜索树。它要么是一棵空树,要么满足以下条件:对于任意节点,其左子树中的所有节点的值小于它的值,而右子树中的所有节点的值大于它的值。这个特点使得在二叉排序树中进行查找操作具有高效性能,接近于折半查找。如果二叉排序树不平衡,它的深度可能达到n,查找效率将变为O(n),相当于顺序查找。因此,为了获得较好的查找性能,需要构造一棵平衡的二叉排序树二叉排序树的存储结构一般使用链式存储结构,每个节点包含一个数据元素以及两个指向左子树和右子树的指针。可以使用递归或迭代的方式实现创建、查找、插入、删除等操作,以及计算平均查找长度等指标。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [数据结构-二叉排序树(图文详细版)](https://blog.csdn.net/qq_55660421/article/details/122530387)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [数据结构实验-二叉排序树算法](https://download.csdn.net/download/whales996/10746805)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值