广告
返回顶部
首页 > 资讯 > 精选 >Java如何实现二叉排序树
  • 389
分享到

Java如何实现二叉排序树

2023-06-28 23:06:00 389人浏览 薄情痞子
摘要

这篇文章给大家分享的是有关Java如何实现二叉排序树的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1 二叉排序树的概述对于常见查找算法,比如顺序查找、二分查找、插入查找、斐波那契查找还不清楚的,可以看这篇文章:常

这篇文章给大家分享的是有关Java如何实现二叉排序树的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

    1 二叉排序树的概述

    对于常见查找算法,比如顺序查找、二分查找、插入查找、斐波那契查找还不清楚的,可以看这篇文章:常见查找算法详解以及Java代码的实现。

    假设查找的数据集是普通的顺序存储,那么插入操作就是将记录放在表的末端,给表记录数加一即可,删除操作可以是删除后,后面的记录向前移,也可以是要删除的元素与最后一个元素互换,表记录数减一,反正整个数据集也没有什么顺序,这样的效率也不错。应该说,插入和删除对于顺序存储结构来说,效率是可以接受的,但这样的表由于无序造成查找的效率很低。

    如果查找的数据集是有序线性表,并且是顺序存储的,查找可以用折半、插值、斐波那契等查找算法来实现,可惜,因为有序,在插入和删除操作上,为了维持顺序,需要移动大量元素,就需要耗费大量的时间。

    有没有一种即可以使得插入和删除效率不错,又可以比较高效率地实现查找的算法呢?这就是二叉排序树。

    二叉排序树(Binary Sort Tree),又称为二叉查找树/二叉搜索树(binary search tree)。它是具有下列性质的二叉树

    • 若它的左子树不空,则左子树上所有节点的值均小于它的根结构的值;

    • 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

    • 它的左、右子树也分别为二叉排序树;

    • 二叉排序树也可以是一个空树。

    构造一棵二叉排序树的目的,其主要目的并不是为了排序,而是为了提高查找和插入删除关键字的速度,用以提升数据结构的综合能力。不管怎么说,在一个有序数据集上的查找,速度总是要快于无序的数据集的,而二叉排序树这种非线性的结构,也有利于插入和删除的实现。

    2 二叉排序树的构建

    2.1 类架构

    首先,最简单的节点对象还是需要一个数据域和两个引用域。

    另外还需要一个比较器的引用,因为需要对元素进行排序,自然需要比较元素的大小,如果外部传递了比较器,那么就使用用户指定的比较器进行比较,否则,数据类型E必须是Comparable接口的子类,否则因为不能比较而报错。

    另外,还需要提供中序遍历的方法,该遍历方法对于二叉排序树的结果将会顺序展示。

    public class BinarySearchTree<E> {        private BinaryTreenode<E> root;        private Comparator<? super E> cmp;        private int size;        public static class BinaryTreeNode<E> {        //数据域        E data;        //左子节点        BinaryTreeNode<E> left;        //右子节点        BinaryTreeNode<E> right;        public BinaryTreeNode(E data) {            this.data = data;        }        @Override        public String toString() {            return data.toString();        }    }        public BinarySearchTree(Comparator<? super E> cmp) {        this.cmp = cmp;    }        public BinarySearchTree() {    }        public boolean isEmpty() {        return size == 0;    }        public int size() {        return size;    }        private int compare(E e1, E e2) {        if (cmp != null) {            return cmp.compare(e1, e2);        } else {            return ((Comparable<E>) e1).compareTo(e2);        }    }        List<BinaryTreeNode<E>> str = new ArrayList<>();        public String toInorderTraversalString() {        //如果是空树,直接返回空        if (isEmpty()) {            return null;        }        //从根节点开始递归        inorderTraversal(root);        //获取遍历结果        String s = str.toString();        str.clear();        return s;    }        private void inorderTraversal(BinaryTreeNode<E> root) {        BinaryTreeNode<E> left = getLeft(root);        if (left != null) {            //如果左子节点不为null,则继续递归遍历该左子节点            inorderTraversal(left);        }        //添加数据节点        str.add(root);        //获取节点的右子节点        BinaryTreeNode<E> right = getRight(root);        if (right != null) {            //如果右子节点不为null,则继续递归遍历该右子节点            inorderTraversal(right);        }    }        public BinaryTreeNode<E> getLeft(BinaryTreeNode<E> parent) {        return parent == null ? null : parent.left;    }        public BinaryTreeNode<E> getRight(BinaryTreeNode<E> parent) {        return parent == null ? null : parent.right;    }        public BinaryTreeNode<E> getRoot() {        return root;    }}

    2.2 查找的方法

    查找的方法很简单:

    • 若根节点的关键字值等于查找的关键字,成功,返回true;

    • 否则,若小于根节点的关键字值,递归查左子树;

    • 若大于根节点的关键字值,递归查右子树;

    • 最终查找到叶子节点还是没有数据,那么查找失败,则返回false。

    public boolean contains(E e) {    return contains(e, root);}private boolean contains(E e, BinaryTreeNode<E> root) {        if (root == null) {        return false;    }        int i = compare(e, root.data);        if (i > 0) {        return contains(e, root.right);            } else if (i < 0) {        return contains(e, root.left);    } else {                return true;    }}

    2.3 插入的方法

    有了二叉排序树的查找函数,那么所谓的二叉排序树的插入,其实也就是将关键字放到树中的合适位置而已,插入操作就好像在调用查找的操作,如果找到了那么什么都不做,返回false,如果没找到,则将要插入的元素插入到遍历的路径的最后一点上:

    • 若二叉树为空。则单独生成根节点,返回true。

    • 执行查找算法,找出被插节点的父亲节点。

    • 判断被插节点是其父亲节点的左、右儿子。将被插节点作为叶子节点插入,返回true。如果原节点存在那么什么都不做,返回false。注意:新插入的节点总是叶子节点。

    public void insert(E e) {    //返回root,但此时新的节点可能已经被插入进去了    root = insert(e, root);}public void insert(E[] es) {    //返回root,但此时新的节点可能已经被插入进去了    for (E e : es) {        root = insert(e, root);    }}private BinaryTreeNode<E> insert(E e, BinaryTreeNode<E> root) {        if (root == null) {        size++;        return new BinaryTreeNode<>(e);    }        int i = compare(e, root.data);        if (i > 0) {        //重新赋值        root.right = insert(e, root.right);            } else if (i < 0) {        //重新赋值        root.left = insert(e, root.left);    } else {            }    //没查询到最底层,则返回该节点    return root;}

    1 测试

    现在我们想要构建如下一颗排序二叉树:

    Java如何实现二叉排序树

    首先要插入根节点47,然后是第二层的节点16、73,然后是第三层的节点1、24、59、88,然后是第四层的节点20、35、62、77。每一层内部节点的顺序可以不一致,但是每一层之间的大顺序一定要保持一致,否则虽然中序遍历输出的时候能够正常输出,但是树的结构不能保证。

    public class BinarySearchTreeTest {    BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<>();    @Test    public void insert() {        //首先要插入根节点47,然后是第二层的节点16,73,然后是第三层的节点1,24,59,88,然后是第四层的节点20,35,62,77。        // 每一层内部节点的顺序可以不一致,但是每一层之间的打顺序一定要保持一致,否则虽然中序遍历输出的时候能够正常输出,但是树的结构不能保证。        Integer[] es = new Integer[]{47, 16, 73, 1, 24, 59, 88, 20, 35, 62, 77};        binarySearchTree.insert(es);        //中序遍历输出        System.out.println(binarySearchTree.toInorderTraversalString());        //查找某个数据是否存在        System.out.println(binarySearchTree.contains(1));        System.out.println(binarySearchTree.contains(2));    }}

    在System.out处打上断点,Debug,可以看到树结构和我们预想的一致,如果改变层间的大顺序,那么使用Debug会发现树结构不如预期。

    Java如何实现二叉排序树

    2.4 查找最大值和最小值

    很简单,最左边的节点一定是最小的,最右边的节点一定是最大的。因此查找最小的节点只需要向左递归查找,查找最大的节点只需要向右递归查找。

    private BinaryTreeNode<E> findMin(BinaryTreeNode<E> root) {    if (root == null) {        return null;            } else if (root.left == null) {        return root;    }        return findMin(root.left);}private BinaryTreeNode<E> findMax(BinaryTreeNode<E> root) {    if (root == null) {        return null;            } else if (root.right == null) {        return root;    }        return findMax(root.right);}

    2.5 删除的方法

    对于二叉排序树的删除,就不是那么容易,我们不能因为删除了节点,而让这棵树变得不满足二叉排序树的特性,所以删除需要考虑多种情况。一共有三种情况需要考虑:

    如果查找到的将要被删除的节点没有子节点,那么很简单,直接删除父节点对于该节点的引用即可,如下图的红色节点:

    Java如何实现二叉排序树

    例如,删除20之后:

    Java如何实现二叉排序树

    如果查找到的将要被删除的节点具有一个子节点,那么也很简单,直接绕过该节点将原本父节点对于该节点的引用指向该节点的子节点即可,如下图的红色节点:

    Java如何实现二叉排序树

    例如,删除59之后:

    Java如何实现二叉排序树

    如果查找到的将要被删除的节点具有两个子节点,那么就比较麻烦了,如下图的红色节点:

    Java如何实现二叉排序树

    比如我们需要删除73,那么我们就必须要找出一个已存在的能够替代73的节点,然后删除该节点。实际上该73节点的左子树的最大节点62和右子树的最小节点77都能够替代73节点,即它们正好是二叉排序树中比它小或比它大的最接近73的两个数。

    一般我们选择一种方式即可,我们这次使用右子树的最小节点替代要删除的节点,使用77替代73之后的结构如下:

    Java如何实现二叉排序树

    完整的代码如下:

            public void delete(E e) {        //返回root,但此时可能有一个节点已经被删除了        root = delete(e, root);    }        private BinaryTreeNode<E> delete(E e, BinaryTreeNode<E> root) {                if (root == null) {            return null;        }                int i = compare(e, root.data);                if (i > 0) {            //从新赋值            root.right = delete(e, root.right);                    } else if (i < 0) {            //从新赋值            root.left = delete(e, root.left);        } else {                                    if (root.left != null && root.right != null) {                                //root.data = findMin(root.right).data;                //root.right = delete(root.data, root.right);                                root.data = findAndDeleteMin(root.right, root);                size--;            } else {                                root = (root.left != null) ? root.left : root.right;                size--;            }        }        //没查询到最底层,则返回该节点        return root;    }        private E findAndDeleteMin(BinaryTreeNode<E> root, BinaryTreeNode<E> parent) {        //如果节点为null,返回        if (root == null) {            return null;                                            } else if (root.left == null) {            //如果该节点是父节点的右子节点,说明还没进行递归或者第一次递归就找到了最小节点.            //那么此时,应该让该节点的父节点的右子节点指向该节点的右子节点,并返回该节点的数据,该节点由于没有了强引用,会被GC删除            if (root == parent.right) {                parent.right = root.right;            } else {                //如果该节点不是父节点的右子节点,说明进行了多次递归。                //那么此时,应该让该节点的父节点的左子节点指向该节点的右子节点,并返回该节点的数据,该节点由于没有了强引用,会被GC删除                parent.left = root.right;            }            //返回最小节点的数据            return root.data;        }        //递归调用,注意此时是往左查找        return findAndDeleteMin(root.left, root);    }

    1 测试

    public class BinarySearchTreeTest {    BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<>();    @Test    public void test() {        //首先要插入根节点47,然后是第二层的节点16,73,然后是第三层的节点1,24,59,88,然后是第四层的节点20,35,62,77。        // 每一层内部节点的顺序可以不一致,但是每一层之间的打顺序一定要保持一致,否则虽然中序遍历输出的时候能够正常输出,但是树的结构不能保证。        Integer[] es = new Integer[]{47, 16, 73, 1, 24, 59, 88, 20, 35, 62, 77};        binarySearchTree.insert(es);        //中序遍历输出        System.out.println(binarySearchTree.toInorderTraversalString());        //查找是否存在        System.out.println(binarySearchTree.contains(1));        System.out.println(binarySearchTree.contains(2));        //移除        binarySearchTree.delete(73);        //中序遍历输出        System.out.println(binarySearchTree.toInorderTraversalString());    }}

    3 二叉排序树的总结

    总之,二叉排序树是以链接的方式存储,保持了链接存储结构在执行插入或删除操作时不用移动元素的优点,只要找到合适的插入和删除位置后,仅需修改链接指针即可。

    插入删除的时间性能比较好。而对于二叉排序树的查找,走的就是从根节点到要查找的节点的路径,其比较次数等于给定值的节点在二叉排序树的层数。极端情况,最少为1次,即根节点就是要找的节点,最多也不会超过树的深度。也就是说,二叉排序树的查找性能取决于二叉排序树的形状。可问题就在于,二叉排序树的形状是不确定的。

    例如{47, 16, 73, 1, 24, 59, 88}这样的数组,我们可以构建下图左的二叉排序树。但如果数组元素的次序是从小到大有序,如{1, 16, 24, 47, 59, 73, 88},则二叉排序树就成了极端的右斜树,注意它依然是一棵二叉排序树,如下图右。此时,同样是查找节点88,左图只需要3次比较,而右图就需要7次比较才可以得到结果,二者差异很大。

    Java如何实现二叉排序树

    也就是说,我们希望二叉排序树是比较平衡的,即其深度与完全二叉树相同,均为|log2n+1|(|x|表示不大于x的最大整数),那么查找的时间复杂也就为O(logn),近似于折半查找,事实上,上图的左图也不够平衡,明显的左重右轻。而极端情况下的右图,则完全退化成为链表,查找的时间复杂度为O(n),这等同于顺序查找。

    因此,如果我们希望对一个集合按二叉排序树查找,最好是把它构建成一棵平衡的二叉排序树,防止极端情况的发生。这样我们就引申出另一个问题,如何让二叉排序树平衡的问题。关于这个问题,在后续的平衡二叉树(AVL树)的部分将会详细解释!

    感谢各位的阅读!关于“Java如何实现二叉排序树”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

    --结束END--

    本文标题: Java如何实现二叉排序树

    本文链接: https://www.lsjlt.com/news/321151.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Java如何实现二叉排序树
      这篇文章给大家分享的是有关Java如何实现二叉排序树的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1 二叉排序树的概述对于常见查找算法,比如顺序查找、二分查找、插入查找、斐波那契查找还不清楚的,可以看这篇文章:常...
      99+
      2023-06-28
    • python实现二叉排序树
      目录方法一(粗暴)方法二(递归)方法一(粗暴) #二叉排序树 class BTree():     def __init__(self,data):         self.lef...
      99+
      2022-11-12
    • 如何使用python实现二叉排序树
      小编给大家分享一下如何使用python实现二叉排序树,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!方法一(粗暴)#二叉排序树class BTree():    def&nb...
      99+
      2023-06-26
    • Python实现二叉排序树与平衡二叉树的示例代码
      目录前言1. 二叉排序树1.1 构建一棵二叉排序树1.2 二叉排序树的数据结构1.3 实现二叉排序树类中的方法:2. 平衡二叉排序树2.1 二叉平衡排序树的数据结构3. 总结前言 什...
      99+
      2022-11-10
    • Java排序二叉树怎么定义
      这篇文章主要介绍了Java排序二叉树怎么定义的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java排序二叉树怎么定义文章都会有所收获,下面我们一起来看看吧。排序二叉树概念二叉排序树(Binary Sort Tr...
      99+
      2023-06-30
    • Java数据结构之二叉排序树的实现
      目录1 二叉排序树的概述2 二叉排序树的构建2.1 类架构2.2 查找的方法2.3 插入的方法2.4 查找最大值和最小值2.5 删除的方法3 二叉排序树的总结1 二叉排序树的概述 本...
      99+
      2022-11-13
    • Java超详细讲解排序二叉树
      目录排序二叉树概念排序二叉树类的定义添加节点中序遍历查找节点查找某一节点的父节点删除节点排序二叉树概念 二叉排序树(Binary Sort Tree),又称二叉查找树(Binary ...
      99+
      2022-11-13
    • 最小二叉树堆排序怎么利用java 实现
      这篇文章给大家介绍最小二叉树堆排序怎么利用java 实现,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。最小二叉堆定义: 二叉堆是完全二元树或者是近似完全二元树,最小二叉堆是父结点的键值总是小于或等于任何一个子...
      99+
      2023-05-31
      java ava
    • Java如何实现平衡二叉树
      小编给大家分享一下Java如何实现平衡二叉树,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1 平衡二叉树的概述为了避免极端情况下二叉搜索树退化为链表,影响查找效率...
      99+
      2023-06-28
    • java中如何实现重建二叉树
      题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回...
      99+
      2021-06-28
      java教程 java 重建 二叉树
    • Java如何实现二叉树和遍历
      这篇文章主要介绍了Java如何实现二叉树和遍历,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。什么是二叉树简单理解为对于一个节点来说,最多拥有一个上级节点,同时最多具备左右两个...
      99+
      2023-06-29
    • JavaScript如何实现二叉树层序遍历
      今天小编给大家分享一下JavaScript如何实现二叉树层序遍历的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。题目描述给你一...
      99+
      2023-07-05
    • Java实现多叉树和二叉树之间的互转
      目录前言正文思路分析代码实现总结前言 本文主要介绍如何把一个多叉树转换成二叉树以及把二叉树还原成多叉树。 正文 给出一个多叉树,实现一个函数,这个函数可以把多叉树转成二叉树,再实现一...
      99+
      2023-05-19
      Java 多叉树和二叉树互转 Java 多叉树和二叉树互转
    • C语言实现BST二叉排序树的基本操作
      本文实例为大家分享了C语言实现BST二叉排序树的基本操作代码,供大家参考,具体内容如下 BST-二叉排序树的几个基本操作。 头文件声明与函数定义 #include <std...
      99+
      2022-11-12
    • 利用java如何实现遍历二叉树
      这篇文章给大家介绍利用java如何实现遍历二叉树,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。遍历二叉树,从上往下遍历。但是同层节点可以从左向右遍历,也可以从右向左遍历(也就是之字型遍历),其中,都需要队列进行实现。只...
      99+
      2023-05-31
      java 二叉树 遍历
    • JavaScript实现二叉树层序遍历
      目录题目描述示例递归实现代码思路解析图示队列实现代码思路解析题目描述 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。 示例 二叉树:[3...
      99+
      2023-05-14
      JavaScript二叉树遍历 JS遍历 二叉树层序遍历 JS二叉树
    • Java平衡二叉树怎么实现
      本篇内容主要讲解“Java平衡二叉树怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java平衡二叉树怎么实现”吧!什么是二叉搜索树简单来说,就是方便搜索的二叉树,是一种具备特定结构的二叉...
      99+
      2023-06-29
    • 利用java实现二叉搜索树
      目录二叉搜索树的定义实现一颗二叉搜索树二叉搜索树的定义类二叉搜索树的查找二叉搜索树的插入二叉搜索树的删除二叉搜索树的定义 它是一颗二叉树 任一节点的左子树上的所有节...
      99+
      2022-11-12
    • 用C++实现二叉树层序遍历
      这篇文章主要讲解了“用C++实现二叉树层序遍历”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“用C++实现二叉树层序遍历”吧!二叉树层序遍历从底部层序遍历其实还是从顶部开始遍历,只不过最后存储...
      99+
      2023-06-20
    • C++如何实现二叉树链表
      目录C++二叉树链表C++二叉树转链表C++二叉树链表 Node.h #ifndef NODE_H #define NODE_H #include <iostream> ...
      99+
      2022-11-13
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作