Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >二分搜索树(Binary Search Tree)

二分搜索树(Binary Search Tree)

作者头像
程序员波特
发布于 2024-01-19 01:38:40
发布于 2024-01-19 01:38:40
20300
代码可运行
举报
文章被收录于专栏:魔法书魔法书
运行总次数:0
代码可运行
什么是二叉树?

  在实现二分搜索树之前,我们先思考一下,为什么要有树这种数据结构呢?我们通过企业的组织机构、文件存储数据库索引等这些常见的应用会发现,将数据使用树结构存储后,会出奇的高效,树结构本身是一种天然的组织结构。常见的树结构有:二分搜索树、平衡二叉树(常见的平衡二叉树有AVL和红黑树)、堆、并查集、线段树、Trie等。Trie又叫字典树或前缀树。   树和链表一样,都属于动态数据结构,由于二分搜索树是二叉树的一种,我们先来说说什么是二叉树。二叉树具有唯一的根节点,二叉树每个节点最多有两个孩子节点,二叉树的每个节点最多有一个父亲节点,二叉树具有天然递归结构,每个节点的左子数也是一棵二叉树,每个节点的右子树也是一颗二叉树。二叉树如下图:

什么是二分搜索树?

  二分搜索树也是一种二叉树,但二分搜索树种每个节点的值都要大于其左子树所有节点的值,小于其右子树所有节点的值,每一棵子树也是二分搜索树。正因为二分搜索树的这种性质,二分搜索树存储的元素必须具有可比较性。下图就是一棵二分搜索树:

我们可以根据二分搜索树的特点,构建一颗二分搜索树,代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 由于二分搜索树中的元素必须具有可比较性,所以二分搜索树中存储的数据必须要实现Comparable接口
 * @param <E>
 */
public class BST<E extends Comparable<E>> {

    //由于用户并不需要知道我们二分搜索树的具体实现,所以这里把节点设置成内部类
    private class Node {
        public E e;
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }
    
    //一棵树只有一个根节点
    private Node root;
    //节点的个数
    private int size;

    //无参构造,这里不写也可以,因为和系统默认的无参构造是相同的
    public BST(){
        root = null;
        size = 0;
    }

    //获取节点的个数
    public int size(){
        return size;
    }

    //判断树是否为空
    public boolean isEmpty(){
        return size == 0;
    }
}
二分搜索树的基本操作
二分搜索树添加新元素

  我们在向二分搜索中添加元素时,需要保持二分搜索树的性质,即需要将我们添加的元素从根节点开始比较,若比根节点小,则去根节点的左子树递归进行添加操作,若比根节点的右子树递归进行添加操作,若相等,则直接返回,因为本文实现的是一棵不包含重复元素的二分搜索树。具体代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // 向二分搜索树中添加新的元素e
    public void add(E e){
        //判断根节点是否为空
        if(root == null){
            //如果根节点为空,则将新添加的元素作为根节点
            root = new Node(e);
            //节点的个数加一
            size ++;
        }
        else
            add(root, e);
    }

    // 向以node为根的二分搜索树中插入元素e,递归算法
    private void add(Node node, E e){
        //如果被添加的元素与当前节点的值相等,则直接返回 -- 本文的二分搜索中不包含重复元素
        if(e.equals(node.e))
            return;
        //如果待添加元素e小于当前节点的值,并且当前节点没有左孩子
        else if(e.compareTo(node.e) < 0 && node.left == null){
            //则将待添加元素e作为当前节点的左孩子
            node.left = new Node(e);
            size ++;
            return;
        }
        //如果待添加元素e大于当前节点的值,并且当前节点没有右孩子
        else if(e.compareTo(node.e) > 0 && node.right == null){
            //则将待添加元素e作为当前节点的右孩子,并返回
            node.right = new Node(e);
            size ++;
            return;
        }
        //如果以上条件都不满足,则根据元素e和当前节点的值的比较,来确定去左子树递归进行添加操作,还是去右子树进行添加操作
        if(e.compareTo(node.e) < 0)
            add(node.left, e);
        else //e.compareTo(node.e) > 0
            add(node.right, e);
    }

  通过上面添加方法的代码实现中,可以看出有如下两点不足并且可以优化的地方:

  1. 待添加元素e需要与当前节点的值进行两轮比较;
  2. 递归终止条件太臃肿了.我们可以来简化一下上面的添加元素的方法,如下:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // 向二分搜索树中添加新元素e
    public void add(E e){
       root = add(root,e);
    }

    //向以node为根的二分搜索树中插入元素e,递归算法
    private Node add(Node node, E e) {
        if (node == null){
            node = new Node(e);
            size ++;
            return node;
        }
        if (e.compareTo(node.e) < 0){
           node.left = add(node.left,e);
        }else if (e.compareTo(node.e) > 0){
            node.right = add(node.right , e);
        }
        return node;
    }

改进之后添加方法就简洁很多了,现在我们完成了二分搜索树的添加后,想一下如何在二分搜索中查找某个元素呢?我们可以用contains()方法来表示当前二分搜索中是否包含该元素,代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //看二分搜索树中是否包含元素e
    public boolean contains(E e){
        //使用递归查找
        return contains(root,e);
    }

    private boolean contains(Node node, E e) {
        //如果根节点为空,则该二分搜索中肯定没有带查找元素e,直接返回false
        if (node == null)
            return false;
        //如果当前节点的值和待查找元素e相等,则返回true
        if (e.compareTo(node.e) == 0){
            return true;
        //如果待查找元素e小于当前节点的值,则去当前节点的左子树进行递归查找
        }else if (e.compareTo(node.e) < 0 ){
            return contains(node.left,e);
        //如果待查找元素e大于当前节点的值,则去当前节点的右子树进行递归查找
        }else { //(e.compareTo(node.e) > 0 )
            return contains(node.right,e);
        }
    }
二分搜索树的遍历(包含非递归实现)

什么是遍历操作?   遍历操作就是把所有的节点都访问一遍,当然访问的原因和你如何访问都和你具体的业务相关,本文主要是通过在在控制台打印输出该节点的值,来完成访问的。我们知道在线性结构下,遍历是极其容易的,比如数组和链表的遍历,当然在树结构下,我们可以通过递归来使二分搜索树的遍历变得非常简单。

  • 递归实现

1. 前序遍历

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //二分搜索树的前序遍历 -- 递归算法
    public void preOrder(){
        preOrder(root);
    }

    private void preOrder(Node node) {
        if (node == null)
            return;
        //访问该节点
        System.out.print(node.e +"\t");
        //递归遍历左子树
        preOrder(node.left);
        //递归遍历右子树
        preOrder(node.right);
    }

  就几行代码,我们就已经完成了我们的前序遍历,是不是很简单,我们现在可以来测试一下我们前面写的添加方法和现在的前序遍历操作,为了更好在控制台看我们的打印结果,我们需要重写一下二分搜索树的toString(),我们可以用“–”来表示节点所在的深度,让输出效果更直观,实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //重写toString()
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        generateBSTString(root,0,builder);
        return builder.toString();
    }

    //生成以node为根节点,深度为depth的描述二叉树的字符串
    private void generateBSTString(Node node, int depth, StringBuilder builder) {
        if(node == null){
            builder.append(generateDepthString(depth) + "null\n");
            return;
        }
        builder.append(generateDepthString(depth) + node.e + "\n");
        generateBSTString(node.left,depth+1,builder);
        generateBSTString(node.right,depth+1,builder);
    }

    //添加深度标识符
    private String generateDepthString(int depth) {
        StringBuilder res = new StringBuilder();
        for (int i=0; i<depth; i++){
            res.append("--");
        }
        return res.toString();
    }

我们可以在主方法中添加我们的测试代码,测试代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static void main(String[] args) {
        BST<Integer> bst = new BST<Integer>();
        int[] nums = {5, 3, 6, 8, 4, 2};
        for(int num: nums){
            //二分搜索树的添加操作
            bst.add(num);
         }

        //前序遍历 -- 递归算法
        bst.preOrder();
        System.out.println();

        System.out.println(bst);
    }

我们现在根据上面的测试代码,来一起看下运行结果:

我们根据运行结果画出的树结构,可以看出是满足二分搜索树的性质的,因此也证明了我们的添加方法和前序遍历是没有问题的。 2. 中序遍历   根据我们的前序遍历的递归实现,我们可以很容易地写出二分搜索树的中序遍历,具体实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //二分搜索树的中序遍历 -- 递归算法
    public void inOrder(){
        inOrder(root);
    }

    private void inOrder(Node node) {
        if (node == null)
            return;
        //遍历左子树
        inOrder(node.left);
        //通过打印输出该节点的值的形式,访问该节点
        System.out.print(node.e + "\t");
        //遍历右子树
        inOrder(node.right);
    }

3. 后序遍历   通过前序遍历和中序遍历的学习,我相信大家对后序遍历的递归实现已经觉得非常容易了,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //二分搜索树的后序遍历 --递归算法
    public void postOrder(){
        postOrder(root);
    }

    private void postOrder(Node node) {
        if ( node== null )
            return;
        //遍历左子树
        postOrder(node.left);
        //遍历右子树
        postOrder(node.right);
        //通过打印输出该节点的值的形式,访问该节点
        System.out.print(node.e+"\t");
    }
  • 非递归实现

1. 前序遍历   实现思路:当我们使用非递归来实现二分搜索树的前序遍历时,我们可以借助栈这种数据结构,由于栈是后进先出的,我们需要先将当前节点的右孩子压入栈中,再将当前节点的左孩子压入栈中,当我们的栈不为空时,我们就循环执行出栈操作,并且将出栈的元素作为当前节点。当然,如果你还不了解栈这种数据结构,你可以看我的上篇文章:常见的线性结构进行学习。非递归前序遍历具体代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //前序遍历 -- 非递归实现
    public List<E> preOrderTraversal(TreeNode root) {
        //该集合用来保存通过前序遍历后的元素
        List<E> res = new ArrayList<E>();
        if (root == null)
            return res;
        //借助栈这种数据结构进行实现
        Stack<TreeNode<E>> stack = new Stack<TreeNode<E>>();
        //由于前序遍历的一个元素一定是根节点,所以我们可以先将根节点压入栈中
        stack.push(root);
        //判断栈是否为空
        while ( !stack.isEmpty() ){
            //将出栈的节点保存起来
            TreeNode<E> curr = stack.pop();
            //将出栈节点的值添加到集合中
            res.add(curr.val);
            //若当前节点的右孩子不为空,就将该节点的右孩子压入栈中
            if (curr.right !=  null)
                stack.push(curr.right);
            //若当前节点的左孩子不为空,就将该节点的左孩子压入栈中
            if (curr.left != null)
                stack.push(curr.left);
        }
        return res;
    }

2. 中序遍历   二分搜索树中序遍历的非递归实现,这里还是通过借助栈来实现的,理解起来要比前序遍历的非递归实现复杂一些,希望大家可以认真思考,仔细体会,具体代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //中序遍历 -- 非递归实现
    public List<E> inOrderTraversal(TreeNode root){
        List<E> res = new ArrayList<E>();

        if (root == null)
            return res;

        TreeNode<E> cur = root;
        Stack<TreeNode> stack = new Stack<TreeNode>();

        while (cur != null || !stack.isEmpty()){
            if (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }else {
                cur = stack.pop();
                res.add(cur.val);
                cur = cur.right;
            }
        }
        return res;
    }

3. 后序遍历   我们通过前面的前序遍历和中序遍历的非递归算法的实现,都是采用的栈这种数据结构进行实现,这也和我们程序调用的系统栈的工作原理相似,下面我们后序遍历的非递归算法仍然接站栈这种数据结构进行实现,这样可以帮助我们更加的熟悉栈这种数据结构的应用,具体代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //后序遍历 -- 非递归算法
    public List<E> postOrderTraversal(TreeNode root) {
        List<E> res = new ArrayList<E>();

        if (root == null)
            return res;

        //借助栈结构实现二分搜索树的非递归后序遍历
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode<E> curr = root;
        TreeNode<E> pre = null;

        while (curr !=  null || !stack.isEmpty()) {
            if (curr != null){
                stack.push(curr);
                curr = curr.left;
            }else {
                curr = stack.pop();
                if (curr.right == null || curr.right == pre){
                    res.add(curr.val);
                    pre = curr;
                    curr = null;
                }else {
                    stack.push(curr);
                    curr =  curr.right;
                }

            }

        }
        return res;
    }

4. 层序遍历   层序遍历和前面三种遍历方式都不一样,前、中、后序遍历本质上都是深度优先遍历,在进行前、中、后序遍历时,会先一直走到二分搜索树的叶子节点,也就是最大深度,而我们的层序遍历,本质上是一种广度优先遍历,就是横向遍历完所有节点后,再遍历下一层节点,如下图:

那么二分搜索树的层序遍历如何实现呢,我们前面讲过队列这种数据结构是先进先出的,我们可以将二分搜索树中的每层节点顺序放进队列中,然后再进行出队操作就可以了,若你不清楚队列,你可以看我的上篇文章常见的线性结构进行学习,现在就让我们来看是如何使用队列实现二分搜索树的层序遍历吧,具体代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //层序遍历
    public void levelOrder(){
        if (root == null)
            return;
        Queue<Node> queue = new LinkedList<Node>();
        queue.add(root);

        while ( !queue.isEmpty()){
            Node removeNode = queue.remove();
            System.out.print(removeNode.e+"\t");
            if (removeNode.left != null)
                queue.add(removeNode.left);
            if (removeNode.right != null)
                queue.add(removeNode.right);
        }
    }
删除二分搜索树中的元素

  由于删除二分搜索中的任意元素是比较复杂的,我们可以先研究如何实现删除二分搜索树的最大值和最小值,当然我们得先找到这棵二分搜索树的最大值和最小值,查找方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //寻找二分搜索树中最大元素 -- 递归获取
    public E maxNum(){
        if (size == 0)
            throw new IllegalArgumentException("BST is empty");
        //递归调用获取二分搜索中最大值所在的节点的方法
        Node maxNode = maxNum(root);
        return maxNode.e;
    }

    //以node为根节点,获取二分搜索中最大值所在的节点
    private Node maxNum(Node node) {
        //递归终止条件---如果当前节点的右孩子为空,则返回当前节点
        if (node.right == null)
            return node;
        //递归从当前节点的右子树获取最大值所在的节点
        return maxNum(node.right);
    }
    

    //寻找二分搜索数中的最小元素 -- 递归法
    public E minNum(){
        if (size == 0) // 也可以写为 root==null
            throw new IllegalArgumentException("BST is empty");
        Node minNode = minNum(root);
        return minNode.e;
    }
    
    //以node为根节点搜索最小元素所在的节点
    private Node minNum(Node node) {
        if (node.left == null)
            return node;
        //递归从当前节点的左子树获取最小值所在的节点
        return minNum(node.left);
    }

  现在我们已经找出最小元素和最大元素所在的节点了,我们现在就可以是实现删除最小元素和最大元素所在的节点操作了,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //从二分搜索树中删除最小元素所在的节点,并返回最小元素的值
    public E removeMinNum(){
        //获取最小值
        E e = minNum();

        root = removeMinNum(root);

        return e;
    }

    //以node为根节点删除最小元素所在的节点
    private Node removeMinNum(Node node) {
        if (node.left == null) {
            Node rightNode = node.right;
            node.right = null;
            size --;
            return rightNode;
        }
        
        node.left = removeMinNum(node.left);
        return node;
    }

    //删除二分搜索数中最大元素所在的节点,并返回该值
    public E removeMaxNum(){
        //获取最大值
        E e = maxNum();

        root = removeMaxNum(root);

        return e;
    }

    //删除以node为根节点的二分搜索中最大元素所在的节点
    private Node removeMaxNum(Node node) {
        if (node.right == null) {
            Node leftNode = node.left;
            node.left = null;
            size --;
            return leftNode;
        }

        node.right = removeMaxNum(node.right);
        return node;
    }

  在我们实现删除二分搜索树中的最大元素所在的节点和删除最小元素所在的节点操作后,我们可以写一个简单的测试用例,来验证下我们的删除最大值和删除最小值操作是否正确:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static void main(String[] args) {

        BST<Integer> bst = new BST<Integer>();
        Random random = new Random();

        int n = 1000;

        // 测试删除最小元素所在的节点
        for(int i = 0 ; i < n ; i ++)
            bst.add(random.nextInt(10000));

        List<Integer> nums = new ArrayList<Integer>();
        while(!bst.isEmpty()){
            //从二分搜索树中删除最小元素所在的节点,并拿到该最小元素
            Integer minNum = bst.removeMinNum();
            //向我们的集合中添加该最小元素
            nums.add(minNum);
        }

        //我们的nums集合中存储的是二分搜索树中所有节点的值按从小到大顺序排序后的元素
        System.out.println(nums);
        for(int i = 1 ; i < nums.size() ; i ++)
            //如果该集合中前一个元素的值大于后一个元素的值,则不满足从小到大的排序规则,则抛出错异常
            if(nums.get(i - 1) > nums.get(i))
                throw new IllegalArgumentException("Error!");
        System.out.println("removeMin test completed.");


        // 测试删除最大元素所在的节点
        for(int i = 0 ; i < n ; i ++)
            bst.add(random.nextInt(10000));

        nums = new ArrayList<Integer>();
        while(!bst.isEmpty()){
            //从二分搜索树中删除最大元素所在的节点,并拿到该最大元素
            Integer maxNum = bst.removeMaxNum();
            //向我们的集合中添加该最小元素
            nums.add(maxNum);
        }

        //我们的nums集合中存储的是二分搜索树中所有节点的值按从大到小倒序排序后的元素
        System.out.println(nums);
        for(int i = 1 ; i < nums.size() ; i ++)
            //如果该集合中前一个元素的值小于后一个元素的值,则不满足从大到小的排序规则,则抛出错异常
            if(nums.get(i - 1) < nums.get(i))
                throw new IllegalArgumentException("Error!");
        System.out.println("removeMax test completed.");
    }

  有了如上操作作为铺垫后,现在就可以来实现删除二分搜索树中的指定元素的操作了,需要注意的是,当待删除节点的左右子树都不为空时,我们需要找到待删除元素的后继或者前驱,后继就是指待删除节点右子树中最小的元素所在的节点,前驱是指待删除节点左子树最大的元素所在的节点。本文是采用的待删除节点的后继来代替待删除元素的位置。 前驱图示:待删除节点右子树中最小的元素所在的节点

后继图示:待删除节点左子树最大的元素所在的节点 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rCkr2SOb-1594278091413)(https://img2020.cnblogs.com/blog/1975191/202004/1975191-20200403113321307-2049082127.png)] 具体代码实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    //删除二分搜索树中的指定元素
    public void removeElement(E e){
        root = removeElement(root,e);
    }

    // 删除掉以node为根的二分搜索树中值为e的节点, 递归算法
    // 返回删除节点后新的二分搜索树的根
    private Node removeElement(Node node, E e) {
        if (node == null)
            return null;
        if (e.compareTo(node.e) <0 ){
            node.left = removeElement(node.left, e);
            return node;
        }else if (e.compareTo(node.e) >0 ){
            node.right = removeElement(node.right,e);
            return node;
        }else { //e.compareTo(node.e) == 0

            //待删除节点左子树为空的情况
            if (node.left == null){
                Node rightNode = node.right;
                node.right = null;
                size --;
                return rightNode;
            }

            //待删除节点的右子树为空的情况
            if (node.right == null){
                Node leftNode = node.left;
                node.left = null;
                size -- ;
                return leftNode;
            }

            //待删除节点的左右子树都不为空的情况
            // 待删除节点的后继:找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点
            // 用这个节点顶替待删除节点的位置
            Node successor = minNum(node.right);
            successor.right = removeMinNum(node.right);
            successor.left = node.left;
            node.right = node.left = null;
            return successor;
        }
    }

本文实现的是一个不包含重复元素的二分搜索树,若你需要你的二分搜索树包含重复元素,在进行添加操作时只需要定义左子树小于等于节点;或者右子树大于等于节点。二分搜索树的学习就到这里了,希望本文能让你对二分搜索树有更深的理解。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
BinarySearchTree二叉搜索树
二叉树具有唯一的根节点 二叉树每个节点最多有两个孩子 二叉树每个节点最多有一个父亲节点,根节点是唯一没有父亲节点的。 二叉树具有天然递归结构。 每个节点的子树都可以看做是二叉树。
羊羽shine
2019/05/29
3150
数据结构之:二分搜索树
为什么要研究树结构?首先因为树在计算机程序中是非常重要的数据结构之一,并且树结构本身是一种天然的组织结构。在很多情况下将数据使用树结构存储后,会发现出奇的高效。甚至有些问题,必须要使用树结构才能够解决。
端碗吹水
2021/01/20
4210
数据结构之:二分搜索树
Algorithms_二叉树&二分搜索树初探
按照上图, 16就是 28根节点的左孩子, 30 就是28的右孩子 。 依次类推 13是16的左孩子, 22是16的右孩子。 29是30的左孩子, 42是30的右孩子。
小小工匠
2021/08/17
3740
数据结构之树-第二篇
1、此时,将元素30从队首拿出来,进行访问,之后将30的左孩子29、右孩子42入队,那么此时队首元素就是13了。
别先生
2020/03/20
4580
算法 | 二分搜索树前中后遍历
从图上我们看出二分搜索树每个节点的值大于其左子节的所有节点的值小于其右子节点的所有节点的值
JavaFish
2019/10/17
3970
二叉搜索树的这些你都会了吗?
在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。
beifengtz
2019/09/09
5230
数据结构与算法-二分搜索树层序遍历
二分搜索树是一种特殊的二叉树,其中每个节点的值都大于其左子树中的所有节点的值,且小于其右子树中的所有节点的值。除了常见的前序、中序和后序遍历外,二分搜索树还支持层序遍历,即按照从上到下、从左到右的顺序访问每个节点。层序遍历通常使用队列来实现。本文将深入探讨二分搜索树层序遍历的基本原理,并通过具体的Java代码详细说明在二分搜索树中进行层序遍历的实现步骤。
用户11147438
2024/08/09
1230
数据结构与算法-二分搜索树层序遍历
数据结构与算法-二分搜索树
二分搜索树是一种特殊的二叉树,它具有独特的性质,使得在树中查找、插入和删除元素变得非常高效。本文将深入探讨二分搜索树的基本原理、实现步骤,并通过具体的案例代码详细说明二分搜索树的每一个细节。
用户11147438
2024/08/09
1440
数据结构与算法-二分搜索树
数据结构 | 二分搜索树及它的各种操作(kotlin实现)
这里实现一些比较经典的案例,比较简单的如前序遍历,中序遍历,后序遍历,使用递归,栈,队列 都可以简单实现。
Petterp
2022/02/09
2320
数据结构 | 二分搜索树及它的各种操作(kotlin实现)
5.4删除二叉搜索树的任意元素
节点删除之后,将左孩子所在的二叉树取代其位置;连在原来节点父亲元素右节点的位置,比如在图中需要删除58这个节点。
wfaceboss
2019/04/19
6380
5.4删除二叉搜索树的任意元素
数据结构与算法-二分搜索树遍历
二分搜索树是一种特殊的二叉树,其中每个节点的值都大于其左子树中的所有节点的值,且小于其右子树中的所有节点的值。这种特性使得在二分搜索树中查找、插入和删除节点变得非常高效。此外,二分搜索树还支持多种类型的遍历,包括前序遍历、中序遍历和后序遍历。每种遍历方式都有其特定的应用场景。本文将深入探讨二分搜索树遍历的基本原理,并通过具体的Java代码详细说明在二分搜索树中进行遍历的实现步骤。
用户11147438
2024/08/09
1190
数据结构与算法-二分搜索树遍历
数据结构与算法-二分搜索树节点删除
二分搜索树是一种特殊的二叉树,其中每个节点的值都大于其左子树中的所有节点的值,且小于其右子树中的所有节点的值。除了常见的插入和查找操作之外,二分搜索树还支持节点的删除。删除节点需要保持二分搜索树的性质不变。本文将深入探讨二分搜索树节点删除的基本原理,并通过具体的Java代码详细说明在二分搜索树中删除节点的实现步骤。
用户11147438
2024/08/09
1350
数据结构与算法-二分搜索树节点删除
Data Structure前情提要——二叉树红黑树
叶子节点就是左右孩子都是空的,但是并不是每一颗树都像上图所示的那样这么规整,有些树树可以只有左孩子没有右孩子的。二叉树的节点一定会大于左节点的值小于右节点的值,每一个节点都要满足,所有每一个节点下面拿出来的树都可以作为一个二叉树。既然有大于等于了,那么这科树的元素一定要有可比较性才可以。
西红柿炒鸡蛋
2018/12/24
4370
数据结构与算法-二分搜索树节点的查找
二分搜索树是一种特殊的二叉树,其中每个节点的值都大于其左子树中的所有节点的值,且小于其右子树中的所有节点的值。这种特性使得在二分搜索树中查找、插入和删除节点变得非常高效。本文将深入探讨二分搜索树节点查找的基本原理,并通过具体的Java代码详细说明在二分搜索树中查找节点的实现步骤。
用户11147438
2024/08/09
2060
数据结构与算法-二分搜索树节点的查找
二分搜索树实现
在析构的时候,我们要释放节点内存,这颗BST树的所有节点内存释放是一个递归的过程,因此我们这里调用destroy递归函数,去递归释放节点内存。
公众号guangcity
2019/10/31
8000
看得见的数据结构Android版之二分搜索树篇
零、前言 1.个人感觉这个二叉搜索树实现的还是很不错的,基本操作都涵盖了 2.在Activity中对view设置监听函数,可以动态传入数据,只要可比较,都可以生成二分搜索树 3.二分搜索树的价值
张风捷特烈
2018/12/18
7100
Data Structure_二叉树_集合_堆_并查集_哈希表
叶子节点就是左右孩子都是空的,但是并不是每一颗树都像上图所示的那样这么规整,有些树树可以只有左孩子没有右孩子的。二叉树的节点一定会大于左节点的值小于右节点的值,每一个节点都要满足,所有每一个节点下面拿出来的树都可以作为一个二叉树。既然有大于等于了,那么这科树的元素一定要有可比较性才可以。
西红柿炒鸡蛋
2019/01/23
5990
懵逼树上懵逼果:学习二分搜索树
我们通过两组添加元素,三组删除元素,一组查找元素的操作来理解二叉查找树的属性性质。
五分钟学算法
2018/12/25
7780
打牢地基-二叉树、BST
二分搜索树-BTS 加速查询过程的原因,假如根节点val = 28, 现在在查找 30 这个元素,因为BTS的存储特性,只需要查找右子树部分就可以了,大大提高了查询的速度 有个细节,需要保证node的val 是可比较的,这是有局限性的
用户1081422
2020/04/08
6600
5.2二叉搜索树遍历(前序、中序、后序、层次、广度优先遍历)
前言:在上一节中,我们对树及其相关知识做了了解,对二叉搜索树做了基本的实现,下面我们继续完善我们的二叉搜索树。
wfaceboss
2019/04/18
5.2K0
5.2二叉搜索树遍历(前序、中序、后序、层次、广度优先遍历)
相关推荐
BinarySearchTree二叉搜索树
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验