定义
priorityQueue是Java中的一种无界优先队列,具体实现是二叉小顶堆,是一颗完全二叉树,实现了Queue接口,不允许null元素插入,初始时是一个Object[],随着元素的插入可自动扩容,入队后元素按自然顺序从小到大排列,也可以重构comparator方法来排列
优先队列
保证每次取出的元素都是队列中权值最小那个
小顶堆
任意一个非叶子结点的权值,都不大于其左右子结点的权值
具体实现
priorityQueue具体实现是数组,实现小顶堆后,其父结点和子结点满足以下关系
leftNode = ParentNode * 2 + 1 rightNode = ParentNode * 2 + 2 parentNode = (currentNode - 1) / 2
方法与时间复杂度
方法 时间复杂度 peek() O(1) element() O(1) add() O(log(N)) offer() O(log(N) remove() O(log(N)) poll() O(log(N))
方法的区别
add(E e)和offer(E e):都是向队列中插入元素,不同之处是插入失败时前者抛出异常,后者返回false
public boolean offer ( E e) {
if ( e == null)
throw new NullPointerException ( ) ;
modCount++ ;
int i = size;
if ( i >= queue. length)
grow ( i + 1 ) ;
size = i + 1 ;
if ( i == 0 )
queue[ 0 ] = e;
else
siftUp ( i, e) ;
return true ;
}
private void siftUp ( 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;
}
element()和peek():都是获取但不删除队首元素,区别是获取失败时前者抛出异常,后者返回null;根据堆的性质,堆顶是整个堆中权值最小的元素,按照数组的小标就是第0个元素,所以可以直接返回下标为0的元素即可
public E peek ( ) {
if ( size == 0 )
return null;
return ( E) queue[ 0 ] ;
}
remove()和poll():都是获取并删除队首元素,区别是获取失败时前者抛出异常,后者返回null
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;
if ( s != 0 )
siftDown ( 0 , x) ;
return result;
}
private void siftDown ( 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;
}
remove(Object o):用于删除队列中和o相等的元素,删除会出现两种情况:①删除的是最后一个元素,直接删除,不需要调整堆结构;②删除的是不是最后一个元素,则从删除的那个元素开始,以最后一个元素为参照物调用一次siftDown()来调整堆结构
public boolean remove ( Object o) {
int i = indexOf ( o) ;
if ( i == - 1 )
return false ;
int s = -- size;
if ( s == i)
queue[ i] = null;
else {
E moved = ( E) queue[ s] ;
queue[ s] = null;
siftDown ( i, moved) ;
. . . . . .
}
return true ;
}
实例
这里我写了一个给无序的标签按其权值大小排序的封装
HotTagCache类:
public class HotTagCache {
private List< String> hots = new ArrayList < > ( ) ;
public void sortTags ( Map< String, Integer> tags) {
int max = 10 ;
PriorityQueue< HotTagDTO> priorityQueue = new PriorityQueue < > ( max) ;
tags. forEach ( ( name, priority) - > {
HotTagDTO hotTagDTO = new HotTagDTO ( ) ;
hotTagDTO. setName ( name) ;
hotTagDTO. setPriority ( priority) ;
if ( priorityQueue. size ( ) < max) {
priorityQueue. add ( hotTagDTO) ;
} else {
HotTagDTO minHot = priorityQueue. peek ( ) ;
if ( hotTagDTO. compareTo ( minHot) > 0 ) {
priorityQueue. poll ( ) ;
priorityQueue. add ( hotTagDTO) ;
}
}
} ) ;
List< String> sortedTags = new ArrayList < > ( ) ;
HotTagDTO poll = priorityQueue. poll ( ) ;
while ( poll != null) {
sortedTags. add ( 0 , poll. getName ( ) ) ;
poll = priorityQueue. poll ( ) ;
}
hots = sortedTags;
}
}
HotTagDTO类,实现Comparable接口,重载compareTo()构造排序规则:
public class HotTagDTO implements Comparable {
private String name;
private Integer priority;
@Override
public int compareTo ( Object o) {
return this . getPriority ( ) - ( ( HotTagDTO) o) . getPriority ( ) ;
}
}
参考