赞
踩
目录
内部比较器——Comparable.compareTo(E o):
外部比较器——Comparator.compare(T o1, T o2):
优先级队列的底层是一个数组,但这个数组又比较特殊——二叉树通过层序遍历存放到该数组的数据。这样存放的方式就是堆这种数据结构。
大根堆:如果在堆中,每个根结点的值大于两个孩子结点的值。(对左右孩子无要求)
小根堆:如果在堆中,每个根结点的值小于两个孩子结点的值。(对左右孩子无要求)
在一个一维数组中:
1.对于每一个根结点都要调整为大小根堆。
2.调整时,先要找到较大的孩子
3.然后二者交换,继续向下调整该根结点下面的结点。
4.调整时可能会存在越界的情况,孩子结点可能会越界。
- public void createHeap() {
- //建大根堆
- //对每一个根节点使用向下调整算法
- //最后一个孩子 c = length - 1
- //c = 2 * p +1
- //p = (c - 1)/2
- for (int parent = (array.length - 1 -1) / 2; parent >= 0; parent--) {
- shiftDown(parent, usedSize);
- }
- }
- //向下调整
- private void shiftDown(int parent, int length) {
- int child = 2 * parent + 1;
- while (child < length) {
- //先判断孩子是否越界
- if (child < length - 1 && array[child] < array[child + 1]) {
- child++;
- }
- if (array[parent] < array[child]) {
- swap(array, parent, child);
- parent = child;
- child = 2 * parent + 1;
- } else {
- break;
- }
- }
- }
-
- private void swap(int[] array, int x, int y) {
- int tmp = array[x];
- array[x] = array[y];
- array[y] = tmp;
- }
在堆里添加完数据后,应该还要保证堆为大(小)根堆。
1.判断堆是否满了,满了扩容。
2.把添加的数据放到数组的最后面。
3.找到最后一个结点的父亲结点,向上调整。
4.(建大堆)如果父亲结点比孩子结点小,就调整,然后,父亲结点指向孩子结点,重新计算父亲结点,直到最后一个孩子调整完。
5.useSized++
优先级队列,是对于某些数据优先操作的结构,所以很自然的我们要优先对堆顶数据进行删除。
1.判断堆是否为空,为空抛出异常。
2.堆顶数据与最后一个结点进行交换。
3.对堆顶使用一次向下调整即可恢复成大(小)根堆。
4.useSized--
- public void pop() {
- if (isEmpty()) {
- return;
- }
- swap(array, 0, usedSize - 1);
- usedSize--;
- shiftDown(0, usedSize);
- }
有了以上概念,我们就能更容易理解PriorityQueue的源码部分的实现。
在生成大小根堆的时候,数据是通过比较大小来排序的。所以PriorityQueue底层必定有比较数据大小的东西。
所有的类都是继承Object类的,Object类中就有equals()方法。
重写equals()方法用到这里显然不合适,因为该方法只能比较二者是否想等,无法比较出大小关系。
Comparable是JDK提供的泛型接口类,源码如下:
- //Compareble是java.lang中的接口类,可以直接使用
- public interface Comparable<E> {
- // 返回值:
- // < 0: 表示 this 指向的对象小于形参 o 指向的对象
- // == 0: 表示 this 指向的对象等于形参 o 指向的对象
- // > 0: 表示 this 指向的对象大于形参 o 指向的对象
- int compareTo(E o);
- }
-
- //对象支持自己与自己比较
- //实现了该接口的类就可以自动进行排序
- //集合通过Collection.sort()排序,数组通过Arrays.sort()进行排序
该方法可以比较出数据的大小,所以我们可以在定义类的时候实现该接口,重写方法就可以比较。
- //Comparator是java.util 包中的泛型接口类,使用时必须导入对应的包
-
- public interface Comparator<T> {
- // 返回值:
- // < 0: 表示 o1 指向的对象小于 o2 指向的对象
- // == 0: 表示 o1 指向的对象等于 o2 指向的对象
- // > 0: 表示 o1 指向的对象等于 o2 指向的对象
- int compare(T o1, T o2);
- }
-
- //使用Comparator的情况:
- //1.没有实现Comparable接口
- //2.实现了Comparable接口,但是其中的compareTo方法不符合自己的预期
- public static void main(String[] args) {
- PriorityQueue<Integer> priorityQueue1= new PriorityQueue<>();
- priorityQueue1.offer(4);
- priorityQueue1.offer(6);
- priorityQueue1.offer(3);
- System.out.println(priorityQueue1);
- }
若是其他引用类型,就不可以这样offer()了,在offer()第二个数据的时候就会抛异常。
- class Student {
- public String name;
- public int age;
-
- public Student (int age) {
- this.age = age;
- }
- }
-
- public class Test {
- public static void main(String[] args) {
- PriorityQueue<Integer> priorityQueue1= new PriorityQueue<>();
- priorityQueue1.offer(4);
- priorityQueue1.offer(6);
- priorityQueue1.offer(3);
- System.out.println(priorityQueue1);
-
- PriorityQueue<Student> priorityQueue2 = new PriorityQueue<>();
- priorityQueue2.offer(new Student(20));
- priorityQueue2.offer(new Student(22));
- }
- }
第一种:什么都不传,那么默认空间大小为11,无比较器
第二种:只传空间大小,此时空间大小为所传的值
第三种:只传比较器,下面详解比较器作用
- class Student implements Comparable<Student> {
- public String name;
- public int age;
-
- public Student (int age) {
- this.age = age;
- }
-
- @Override
- public int compareTo(Student o) {
- return this.age - o.age;
- }
-
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
-
- public class Test {
- public static void main(String[] args) {
- PriorityQueue<Integer> priorityQueue1= new PriorityQueue<>();
- priorityQueue1.offer(4);
- priorityQueue1.offer(6);
- priorityQueue1.offer(3);
- System.out.println(priorityQueue1);
-
- PriorityQueue<Student> priorityQueue2 = new PriorityQueue<>();
- priorityQueue2.offer(new Student(20));
- priorityQueue2.offer(new Student(22));
- priorityQueue2.offer(new Student(23));
- System.out.println(priorityQueue2);
- }
- }
当实现了Comparable接口后,重写CompareTo方法后,此时就可以比较引用类型了。
此时它应该执行到一下源码部分。
- class Student {
- public String name;
- public int age;
-
- public Student (int age) {
- this.age = age;
- }
-
-
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
- class StuCompare implements Comparator<Student> {
- @Override
- public int compare(Student o1, Student o2) {
- return o2.age - o1.age;
- }
- }
-
- public class Test {
- public static void main(String[] args) {
- PriorityQueue<Integer> priorityQueue1= new PriorityQueue<>();
- priorityQueue1.offer(4);
- priorityQueue1.offer(6);
- priorityQueue1.offer(3);
- System.out.println(priorityQueue1);
-
- PriorityQueue<Student> priorityQueue2 = new PriorityQueue<>(new StuCompare());
- priorityQueue2.offer(new Student(20));
- priorityQueue2.offer(new Student(22));
- priorityQueue2.offer(new Student(23));
- System.out.println(priorityQueue2);
- }
- }
通过自定义的比较器,并且通过传入比较器的构造方法后,我们也可以比较。
此时它应该执行到下面的源码部分。
因为源码默认建小根堆,如果我们想建大根堆,有了以上源码分析,我们不难发现,关键就在比较器上,我们只需要改变比较规则,就可以建立大根堆。
比如Integer,我们无法到源码中改变比较规则,所以只能传比较器,这样会优先使用有比较器的方法。
- class IntCompare implements Comparator<Integer> {
- @Override
- public int compare (Integer o1, Integer o2) {
- return o2.compareTo(o1);
- }
- }
- public class Test {
- public static void main(String[] args) {
- PriorityQueue<Integer> priorityQueue1= new PriorityQueue<>(new IntCompare());
- priorityQueue1.offer(4);
- priorityQueue1.offer(6);
- priorityQueue1.offer(3);
- System.out.println(priorityQueue1);
- }
- }
若该引用类型实现了Comparable接口,我们直接修改compareTo
若没有,则修改比较器中的compare
- class Student implements Comparable<Student> {
- public String name;
- public int age;
-
- public Student (int age) {
- this.age = age;
- }
-
- @Override
- public int compareTo(Student o) {
- return o.age - this.age;
- }
-
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
-
-
-
- public class Test {
- public static void main(String[] args) {
- PriorityQueue<Student> priorityQueue2 = new PriorityQueue<>();
- priorityQueue2.offer(new Student(20));
- priorityQueue2.offer(new Student(22));
- priorityQueue2.offer(new Student(23));
- System.out.println(priorityQueue2);
- }
- }
- class Student {
- public String name;
- public int age;
-
- public Student (int age) {
- this.age = age;
- }
-
-
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
-
- class StuCompare implements Comparator<Student> {
- @Override
- public int compare(Student o1, Student o2) {
- return o2.age - o1.age;
- }
- }
-
- public class Test {
- public static void main(String[] args) {
- PriorityQueue<Student> priorityQueue2 = new PriorityQueue<>(new StuCompare());
- priorityQueue2.offer(new Student(20));
- priorityQueue2.offer(new Student(22));
- priorityQueue2.offer(new Student(23));
- System.out.println(priorityQueue2);
- }
- }
- class Student {
- public String name;
- public int age;
-
- public Student (int age) {
- this.age = age;
- }
-
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
-
- public class Test {
- public static void main(String[] args) {
- //这里直接new了一个比较器传过去了
- PriorityQueue<Student> priorityQueue2 = new PriorityQueue<>(new Comparator<Student>() {
- @Override
- public int compare(Student o1, Student o2) {
- return o1.age - o2.age;
- }
- });
- priorityQueue2.offer(new Student(20));
- priorityQueue2.offer(new Student(22));
- priorityQueue2.offer(new Student(23));
- System.out.println(priorityQueue2);
- }
-
- public static void main1(String[] args) {
- MyPriorityQueue heap = new MyPriorityQueue();
- int[] arr = {27, 15, 19, 18, 28, 34, 65, 49, 25, 37};
- heap.initArray(arr);
- heap.createHeap();
- heap.push(100);
- //heap.pop();
-
- PriorityQueue<Integer> priorityQueue1= new PriorityQueue<>();
- priorityQueue1.offer(4);
- priorityQueue1.offer(6);
- priorityQueue1.offer(3);
- System.out.println(priorityQueue1);
-
- }
- }
有什么错误评论区指出,希望可以帮到你。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。