当前位置:   article > 正文

恋上数据结构与算法:二叉搜索树01(十二)_恋上数据结构与算法打印器

恋上数据结构与算法打印器

文章目录

(一)二叉搜索树(Binary Search Tree)的需求分析
(二)二叉搜索树(Binary Search Tree)的概念
(三)二叉搜索树(Binary Search Tree)的设计
(四)二叉搜索树(Binary Search Tree)之add:根节点
(五)二叉搜索树(Binary Search Tree)之add:思路
(六)二叉搜索树(Binary Search Tree)之add:实现
(七)二叉搜索树(Binary Search Tree)之compare:comparable
(八)二叉搜索树(Binary Search Tree)之compare:comparator
(九)二叉搜索树(Binary Search Tree)之compare:完美结合
(十)二叉搜索树(Binary Search Tree)之compare:匿名类
(十一)二叉搜索树(Binary Search Tree)之打印器:基本使用
(十二)二叉搜索树(Binary Search Tree)之打印器:Person类
(十三)二叉搜索树(Binary Search Tree)之打印器:更多用法
(十四)二叉搜索树(Binary Search Tree)之打印器:文件
(十五)二叉搜索树(Binary Search Tree):网站推荐
(十六)二叉搜索树(Binary Search Tree):值相等的处理

(一)二叉搜索树(Binary Search Tree)的需求分析

在这里插入图片描述
说明

  1. 二分搜索使得复杂度每次都减半,最坏复杂度就是logn(记住)
  2. 对于上面的有序的动态数组(无序的话添加很快,加在后面就可以了,但是删除依然很慢),无论是增加元素还是删除元素,都应该先做一次搜索,如果使用普通的搜索复杂度肯定是O(n),使用二分搜索最坏复杂度可以降低到O(logn)
  3. 归根结底是要解决搜索的问题

(二)二叉搜索树(Binary Search Tree)的概念

在这里插入图片描述
说明

  1. 任意一个节点的值都大于左子树所有节点的值(不是之和)
    在这里插入图片描述
  2. 任意一个节点的值都小于右子树所有节点的值(不是之和)
    在这里插入图片描述
  3. 它的左右子树也是一颗二叉搜索树,也满足上面两点规律

(三)二叉搜索树(Binary Search Tree)的设计

在这里插入图片描述
说明:对于之前的数组链表都有索引(int index)的概念,但是二叉搜索树没有索引
原因:二叉树是树形结构,非线性结构没办法标索引

代码大致框架如下:
在这里插入图片描述

(四)二叉搜索树(Binary Search Tree)之add:根节点

首先写一个Node内部类,如下:

    private static class Node<E> {
        E element;
        Node<E> left;
        Node<E> right;
        Node<E> parent;

        public Node(E element, Node<E> parent) {
            this.element = element;
            this.parent = parent;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

构造节点的时候传递的element通常是不允许为null的,写一个检查的方法,如下:

    private void elementNotNullCheck(E element) {
        if (element == null) {
            throw new IllegalArgumentException("element must not be null");
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5

第一次添加节点,添加的是根节点,如下:
在这里插入图片描述

    public void add(E element) {
        elementNotNullCheck(element);
        //添加第一个节点
        if (root == null) {
            root = new Node<>(element, null);
            size++;
            return;
        }
        //添加的不是第一个节点
        
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

(五)二叉搜索树(Binary Search Tree)之add:思路

对下面这颗二叉树添加121,如下:
在这里插入图片描述
添加之后,结果如下:
在这里插入图片描述
过程:以添加12为例,首先用12跟7比较,发现12比7大,就继续找7的右节点
以此类推,找到最后发现还是比11大,就把12放在11右节点

步骤

  1. 找到父节点parent
  2. 创建新节点node
  3. parent.left = node或者parent.right = node

遇到值相等的元素该如何处理?建议覆盖旧的值

(六)二叉搜索树(Binary Search Tree)之add:实现

先写一个compare(E e1, E e2)方法实现比较功能,但是先留空,如下:

    /**
     * 返回值等于0,代表e1等于e2
     * 返回值大于0,代表e1大于e2
     * 返回值小于0,代表e1小于e2
     *
     * @param e1
     * @param e2
     * @return
     */
    private int compare(E e1, E e2) {
        return 0;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

add(E element)方法如下:

public void add(E element) {
        elementNotNullCheck(element);
        //添加第一个节点
        if (root == null) {
            root = new Node<>(element, null);
            size++;
            return;
        }
        //添加的不是第一个节点
        Node<E> node = root;//找到父节点
        Node<E> parent = null;//用于保存父节点
        int cmp = 0;//用于记录方向(左还是右)
        while (node != null) {//只有node不为空,才拿node的值跟element做比较
            cmp = compare(element, node.element);//记录方向
            parent = node;//保存父节点,否则while循环结束,node为null,无法进行下一步操作
            if (cmp > 0) {
                node = node.right;//拿node的右节点继续做比较
            } else if (cmp < 0) {
                node = node.left;//拿node的左节点继续做比较
            } else {//相等
                return;//最好是替换,这里先直接返回
            }
        }
        //看插入到父节点的哪个位置
        Node<E> newNode = new Node<>(element, parent);//创建一个新节点
        if (cmp > 0) {
            parent.right = newNode;
        } else {
            parent.left = newNode;
        }
        size++;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

(七)二叉搜索树(Binary Search Tree)之compare:comparable

首先编写一个Comparable接口,如下:
在这里插入图片描述
我们让BinarySearchTree里面的泛型E继承Comparable接口
在这里插入图片描述
BinarySearchTree里的元素必须实现Comparable接口,并重写int compareTo(E e)方法,如下:
在这里插入图片描述
Person类中重写int compareTo(E e)方法,并且在BinarySearchTree中调用,如下:
在这里插入图片描述

(八)二叉搜索树(Binary Search Tree)之compare:comparator

二叉搜索树要求小的节点放在左子树,大的节点放在右子树,两种情况如下:
在这里插入图片描述
而刚才继承comparable接口的写法就会存在弊端,如下:
在这里插入图片描述
如果我再创建一颗树(bst3),那么这两棵树只能都是:年龄小的节点小年龄小的节点大
如果我想bst2属于年龄小的节点小,而bst3属于年龄小的节点大就需要用下面这种方法了

首先编写一个Comparator接口,如下:
在这里插入图片描述
通过构造函数的方法传递比较器接口,如下:
在这里插入图片描述
这样就可以实现个性化比较器了,如下:
在这里插入图片描述
BinarySearchTree把上一个比较器相关的代码注释掉,如下:
在这里插入图片描述
最后修改compare(E e1, E e2)方法,如下:
在这里插入图片描述

(九)二叉搜索树(Binary Search Tree)之compare:完美结合

我们理想的状态是:

  1. 不传递比较器接口就默认使用自带的comparable接口
  2. 传递比较器接口就使用传递的comparator接口

我们接下来将这两者进行完美结合

再写一个空参的构造方法,如下:
在这里插入图片描述
修改compare(E e1, E e2)方法,如下:
在这里插入图片描述

其实刚才写的Comparable接口和Comparator接口都可以删掉,JDK官方给我们提供了一样的接口

(十)二叉搜索树(Binary Search Tree)之compare:匿名类

除了像刚才那样让一个去实现接口以外(如下),JDK官方还提供匿名类的写法
在这里插入图片描述
写法如下:
在这里插入图片描述

注意

  1. Java的匿名类类似于IOS中的Block、JS中的闭包(function)
  2. 类似于Integer这类包装类,本身就实现了Comparable接口,如下:
    在这里插入图片描述

(十一)二叉搜索树(Binary Search Tree)之打印器:基本使用

我们要怎么样才能看到二叉树打印的结果呢?
在这里插入图片描述
打开 http://520it.com/binarytrees/ 选中二叉搜索树,然后 输入相关节点的值,如下:
在这里插入图片描述

上面的是预期效果,实际代码写得对不对要在代码中验证

首先把资料包中的printer文件夹拷贝过来,如下:
在这里插入图片描述
二叉搜索树实现BinaryTreeInfo接口,如下:
在这里插入图片描述
并且重写4个方法,如下:
在这里插入图片描述
最后调用静态方法打印即可,如下:
在这里插入图片描述
传递不同的参数,会打印出不同的效果,如下:
在这里插入图片描述

(十二)二叉搜索树(Binary Search Tree)之打印器:Person类

重写Person类的toString()方法,如下:
在这里插入图片描述
效果如下:
在这里插入图片描述

(十三)二叉搜索树(Binary Search Tree)之打印器:更多用法

可以把parent也打印出来,方便后期调试,如下:
在这里插入图片描述
使用匿名类的写法,可以打印任意东西,不局限于打印二叉树
在这里插入图片描述

(十四)二叉搜索树(Binary Search Tree)之打印器:文件

首先把资料包里面的file文件夹拷贝过来,如下:
在这里插入图片描述
最后调用即可,如下:
在这里插入图片描述
注意:重载方法的第三个参数,是指是否追加到文件末尾
在这里插入图片描述

(十五)二叉搜索树(Binary Search Tree):网站推荐

http://520it.com/binarytrees/
http://btv.melezinek.cz/binary-search-tree.html
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

(十六)二叉搜索树(Binary Search Tree):值相等的处理

在这里插入图片描述
这样做的好处是对于自定义对象而言的,比如说之前的Person类用于比较的是age,两个age相等的Person对象在二叉树看来是等价的,但是他们的其它字段可能不一样,所以最好还是用新的覆盖旧的

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/615143
推荐阅读
相关标签
  

闽ICP备14008679号