文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java数据结构超详细分析二叉搜索树

2024-04-02 19:55

关注

封面

1.搜索树的概念

二叉搜索树是一种特殊的二叉树,又称二叉查找树,二叉排序树,它有几个特点:

1-1

2.二叉搜索树的简单实现

我们来简单实现以下搜索树,就不使用泛型了,二叉搜索树基本结构:


public class BinarySearchTree {

    static class Node {
        public int val;
        public Node left;
        public Node right;
        public Node(int val) {
            this.val = val;
        }
    }

    public Node root;
    //其他方法
}

2.1查找

二叉搜索树最擅长的就是查找,根据二叉搜索树的定义,左子树的元素比根小,右子树的元素比根大,所以我们只需要根据根结点的值与目标元素的值比较,就能实现查找功能。

参考实现代码:


    public Node search(int key) {
        Node cur = this.root;
        while (cur != null) {
            //根与目标元素相等,表示找到了。
            if (cur.val == key) return cur;
            //根比目标元素大,去左子树找。
            else if (cur.val > key) cur = cur.left;
            //根比目标元素小,去右子树找。
            else cur = cur.right;
        }
        //此时cur = null, 左右子树找不到,那就找不到了。
        return cur;
    }

2.2插入

需要在二叉搜索树中插入一个元素,首先得找到一个合适的插入位置,如何找呢?其实就是利用搜索树查找的方式,找到一个空位,如何将目标结点插入到这个位置。

2-1

由于你找到空位时,无法获取该空位的前一个位置,所以每次查找的时候都需要保存上一次查找的位置。

找到位置后,将目标结点插入到该位置。

2-2

参考实现代码:


    public boolean insert(int val) {
        //结点为空,直接插
        if(root == null) {
            root = new Node(val);
            return true;
        }
        Node cur = this.root;   //当前查找位置
        Node parent = null;     //查找的上一个位置
        while (cur != null) {
            parent = cur;
            if (val > cur.val) cur = cur.right;
            else if (val < cur.val) cur = cur.left;
            else return false;
        }
        //开始插入,找到空位前一个位置,比插入元素小,空位在右边,插入右边
        if (val > parent.val) {
            parent.right = new Node(val);
        } else {
            //比插入元素大,空位在左边,插入左边
            parent.left = new Node(val);
        }
        return true;
    }

2.3删除

删除是搜索树基本操作中最麻烦的一个操作,需要考虑多种情况。

不妨设需要删除的结点为curcur的父结点为parent,搜索树的根结点为root。首先需要删除结点,那就得找到结点,所以第一步是找结点,思路与查找的思路一模一样。

第二步那就是删除了,删除结点大概有下面几种情况:

情况1:cur.left == null

情况2:cur.right == null

情况3:cur.left != null && cur.right != null

方案1:找到cur右子树中最小的元素target,然后将该元素的值覆盖到cur处(可以理解为交换),此时等价于删除target处的结点,即该结点的父结点为preTarget

3-1

3-2

因为targetcur右子树最小的一个结点,所以target.left == null,此时preTarget.left == target,所以删除时按照上面的情况1去进行删除。

3-2-1

但是还有一种特殊情况,那就是cur.right就是最小结点,此时preTarget==cur,即preTarget.right == target,这时删除时要将 preTarget.right = target.right。

3-3

3-4

3-4--0

方案2:找到cur左子树中最大的元素target,然后将该元素的值覆盖到cur处(可以理解为交换),此时等价于删除target处的结点,即该结点的父结点为preTarget

4-1

因为targetcur左子树最大的一个结点,所以target.right == null,此时preTarget.right == target,所以删除时按照上面的情况2去进行删除。

4-2

但是还有一种特殊情况,那就是cur.left就是左子树最大结点,此时preTarget==cur,即preTarget.left == target,这时删除时要将 preTarget.left = target.left。

4-3

4-4

参考实现代码:


    public void remove(int key) {
        Node cur = root;
        Node parent = null;
        while (cur != null) {
            if(cur.val == key) {
                //这里开始删除
                removeNode(cur,parent);
                break;
            }else if(cur.val < key) {
                parent = cur;
                cur = cur.right;
            }else {
                parent = cur;
                cur = cur.left;
            }
        }
    }

removeNode方法(方案1):


    public void removeNode(Node cur,Node parent) {
        if(cur.left == null) {
            if(cur == root) {
                root = cur.right;
            }else if(cur == parent.left) {
                parent.left = cur.right;
            }else {
                parent.right = cur.right;
            }
        }else if(cur.right == null) {
            if(cur == root) {
                root = cur.left;
            }else if(cur == parent.left) {
                parent.left = cur.left;
            }else {
                parent.right = cur.left;
            }
        }else {
            Node preTarget  = cur ;
            Node target  = cur.right;
            while (target.left != null) {
                preTarget = target;
                target = target.left;
            }
            cur.val = target.val;
            if (target == preTarget.left) {
                preTarget.left = target.right;
            } else {
                preTarget.right = target.right;
            }
        }
    }

removeNode方法(方案2):


    public void removeNode(Node cur,Node parent) {
        if(cur.left == null) {
            if(cur == root) {
                root = cur.right;
            }else if(cur == parent.left) {
                parent.left = cur.right;
            }else {
                parent.right = cur.right;
            }
        }else if(cur.right == null) {
            if(cur == root) {
                root = cur.left;
            }else if(cur == parent.left) {
                parent.left = cur.left;
            }else {
                parent.right = cur.left;
            }
        }else {
            Node preTarget  = cur ;
            Node target  = cur.left;
            while (target.right != null) {
                preTarget = target;
                target = target.right;
            }
            cur.val = target.val;
            if (target == preTarget.left) {
                preTarget.left = target.left;
            } else {
                preTarget.right = target.left;
            }
        }
    }

2.4修改

搜索树的修改可以基于删除和插入,先删除目标元素,然后再插入修改元素。

参考实现代码:


    public void set(int key, int val) {
        remove(key);
        insert(val);
    }

3.二叉搜索树的性能

在平衡二叉树的情况下(左右子树高度差不超过1),假设有n个结点,此时时间复杂度为二叉树的高度,即 O ( l o g 2 n ) O(log_2n) O(log2​n),但是这只是例行情况,最不理想的情况就是二叉树化为单分支树,时间复杂为 O ( n ) O(n) O(n)。

为了解决这个问题,后面引申出AVL树,红黑树,其中TreeMap与TreeSet的底层就是红黑树。具体红黑树是什么,这里就不多说了。

本文到底了,你学会了吗?

到此这篇关于Java数据结构超详细分析二叉搜索树的文章就介绍到这了,更多相关Java 二叉搜索树内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯