版权声明:中华人民共和国持有版权 https://blog.csdn.net/Fly_Fly_Zhang/article/details/88258269
特点:
- PriorityQueue队列里元素不能为null;
- 存储元素是可以重复的;
- PriorityQueue存储自定义类时,自定义类需要实现Comparable接口,否则会抛出异常;或者在构建PriorityQueue时,实现Comparator;
Comparator和Comparable的区别:
- 方法不同:
- Comparator需要实现的是compare()方法;
- Comparable需要实现compareTo() 方法;
- 使用场景不同:
- Comparator在需要比较的类比较底层时或者类已经实现的Comparable接口不适合此次比较;临时自定义比较器;
- Comparable比较适合类中单一比较方法的;
底层数据结构:数组
基本属性:
private static final int DEFAULT_INITIAL_CAPACITY = 11; //初始容量大小为11
private transient Object[] queue; //存储数据数组
private int size = 0;//数组中元素个数
private final Comparator<? super E> comparator; //比较器
private transient int modCount = 0;//版本号
构造函数:
public PriorityQueue() {
//无参构造,创建默认大小数组,未传入比较器
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityQueue(int initialCapacity) {
//指定数组大小,未传入比较器
this(initialCapacity, null);
}
//指定数组大小,传入比较器
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
if (initialCapacity < 1) //传入数组代销小于1,抛出异常
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
@SuppressWarnings("unchecked")
public PriorityQueue(Collection<? extends E> c) {
//传入一个collection接口下的集合
if (c instanceof SortedSet<?>) {
//如果这个集合实现了sortedSet接口,就可以被添加进来,指SortedSet集合
SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
this.comparator = (Comparator<? super E>) ss.comparator(); //得到原集合的比较器;
initElementsFromCollection(ss);
}
else if (c instanceof PriorityQueue<?>) { //如果传入的集合正好时PriorityQueue集合
PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
this.comparator = (Comparator<? super E>) pq.comparator(); //得到比较器
initFromPriorityQueue(pq);
}
else { //如果都不是,那么默认未传入比较器
this.comparator = null;
initFromCollection(c);
}
}
@SuppressWarnings("unchecked")
public PriorityQueue(PriorityQueue<? extends E> c) {
//传入集合正好时PriorityQueue
this.comparator = (Comparator<? super E>) c.comparator();
initFromPriorityQueue(c);
}
@SuppressWarnings("unchecked")
public PriorityQueue(SortedSet<? extends E> c) { //指TreeSet
//传入集合正好实现了SortedSet接口
this.comparator = (Comparator<? super E>) c.comparator();
initElementsFromCollection(c);
}
CRUD研究(增删改查):HashMap的hash()是对key值的hash:
- 添加元素:
- add () : 添加元素,底层调用offer();
- offer() :添加元素,插入元素为null时抛出异常;
public boolean add(E e) {
return offer(e);
}
public boolean offer(E e) {
if (e == null) //不能存储null值
throw new NullPointerException();
modCount++;//版本发生变化
int i = size;//将插入角标
if (i >= queue.length) //进行扩容
grow(i + 1);
size = i + 1;//数组中元素个数
if (i == 0)//数组为空,直接插入0号角标
queue[0] = e;
else
siftUp(i, e);
return true;
}
//数组扩容
private void grow(int minCapacity) {
int oldCapacity = queue.length;
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) : //二倍加二
(oldCapacity >> 1)); //1.5倍扩容
if (newCapacity - MAX_ARRAY_SIZE > 0)//新数组长度超出额定值
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity); //创建扩容后的数组;
}
//判断新数组长度是否大于默认最大值,如果大于则数组长度为默认最大值
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
//找到新添加元素在数组中位置;
private void siftUp(int k, E x) {
if (comparator != null) //有自定义比较器
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);//采用默认比较器
}
private void siftUpComparable(int k, E x) { //默认比较器
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) { //k为数组有元素的最大角标
int parent = (k - 1) >>> 1; //父节点
Object e = queue[parent];
if (key.compareTo((E) e) >= 0) //调用默认比较
//要插入元素大于父节点,满足小根堆,插入k角标
break;
//要插入元素小于父节点,将父节点元素方法要插入子节点位置
queue[k] = e;
k = parent; //新的待插入角标为父节点
}
queue[k] = key;
}
private void siftUpUsingComparator(int k, E x) { //自定义比较器
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)//调用自定义比较器
break;
//要插入元素小于父节点,将父节点元素方法要插入子节点位置
queue[k] = e;
k = parent; //新的待插入角标为父节点
}
queue[k] = x;
}
- 获取元素:队列只能获取队头元素:
- peek():获取第一个元素,仅获取,并没有删除;队列为空返回null;
- element() : 获取第一个元素,队列为空时抛出异常,继承自父类;
public E peek() {
if (size == 0) //队列中没有元素,返回null
return null;
return (E) queue[0];
}
//继承自AbstractQueue的类方法
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
- 删除元素:
- remove(): 删除队顶元素,底层调用的是poll;队列为空则抛出异常;==>父类提供方法;
- poll() : 删除队顶元素,队列为空返回null;
//父类提供方法
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
//实现父类Queue接口的方法;
public E poll() {
if (size == 0)//队列中无元素
return null;
int s = --size;//最后元素角标
modCount++;
E result = (E) queue[0]; //要返回的删除元素
E x = (E) queue[s];//得到最后一个角标的元素
queue[s] = null; //将最后一个角标元素置为null
if (s != 0) //队列中有元素
siftDown(0, x); //重新调整小根堆
return result;
}
private void siftDown(int k, E x) {
if (comparator != null) //有没有给自定义比较器
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
//默认比较器调整小根堆
private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>)x;
//
int half = size >>> 1; //得到中值坐标
//因为x是最后有元素的角标,所以 half坐标正好是它的父节点,
//父节点肯定是小于子节点的,我们一直是用x值进行比较的,如果到最后一次循环,
//实际上是没有必要在去进行比较
while (k < half) { //当前坐标小于中值坐标
int child = (k << 1) + 1; //左孩子 2n+1
Object c = queue[child];
int right = child + 1; //右孩子,2n+2
//比较两个孩子,得到其中最小的一个孩子
if (right < size &&
((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
if (key.compareTo((E) c) <= 0) //判断最小的孩子与父节点的大小,如果父小于子,满足小根堆
break;
//父大于子,调整两者位置;
queue[k] = c;
k = child;
}
queue[k] = key;
}
//自定义比较器调整根堆
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}