JAVA笔记 ------ 比较器和二叉树练习

本文介绍了Java中Comparable接口和Comparator类在对象排序中的应用,讲解了如何使用它们对Person对象数组进行排序。此外,还探讨了二叉树结构,特别是二叉搜索树的插入和删除操作,以及数据结构转换为数组的方法。文章通过实例代码详细展示了其实现过程,强调了数据结构选择对效率的影响,并提到了红黑树作为更高级的平衡二叉树概念。
摘要由CSDN通过智能技术生成

比较器和二叉树

比较器

  • 所谓的比较器就是我们进行大小关系的一个判断!
  • 比较器还能对对象数组进行排序,但是排序需要用到比较器的。
  • 而其中数组的Arrays类里面的sort方法就可以进行排序,但是想要进行sort方法进行排序,必须使用的类里面要完成比较器的比较方法,才可以使用sort排序,否则就会报错。

在这里插入图片描述

  • 就是要实现Comparable接口里面的compareTo方法,代码如下:
import java.lang.reflect.Array;
import java.util.Arrays;

class Person implements Comparable<Person>{
    private String name;
    private int age;
    public Person(String name,int age){
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString(){
        return "【person对象】姓名:" + this.name + "、年龄:" + this.age;
    }

    @Override
    public int compareTo(Person o) {
        return this.age - o.age;
    }
}
public class 比较器练习 {
    public static void main(String[] args) {
        Person [] ans = new Person[]{
                new Person("小明",100),
                new Person("小红",80),
                new Person("小白",60),
                new Person("小黑",20)
        };
        Arrays.sort(ans);
        System.out.println(Arrays.toString(ans));
    }
}

  • 我们可以知道的是,如果Person类没有对compareTo方法进行实现的话,主函数里面的对象数组是无法完成排序的。
  • 所以,如果以后遇到了对象数组排序,那么一定要使用Comparable接口来实现排序;

Comparator

  • 属于一种挽救的排序功能,在后期无法对类进行修改的时候,可以使用;

在这里插入图片描述

  • 可利用这个类进行排序规则的定义!
  • 代码如下:
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;

class PersonComparator implements Comparator<Person>{
    @Override
    public int compare(Person person1, Person person2) {
        return person1.getAge() - person2.getAge();
    }
}
class Person {
    private String name;
    private int age;
    public Person(String name,int age){
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString(){
        return "【person对象】姓名:" + this.name + "、年龄:" + this.age + "\n";
    }
}
public class 比较器练习 {
    public static void main(String[] args) {
        Person [] ans = new Person[]{
                new Person("小明",100),
                new Person("小红",80),
                new Person("小白",60),
                new Person("小黑",20)
        };
        Arrays.sort(ans,new PersonComparator());
        System.out.println(Arrays.toString(ans));
    }
}
  • 这就是挽救型的排序比较;
  • 但是呢,这边建议,如果不是必须的情况下,还是使用第一种Comparable接口会比较好一点。

面试题:请解释Comparable与Comparator两个接口的区别?

  • java.lang.Comparable是在类定义的时候实现的父接口,主要用于比较排序定义排序规则,里面也只有一个compareTo方法。
  • java.util.Comparator是挽救型的比较器操作,需要设置单独的比较器规则类实现排序里面有compare方法。

二叉树结构

  • 在进行链表结构学习的时候呢,对于每一种操作他们的复杂度都是O(n),那么在30以内的时候还能接受,但是当里面的数据变得很大的时候,那么复杂度就会直线上升。所以,我们只能够换数据结构,那么二叉树就是解决问题的方法,他可以将复杂度调至到O(logn)。
  • 这个我们还是可以接受的。
  • 那么二叉树的实现原理如下:

取第一个数据为保存的根节点,小于或等于根节点的节点要放在根节点的左子树,而大于节点的数据,要放在该节点的右子树。

在这里插入图片描述

  • 那么实现二叉树的处理中最为关键的就是数据的保存,那么数据的保存一定要有比较器的支持,而且比较器的我们首选的应该是Comparable接口的实现。

二叉树的实现


import java.util.Arrays;

class BinaryTree <T extends Comparable<T>> {
    private class Node {
        private Comparable<T> data;     //存放Comparable,可以进行比较
        private Node parent;
        private Node right;
        private Node left;
        public Node(Comparable<T> data){  //构造方法直接进行数据的存储
            this.data = data;
        }
        // Node内部类增加节点addNode方法
        public void addNode(Node newNode){
            if(newNode.data.compareTo( (T)this.data ) <= 0){
                if(this.left == null){
                    this.left = newNode;
                    newNode.parent = this;
                }else{
                    this.left.addNode(newNode);
                }
            }else{
                if(this.right == null){
                    this.right = newNode;
                    newNode.parent = this;
                }else{
                    this.right.addNode(newNode);
                }
            }
        }
        // Node内部类数据转换成数组toArrayNode方法
        public void toArrayNode(){
            if(this.left != null){
                this.left.toArrayNode();
            }
            BinaryTree.this.returnData[BinaryTree.this.foot ++ ] = this.data;
            if(this.right != null){
                this.right.toArrayNode();
            }
        }

    }
    /* -------------- 以下是二叉树的的功能实现 ------------ */
    private Node root;          //保存的根节点
    private int count;          //保存数据的个数
    private int foot = 0;
    private Object [] returnData;

    public void add(Comparable<T> data){
        if(data == null){
            throw new NullPointerException("保存的数据不允许为空");
        }
        Node newNode = new Node(data);
        if(this.root == null){
            this.root = newNode;
        }else{
            this.root.addNode(newNode);
        }
        this.count ++ ;
    }
    public Object [] toArray(){
        if(this.count == 0){
            return null;
        }
        this.returnData = new Object[this.count];
        this.foot = 0;
        this.root.toArrayNode();
        return returnData;
    }
}
public class 二叉树练习 {
    public static void main(String[] args) {
        BinaryTree<Person> tree = new BinaryTree<Person>();
        tree.add(new Person("小黑",20));
        tree.add(new Person("小红",30));
        tree.add(new Person("小白",40));
        tree.add(new Person("小绿",60));
        tree.add(new Person("小蓝",50));
        tree.add(new Person("小灰",100));
        System.out.println(Arrays.toString(tree.toArray()));
    }
}

  • 我们采用内部类的i形式,就可以完成了二叉数的基本实现了,二叉数在保存完节点以后,在内部里面就会完成排序。所以输出的就是有序的。

二叉树的数据删除

二叉树的数据删除是非常复杂的,因为考虑的东西挺多的,如下:

  • 情况1 :如果删除的节点没有子节点,那么就可以直接删除。

在这里插入图片描述

  • 情况2 :如果待删除的节点只有一个子节点,那么直接删除,用它的子节点去替换它。
  • 但是这里要考虑两种情况,一个是这个唯一的子节点是左子节点,还有就是右子节点。但是删除的方式相同

在这里插入图片描述

  • 情况3 :如果删除的节点里面有两个子节点,先直接删除节点,然后用其右节点的最后的左节点进行顶包。

在这里插入图片描述

  • 这就是删除数据的三种情况了,我们下面进行代码完成:
import jdk.nashorn.internal.ir.BinaryNode;

import java.util.Arrays;

class BinaryTree <T extends Comparable<T>> {
    private class Node {
        private Comparable<T> data;     //存放Comparable,可以进行比较
        private Node parent;
        private Node right;
        private Node left;

        public Node(Comparable<T> data) {  //构造方法直接进行数据的存储
            this.data = data;
        }

        // Node内部类增加节点addNode方法
        public void addNode(Node newNode) {
            if (newNode.data.compareTo((T) this.data) <= 0) {
                if (this.left == null) {
                    this.left = newNode;
                    newNode.parent = this;
                } else {
                    this.left.addNode(newNode);
                }
            } else {
                if (this.right == null) {
                    this.right = newNode;
                    newNode.parent = this;
                } else {
                    this.right.addNode(newNode);
                }
            }
        }

        // Node内部类数据转换成数组toArrayNode方法
        public void toArrayNode() {
            if (this.left != null) {
                this.left.toArrayNode();
            }
            BinaryTree.this.returnData[BinaryTree.this.foot++] = this.data;
            if (this.right != null) {
                this.right.toArrayNode();
            }
        }
        //Node内部类判断数据是否存在   (可以省略)
        public boolean containsNode(Comparable<T> data) {
            if(data.compareTo((T)this.data) == 0){
                return true;
            }else if(data.compareTo((T)this.data) < 0){
                if(this.left != null){
                    return this.left.containsNode(data);
                }else {
                    return false;
                }
            }else {
                if(this.right != null){
                    return this.right.containsNode(data);
                }else{
                    return false;
                }
            }
        }
        //Node类,返回查找到的节点
        public Node getRemoveNode(Comparable<T> data){
            if(data.compareTo((T)this.data) == 0){
                return this;
            }else if(data.compareTo((T)this.data) < 0){
                if(this.left != null){
                    return this.left.getRemoveNode(data);
                }else{
                    return null;
                }
            }else {
                if(this.right != null){
                    return this.right.getRemoveNode(data);
                }else{
                    return null;
                }
            }
        }
    }
    /* -------------- 以下是二叉树的的功能实现 ------------ */
    private Node root;          //保存的根节点
    private int count;          //保存数据的个数
    private int foot = 0;
    private Object [] returnData;

    //BinaryTree类的增加数据方法
    public void add(Comparable<T> data){
        if(data == null){
            throw new NullPointerException("保存的数据不允许为空");
        }
        Node newNode = new Node(data);
        if(this.root == null){
            this.root = newNode;
        }else{
            this.root.addNode(newNode);
        }
        this.count ++ ;
    }
    //BinaryTree类的数据转换成数组方法
    public Object [] toArray(){
        if(this.count == 0){
            return null;
        }
        this.returnData = new Object[this.count];
        this.foot = 0;
        this.root.toArrayNode();
        return returnData;
    }
    //BinaryTree类判断数据是否存在
    public boolean contains(Comparable<T> data){
        if(this.count == 0)return false;
        return this.root.getRemoveNode(data) != null;
    }
    //BinaryTree类返回二叉数的大小
    public int getCount(){
        return this.count;
    }
    //BinaryTree类的数据删除方法
    public void remove(Comparable<T> data){
        if(this.root == null){
            return ;
        }else{
            if(this.root.data.compareTo((T)data) == 0){
                Node moveNode = this.root.right;
                while(moveNode.left != null){
                    moveNode = moveNode.left;
                }
                moveNode.left = this.root.left;
                moveNode.right = this.root.right;
                moveNode.parent.left = null;
                this.root = moveNode;
                this.count --;
            }else{
                Node removeNode = this.root.getRemoveNode(data);
                if(removeNode != null){
                    this.count -- ;
                    //情况一
                    if(removeNode.left == null && removeNode.right ==null){
                        if(removeNode.parent.left != null && removeNode.data.compareTo((T)removeNode.parent.left.data) == 0){
                            removeNode.parent.left = null;
                            removeNode.parent = null;
                        }else{
                            removeNode.parent.right = null;
                            removeNode.parent = null;
                        }
                    }else if(removeNode.left != null && removeNode.right == null){  //情况二_1
                        if(removeNode.parent.left != null && removeNode.data.compareTo((T)removeNode.parent.left.data) == 0){
                            removeNode.parent.left = removeNode.left;
                            removeNode.left.parent = removeNode.parent;
                            removeNode.parent = null;
                        }else{
                            removeNode.parent.right = removeNode.left;
                            removeNode.left = removeNode.parent;
                            removeNode.parent = null;
                        }
                    }else if(removeNode.left == null && removeNode.right != null){  //情况二_2
                        if(removeNode.parent.left != null && removeNode.data.compareTo((T)removeNode.parent.left.data) == 0){
                            removeNode.parent.left = removeNode.right;
                            removeNode.right = removeNode.parent;
                            removeNode.parent = null;
                        }else{
                            removeNode.parent.right = removeNode.right;
                            removeNode.right = removeNode.parent;
                            removeNode.parent = null;
                        }
                    }else{
                        Node moveNode = removeNode.right;
                        while(moveNode.left != null){
                            moveNode = moveNode.left;
                        }
                        if(removeNode.data.compareTo((T)moveNode.parent.data) == 0){
                            moveNode.parent.right = moveNode.right;
                        }else{
                            moveNode.parent.left = moveNode.right;
                        }
                        //判断要删除的节点是在他父亲节点的左边还是右边
                        if(removeNode.parent.left != null && removeNode.parent.left.data.compareTo((T)removeNode.data) == 0){
                            removeNode.parent.left = moveNode;
                        }else{
                            removeNode.parent.right = moveNode;
                        }
                        moveNode.right = removeNode.right;
                        moveNode.left = removeNode.left;
                    }
                }
            }
        }
    }
}
public class 二叉树练习 {
    public static void main(String[] args) {
        BinaryTree<Person> tree = new BinaryTree<Person>();
        Person ans1 = new Person("小白",80);
        Person ans2 = new Person("小黑",50);
        Person ans3 = new Person("小红",90);
        Person ans4 = new Person("小绿",10);
        Person ans5 = new Person("小蓝",60);
        Person ans6 = new Person("小灰",85);
        Person ans7 = new Person("aa",95);
        tree.add(ans1);
        tree.add(ans2);
        tree.add(ans3);
        tree.add(ans4);
        tree.add(ans5);
        tree.add(ans6);
        tree.add(ans7);
        tree.add(new Person("小青",55));
        tree.add(new Person("小青",65));
        tree.remove(new Person("xaio",50));
        System.out.println(Arrays.toString(tree.toArray()));
        System.out.println(tree.getCount());
    }
}

  • 说实在话,这个删除数据是真的把我搞哭了,搞了一个下午;
  • 第三种情况,思维固化了,最最最主要的是,视频老师没有备课,导致出现了好多bug,最后还是自己把他撸出来了,害,太累了,我要去吐槽;

红黑树原理分析

  • 这里重点理解,害,冲冲冲冲;
  • 红黑树呢,在本质上面,他是又给二叉查找树,但是他在二叉查找树的原有基础上面添加了一个标记。同时具有一定的规则,这些规则使得二叉树,能够保存平衡。

在这里插入图片描述

  • 那么他有什么特点呢,让我们来看看把,这可是很重要的,详细理解哦!!!

在这里插入图片描述

在这里插入图片描述

  • 这个还是太负责了,下次单独列一篇写。咳咳。。。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值