美文网首页
数据结构-树-二叉查找树

数据结构-树-二叉查找树

作者: TioSun | 来源:发表于2020-08-20 21:05 被阅读0次

二叉查找树是二叉树中比较常见且常用的类型,也叫二叉搜索树。二叉查找树要求二叉树中的任意一个节点满足以下要求

  1. 左子树中的每个节点的值都小于该节点
  2. 右子树中的每个节点的值都大于该节点
    如图所示,就是一颗二叉查找树


    二叉查找树

    下面我们来看下二叉查找树的查找、插入、删除动作是怎么实现的

二叉查找树的查找

二叉树的查找是先从根节点开始,将待查找值和当前节点(最开始是根节点)进行比较,如果比当前节点的值小,则进入其左子树重复该步骤,如果比根节点的值大,则进入其右子树重复该步骤。图示,查找一个值为21的节点


查找值21

加上代码,方便理解

package tree;

/**
 * @author TioSun
 * 二叉查找树
 */
public class BinarySearchTree {

    private TreeNode tree;
    
    public TreeNode find(int data) {
        
        TreeNode currentNode = tree;
        
        while (currentNode != null) {
            
            // 待查找值大于当前值,访问其右子树
            if (data > currentNode.data) {
                currentNode = currentNode.right;
                
            // 待查找值小于当前值,访问其左子树
            }else if (data < currentNode.data) {
                currentNode = currentNode.left;
            }else {
                return currentNode;
            }
        }
        return null;
    }


    public static class TreeNode {

        private int data;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(int data) {
            this.data = data;
        }

    }
}

二叉查找树的查找很简单,就不多说了,下面来看看二叉查找树的插入

二叉查找树的插入

和二叉查找树的搜索类似,二叉查找树的插入是将待插入值和当前节点(最开始是根节点)进行比较,如果比当前节点小,则判断其左子节点是否为空,如果为空则插入,如果不为空,则进入其左子节点重复该步骤;如果比当前节点大,则判断其右子节点是否为空,如果为空则插入,如果不为空则进入其右子节点,重复该步骤。

package tree;

/**
 * @author TioSun
 * 二叉查找树
 */
public class BinarySearchTree {

    private TreeNode tree;

    public void insert(int data) {

        if (tree == null) {
            tree = new TreeNode(data);
            return;
        }
        TreeNode currentNode = tree;

        while (currentNode != null) {

            if (data > currentNode.data) {
                if (currentNode.right == null) {
                    currentNode.right = new TreeNode(data);
                    return;
                }
                currentNode = currentNode.right;
            }else {
                if (currentNode.left == null) {
                    currentNode.left = new TreeNode(data);
                    return;
                }
                currentNode = currentNode.left;
            }
        }
    }


    public static class TreeNode {

        private int data;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(int data) {
            this.data = data;
        }

    }
}

二叉查找树的插入也很简单,下面来看下稍微复杂点的二叉查找树的删除

二叉查找树的删除

二叉查找树的删除比较复杂,根据删除的节点不同分为三种情况

  1. 删除的节点是叶子节点,则只需要将其父节点指向删除节点的指针指为null就好了,例如上图中的17。
  2. 删除的节点只有一个子节点,这种情况也比较简单,只需将删除节点的父节点指向删除节点的指针重新指向为删除节点的子节点就好,以上图为例,要删除节点8,只需将11指向8的指针指向10就可以了。
  3. 删除的节点有两个子节点,这种情况是比较复杂的,我们需要将待删除节点上的值赋值为其右子树上的最小节点的值,然后再删除掉这个最小的节点,由于是最小的节点,所以肯定没有左子节点,所以只需要再参照第一条或第二条的方式删除即可。
package tree;

/**
 * @author TioSun
 * 二叉查找树
 */
public class BinarySearchTree {

    private TreeNode tree;

    public void delete (int data) {

        TreeNode needDelete = tree;
        TreeNode needDeleteParent = null;

        // 定位需要删除的节点。
        while (needDelete != null && needDelete.data != data) {
            needDeleteParent = needDelete;
            if (data > needDelete.data) {
                needDelete = needDelete.right;
            }else {
                needDelete = needDelete.left;
            }
        }
        if (needDelete == null) {
            return;
        }
     
        // 第三种情况,待删除节点的左右子节点都不为空
        if (needDelete.left != null && needDelete.right != null) {
            TreeNode minNode = needDelete.right;
            TreeNode minNodeParent = needDelete;
            
            while (minNode.left != null) {
                minNodeParent = minNode;
                minNode = minNode.left;
            }
            // 将待删除的节点用其右子树下的最小节点替换
            needDelete.data = minNode.data;
            // 将待删除的节点定位到最小节点上
            needDelete = minNode;
            needDeleteParent = minNodeParent;
        }
        // 删除只有一个或零个子节点的节点
        // 获取要删除的节点的子节点
        TreeNode child = null;
        if (needDelete.left != null) {
            child = needDelete.left;
        }else if (needDelete.right != null) {
            child = needDelete.right;
        }
        // parentNode为空,说明要删除的是根节点
        if (needDeleteParent == null) {
            tree = child;
        }
        // 如果要删除的是parent的左子节点,则将左子节点重新指向待删除节点的子节点
        if (needDeleteParent.left == needDelete) {
            needDeleteParent.left = child;
        }else {
            // 如果要删除的是parent的右子节点,则将右子节点重新指向待删除节点的子节点
            needDeleteParent.right = child;
        }
    }


    public static class TreeNode {

        private int data;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(int data) {
            this.data = data;
        }
    }
}

除了上述的常规操作以外,二叉树还支持快速查找最大值(不停的right),最小值(不停的left)以及输出有序序列(中序遍历)等,就不一一用代码展示了。

如何处理重复数据

对于重复数据的处理,一般有两种做法

  1. 第一种做法比较简单好懂,以上文为例,就是将data变成一个数组或链表结构去存储相关数据。
  2. 第二种比较不好理解,但是形式上可能更加优雅。下面详细介绍第二种做法
重复数据的插入

重复数据的插入,我们可以将其插入已存在数据的右子树上,插入逻辑和普通的插入逻辑相同。

重复数据的查询

重复数据的查询,我们可以在查到相关数据后,不直接返回,而是继续往其右子树上查找,直到查到叶子节点为止,输出的也是一串符合查找条件的值。

重复数据的删除

重复数据的删除也和普通的删除类似,不过也是往右子树上遍历去删除所有满足条件的节点。

相关文章

  • 数据结构 - 概要

    数组 链表 堆/栈/队列 树 数据结构 - 二叉树数据结构 - 二叉查找树数据结构 - 平衡二叉树数据结构 - A...

  • 11-二叉查找树

    二叉查找树 1.什么是二叉查找树? 二叉查找树是一种支持数据动态的插入,删除,查找的数据结构。 2.二叉查找树的设...

  • 红黑树初步理解

    为什么? 为什么要学习红黑树?我们数据结构中学习过二叉查找树,二叉查找树可以增大查找的效率,但是二叉查找树有一个巨...

  • 红黑树

    红黑树是一种平衡二叉查找树。发明平衡二叉查找树这类数据结构的初衷是,解决普通二叉查找树在频繁的插入、删除等动态更新...

  • 揭开红黑树的神秘面纱

    在了解红黑树之前,先了解下查找树与二叉查找树 。 查找树(search tree) 查找树 是一种数据结构,它支持...

  • 不可多得的后端架构师技术图谱!内附参考资料!

    数据结构 二叉树 完全二叉树 平衡二叉树 二叉查找树(BST) 红黑树 B-,B+,B*树 LSM 树 队列 集合...

  • 数据结构之二叉树(一)——绪论

    前言 二叉树是数据结构中一种重要的数据结构,也是树表家族最为基础的结构,包括完全二叉树、满二叉树、二叉查找树、AV...

  • 算法和数据结构1.8二叉查找树

    二叉查找树(二叉搜索树或二叉排序树)是一种数据结构。采用了图的树形结构。数据存储于二叉查找树的各个结点中。 二叉查...

  • 后端架构师技术图谱

    数据结构队列集合链表、数组字典、关联数组栈树二叉树完全二叉树平衡二叉树二叉查找树(BST)红黑树B-,B+,B*树...

  • 后端架构师技术图谱(一)

    数据结构队列集合链表、数组字典、关联数组栈树二叉树完全二叉树平衡二叉树二叉查找树(BST)红黑树B-,B+,B*树...

网友评论

      本文标题:数据结构-树-二叉查找树

      本文链接:https://www.haomeiwen.com/subject/lyuejktx.html