PriorityQueue source code and characteristic analysis of data structure (size root heap conversion, expansion)

Article directory

  • 1. Features of PriorityQueue
  • 2. Introduction to common interfaces of PriorityQueue
    • 1. The construction of the priority queue
    • 2. Insert / delete / get the element with the highest priority
  • Three, PriorityQueue source code analysis
  •        1. Small and heap source code analysis
  •        2. PriorityQueue is a small heap by default. How can it become a large heap?
  •        3. How does the Integer data type become a large heap? (self-implementing comparator)
  •        4. Source code analysis of PriorityQueue expansion
  • 4. Summary
  • Five, the comparison method of PriorityQueue in the collection framework

1. Features of PriorityQueue

The Java collection framework provides two types of priority queues, PriorityQueue and PriorityBlockingQueue. PriorityQueue is thread-unsafe, and PriorityBlockingQueue is thread-safe.

 Note on the use of PriorityQueue:

1. When using, you must import the package where PriorityQueue is located, namely:

import java.util.PriorityQueue;

2. The elements placed in the PriorityQueue must be able to compare the size, and cannot insert objects that cannot be compared, otherwise a
ClassCastException will be thrown

    public static void main(String[] args) {
        PriorityQueue<Student> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(new Student(10));

    }
//这个时候虽然是不能比较的,但是此时运行也没有报错,那是因为此时只有一个对象,是不需要进行比较的
    public static void main(String[] args) {
        PriorityQueue<Student> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(new Student(10));
        priorityQueue.offer(new Student(5));

    }
//但是此时运行就会报错了,因为此时这两个对象是无法进行比较的

At this point, there are two solutions, one is to give the comparator, the other is to implement the Comparable interface and override the compareTo method.

 At this point we choose to implement the Comparable interface and override the compareTo method:

class Student implements Comparable<Student>{
    public int age;
    public Student(int age){
        this.age = age;
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}

3. Null objects cannot be inserted, otherwise NullPointerException will be thrown
4. There is no capacity limit, any number of elements can be inserted, and its internal capacity can be automatically expanded
5. The time complexity of inserting and deleting elements is O(log2N) (log takes 2 as the N at the bottom)
6. The bottom layer of PriorityQueue uses a heap data structure
7. PriorityQueue is a small heap by default - that is, the elements obtained each time are the smallest elements 

2. Introduction to common interfaces of PriorityQueue

1. The construction of the priority queue

Constructor Features
PriorityQueue() Creates an empty priority queue with a default capacity of 11
PriorityQueue(int
initialCapacity)
Create a priority queue with initialCapacity, note: initialCapacity cannot be less than 1, otherwise an
IllegalArgumentException will be thrown
PriorityQueue(Collection<?
extends E> c)
Use a collection to create a priority queue

2. Insert / delete / get the element with the highest priority

Function name Features
boolean
offer(E e)
Insert element e, and return true if the insertion is successful. If the e object is empty, a NullPointerException will be thrown. The time complexity is O(log2N) (log is N with the base of 2). Note: when the space is not enough, the capacity will be expanded
E peek() Get the element with the highest priority, or return null if the priority queue is empty
E poll() Remove the element with the highest priority and return, or null if the priority queue is empty
int size() Get the number of valid elements
void
clear()
empty
boolean
isEmpty()
Check if the priority queue is empty, return true if empty

Three, PriorityQueue source code analysis

1. Do source code analysis for the following three lines (small root heap):

        PriorityQueue<Student> priorityQueue = new PriorityQueue<>();
        priorityQueue.offer(new Student(10));
        priorityQueue.offer(new Student(5));

     

PriorityQueue<Student> priorityQueue = new PriorityQueue<>();

The source code analysis of this line of code is as follows:

priorityQueue.offer(new Student(10));

Next, let's look at the source code of the first offer:

 

 priorityQueue.offer(new Student(5));

Next, let's look at the source code of the second offer:

 

 2. PriorityQueue is a small root heap by default. How can it become a large root heap?

By modifying the comparison rules, it can become a large root heap.

There are two ways:

First, through our source code analysis above, we can modify the comparison rules, which can be modified to < ; but we cannot modify the source code, so I will directly look at the second method.

 The second is: modify the comparison rules in the rewritten comparaTo method:

  public int compareTo(Student o) {
        return this.age - o.age;
    }

  3. How does the Integer data type become a large heap? (self-implementing comparator)

The first step is to implement the comparator by yourself:

class IntComparator implements Comparator<Integer>{

    @Override
    public int compare(Integer o1, Integer o2) {
        //return o2 - o1;
        return o2.compareTo(o1);
    }
}

The second step is to pass in the comparator when passing parameters: 

 PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new IntComparator());


At this point, when we run the program again, it is already a big heap. 

Let's analyze the source code:

   4. Source code analysis of PriorityQueue expansion

    private void grow(int minCapacity) {
        int oldCapacity = queue.length;
        // Double size if small; else grow by 50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                         (oldCapacity + 2) :
                                         (oldCapacity >> 1));
        // overflow-conscious code
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        queue = Arrays.copyOf(queue, newCapacity);
    }

If the capacity is less than 64, it is expanded according to 2 times of oldCapacity.
If the capacity is greater than or equal to 64, it is expanded according to 1.5 times of oldCapacity.
If the capacity exceeds MAX_ARRAY_SIZE ( 2147483639 ), expand according to MAX_ARRAY_SIZE

4 Summary

1. When the array capacity is not passed in, the default is 11

2. When no comparator is passed in, the passed in objects must be comparable, otherwise an error will be reported

3. The priority is to use the comparator to compare        

Comparison of PriorityQueue in Collection Framework

The bottom layer of PriorityQueue in the collection framework uses a heap structure, so its internal elements must be able to compare the size, PriorityQueue adopts: Comparble and Comparator .
1. Comparble is the default internal comparison method. If the user inserts a custom type object, the object of this class must implement the Comparble interface and override the compareTo method.
2. The user can also choose to use the comparator object. If the user inserts a custom type object, he must provide a comparator class, which implements the Comparator interface and overrides the compare method.
There are three comparison methods for comparison:
Overridden method explain
Object.equals
Because all classes inherit from Object , they can be overridden directly, but they can only be compared for equality and
no
Comparable.compareTo
The interface needs to be implemented manually, which is more intrusive, but once implemented, there is an order for each use of the class, which belongs to the internal order
Comparator.compare
A comparator object needs to be implemented, which is less invasive to compare classes, but more invasive to algorithm code implementation

Guess you like

Origin blog.csdn.net/crazy_xieyi/article/details/127278362