28、比较器

Arrays类

  1. Arrays类是java.util工具包中的一个类,主要用于对数组进行操作。
  2. 在Arrays类中存在有二分查找法:public static int binarySearch(数据类型[] a, 数据类型 key)
    二分查找举例:在1,2,3,4,5,6,7,8,9中找到2。
    先找到5,判断可得,2 比5小;在1-5间继续找,先找到3,2比3小;在1~3间继续找,找到了2。由该过程可得,二分查找前,数据必须进行排序。
    范例 :二分查找
import java.util.Arrays;

public class Demo {
    public static void main(String[] args) throws Exception {
        int data[] = new int[]{1, 9, 5, 7, 2, 3, 4, 6, 10, 8};
        // 未进行排序,二分查找可能失败,结果为负数
        System.out.println(Arrays.binarySearch(data, 9)); // -9
        java.util.Arrays.sort(data);
        // 数组排序后,二分查找成功
        System.out.println(Arrays.binarySearch(data, 9));
    }
}
  1. 在Arrays类中提供了数组比较equals(),该方法与Object类中的equals()没有任何关系:
    public static boolean equals(数据类型[] a, 数据类型[] a2)
    范例:实现数组比较
import java.util.Arrays;

public class Demo {
    public static void main(String[] args) throws Exception {
        int dataA[] = new int[]{1, 2, 3};
        int dataB[] = new int[]{2, 1, 3};
        int dataC[] = new int[]{1, 2, 3};
        System.out.println(Arrays.equals(dataA, dataB)); // false
        System.out.println(Arrays.equals(dataA, dataC)); // true
    }
}

如果要使得数据判断为相同,数组中的元素顺序必须一致,因为该方法是按照顺序一个个比较元素的。
4. 在Arrays类中提供
·填充数组的方法:public static void fill(数据类型[] a, 数据类型 val);
·将数组变为字符串输出:public static String toString(数据类型[] a);

import java.util.Arrays;

public class Demo {
    public static void main(String[] args) throws Exception {
        int data[] = new int[10];
        Arrays.fill(data, 3); // 填充数组
        System.out.println(Arrays.toString(data)); // 将数组变为字符串输出
    }
}

Comparable接口

  1. Arrays类中提供的数组排序方法:
    · 对象数组排序:public static void sort(Object[] a);
    范例:使用sort()进行数组排序
import java.util.Arrays;

class Book {
    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    @Override
    public String toString() {
        return "书名:" + this.title + ",价格:" + this.price;
    }
}

public class Demo {
    public static void main(String[] args) throws Exception {
        Book books[] = new Book[]{
                new Book("Java开发", 66.6),
                new Book("JSP", 36.6),
                new Book("C++", 86.6),
                new Book("C", 16.6)
        };
        Arrays.sort(books); // 对象数组排序
        System.out.println(Arrays.toString(books));
    }
}

上述代码没有任何语法错误,但是执行后发生了异常

Exception in thread “main” java.lang.ClassCastException: com.java.demo.Book cannot be cast to java.lang.Comparable
at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:188)
at java.util.Arrays.sort(Arrays.java:1246)
at com.java.demo.Demo.main(Demo.java:28)

造成这种异常的原因是两个没有关系的类对象发生了强制转换。
2. 每一个对象只保留有地址信息,地址中是有内容的,所以int型数组比较,只要判断大小;而对象数组,里面包含的只是编码(地址)比较是没意义的,像上述代码,按照价格排序才是有意义的,所以此处必须明确地设置出比较的规则。
比较的规则就是由Comparable接口定义的,此接口定义如下:
public interface Comparable<T> { public int compareTo(T o); }
实际上String类是Comparable接口的子类,之前使用的compareTo()方法就是比较的操作功能,如果现在要进行对象比较,建议compareTo()返回三类数据:1(大于)0(等于)-1(小于)
范例:使用比较器

import java.util.Arrays;

class Book implements Comparable<Book> { // 实现比较
    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    @Override
    public String toString() {
        return "书名:" + this.title + ",价格:" + this.price + "\n";
    }

    @Override
    public int compareTo(Book o) { // Arrays.sort()会自动调用此方法
        if (this.price > o.price) {
            return 1;
        } else if (this.price < o.price) {
            return -1;
        } else {
            return 0;
        }
    }
}

public class Demo {
    public static void main(String[] args) throws Exception {
        Book books[] = new Book[]{
                new Book("Java开发", 66.6),
                new Book("JSP", 36.6),
                new Book("C++", 86.6),
                new Book("C", 16.6)
        };
        Arrays.sort(books); // 对象数组排序
        System.out.println(Arrays.toString(books));
    }
}

总结:

只要是一组对象要进行排序,对象所在的类一定要实现Comparable接口。

二叉树实现

  1. 树是一种比链表更复杂的概念,本质上也属于动态数组。但是与链表的不同在于,树可以针对数据进行排序。
    树的操作原理:选择第一个数据作为根节点,而后比根节点小的数据放在根节点的左子树(左节点),比根节点大的数据放在右子树(右节点),取得的数据按照中序遍历的方式取出结果(左-中-右顺序)。
    在任何数据结构中Node类的核心功能是保存真实数据以及配置节点关系。二叉树举例图:
    在这里插入图片描述
    范例:实现二叉树
    · 第一步:定义数据所在的类,该类要实现Comparable接口
class Book implements Comparable<Book> { // 实现比较
    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    @Override
    public String toString() {
        return "书名:" + this.title + ",价格:" + this.price + "\n";
    }

    @Override
    public int compareTo(Book o) { // Arrays.sort()会自动调用此方法
        if (this.price > o.price) {
            return 1;
        } else if (this.price < o.price) {
            return -1;
        } else {
            return 0;
        }
    }
}

· 定义二叉树,所有数据结构都需要Node类的支持

import java.util.Arrays;

class Book implements Comparable<Book> { // 实现比较
    private String title;
    private double price;

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    @Override
    public String toString() {
        return "书名:" + this.title + ",价格:" + this.price + "\n";
    }

    @Override
    public int compareTo(Book o) { // Arrays.sort()会自动调用此方法
        if (this.price > o.price) {
            return 1;
        } else if (this.price < o.price) {
            return -1;
        } else {
            return 0;
        }
    }
}

class BinaryTree {
    private class Node {
        private Comparable data; // 排序的依据就是Comparable
        private Node left; // 左节点
        private Node right; // 右节点

        @SuppressWarnings("unused")
        public Node(Comparable data) {
            this.data = data;
        }

        public void addNode(Node newNode) {
            if (this.data.compareTo(newNode.data) < 0) {
                if (this.left == null) {
                    this.left = newNode;
                } else {
                    this.left.addNode(newNode);
                }
            } else {
                if (this.right == null) {
                    this.right = newNode;
                } else {
                    this.right.addNode(newNode);
                }
            }
        }

        public void toArrayNode() {
            if (this.left != null) {
                this.left.toArrayNode(); // 左子树输出
            }
            BinaryTree.this.retData[BinaryTree.this.foot++] = this.data;
            if (this.right != null) {
                this.right.toArrayNode(); // 右子树输出
            }
        }
    }

    // ==========================内部类===============================
    private Node root; // 根节点
    private int count; // 元素个数
    private Object[] retData;
    private int foot;

    public void add(Object obj) { // 数据添加
        Comparable com = (Comparable) obj; // 必须变为Comparable才能实现Node保存
        Node newNode = new Node(com); // 创建新节点
        if (this.root == null) { // 根节点不存在
            this.root = newNode; // 保存为根节点
        } else {
            this.root.addNode(newNode);
        }
        this.count++;
    }

    public Object[] toArray() {
        if (this.root == null) {
            return null;
        }
        this.foot = 0;
        this.retData = new Object[this.count];
        this.root.toArrayNode();
        return this.retData;
    }
}

public class Demo {
    public static void main(String[] args) throws Exception {
        BinaryTree bt = new BinaryTree();
        bt.add(new Book("Java开发", 66.6));
        bt.add(new Book("JSP", 36.6));
        bt.add(new Book("C++", 86.6));
        bt.add(new Book("C", 16.6));
        Object obj[] = bt.toArray();
        System.out.println(Arrays.toString(obj));
    }
}

Comparator接口

  1. comparator接口的特征是在类定义时就默认实现,现在一个类已经开发完善了。
class Book {
    private String title;
    private double price;

    public Book() {
    }

    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }

    @Override
    public String toString() {
        return "书名:" + this.title + ",价格:" + this.price + "\n";
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

假设上述在初期设计时,有对象数组,但是没有设置对象数组排序的方法。之后要实现对象数组的排序,这时在不能修改Book类定义的情况下是不能实现Comparable接口的。因此Java为解决该问题,提供了另外一个比较器:java.util.Comparator,原先在Comparator下定义了两个方法:

@FunctionalInterface
public interface Comparator<T> {
    public int compare(T o1, T o2);

    public boolean equals(Object obj);
}

上述代码中,实际真正要实现只有compare()方法,需要定义一个类实现Comparator接口,这个类将作为指定类的排序类。
范例:定义排序的工具类

class BookComparator implements Comparator<Book> {
    @Override
    public int compare(Book o1, Book o2) {
        if (o1.getPrice() > o2.getPrice()) {
            return 1;
        } else if (o1.getPrice() < o2.getPrice()) {
            return -1;
        } else {
            return 0;
        }
    }
}

Comparable接口的使用依靠Arrays类的sort()方法,而Comparator接口可以利用另一个被重载的sort()方法:public static <T> void sort(T[] a,Comparator<?super T>c)
范例:进行排序

public class Demo {
    public static void main(String[] args) throws Exception {
        Book books[] = new Book[]{
                new Book("Java开发", 66.6),
                new Book("JSP", 36.6),
                new Book("C++", 86.6),
                new Book("C", 16.6)
        };
        Arrays.sort(books, new BookComparator());
        System.out.println(Arrays.toString(books));
    }
}

由该过程可得,使用Comparator比较麻烦,因为要定义一个专门的排序类,并且调用排序时也要明确地指明一个排序规则类。

题目:请解释Comparator和Comparable的区别?(请解释两种比较器的区别)
答案:
· 如果对象数组要进行排序那么必须设置排序规则,可以使用Comparator和Comparable接口实现;
· java.lang.Comparable是在一个类定义时实现的接口,这样该类数组就可以进行排序,在该接口下定义了一个public int compareTo()方法;
· java.util.Comparator是专门定义一个指定类的比较规则,用于进行挽救的比较操作,该接口下定义有两个方法public int compare()、public boolean equals()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值