前面我用堆写了一个优先队列,可以保证优先级高的先执行,但不能保证同等优先级的有序。java JDK的PriorityBlockingQueue也是用堆实现的优先队列。
场景:如果有1~9个会员等级进行排队购买,首先保证高等级的进行优先购买,同等级的有序排队。那么这个场景采用普通的优先队列就不能满足了。
理论方案:靠普通堆是实现不了的,除非你在构建堆的时候进行额外处理,强行保证它同等级的有序,那这个还不如写排序来的实在。还是以堆数据结构作为基础,实现优先功能,接下来就是要保证同等级别的有序了,这个功能交给链表实现。先将传过来的对象插入堆中,然后堆对象的关键字放入散列函数进行求值,获得在散列表里的位置,散列表装的就是链表了,然后把对象插入到链表最后,就将这个对象进行了一个排序。所以反过来获取第一个要购物的对象就是:堆的第一个位置始终是优先级最高的对象(此对象在优先级里可能不是第一个),然后对这个对象进行散列求值得到散列表的位置,获取散列表里链表的第一个元素就是真正实际第一个要购物的对象。
时间复杂度还是很快的:O(logn)+O(1)+O(1),不足就是对象花费了双倍空间。
java代码实现:
package com.tczs.heap;
public abstract class AbstractCompare<T> implements Comparable<T>{
protected int key;
public abstract int getKey();
public abstract void setKey(int key);
@Override
public int compareTo(T o){
if(o instanceof AbstractCompare){
AbstractCompare obj = (AbstractCompare) o;
if(key > obj.key)
return 1;
else if(key < obj.key)
return -1;
else
return 0;
}else
throw new IllegalArgumentException();
}
}
package com.tczs.heap;
import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class PriorityOrderlyBlockingQueue<T extends AbstractCompare<T>> {
private Object[] array; //二叉堆数组
private int capacity = 16;
private int hashTableLength = 20; //确保这个值比你的优先级种类数量大
private int length;
private int index;
private NodeValue[] nodeArray; //链表数组
private final ReentrantLock lock;
private final Condition notEmpty;
private static final int MAXIMUM_CAPACITY = Integer.MAX_VALUE;
public PriorityOrderlyBlockingQueue(int initialCapacity,int hashTableLength){
if(initialCapacity > 7)
this.capacity = initialCapacity;
if(hashTableLength > 7)
this.hashTableLength = hashTableLength;
nodeArray = new NodeValue[this.hashTableLength];
array = new Object[this.capacity];
lock = new ReentrantLock();
notEmpty = lock.newCondition();
}
public PriorityOrderlyBlockingQueue(int initialCapacity){
this(initialCapacity,0);
}
public PriorityOrderlyBlockingQueue(){
this(0,0);
}
public int size(){
return this.length;
}
/**
* 获取最小元素
* @return
*/
public T getMin(){
return get(1);
}
public T get(int index){
return array==null ? null:(T)array[index];
}
public void put(T element){
ReentrantLock lock = this.lock;
lock.lock();
try{
buildHeap(element);
hashInsertElement(element);
notEmpty.signal();
}finally {
lock.unlock();
}
}
/**
* 构建二叉堆(插入元素)
* @param element
*/
public void buildHeap(T element){
if(element == null)
throw new NullPointerException("element is null");
if(++index == capacity){
capacity = Math.min(MAXIMUM_CAPACITY,capacity<<1);
array = Arrays.copyOf(array,capacity);
}
array[index] = element;
fixedInsertArray(this.index);
length++;
}
private void fixedInsertArray(int index ){
while(index != 1){
T current = get(index);
if(current == null)
break;
T parent = get(index/2);
if (compare(current, parent) < 0) {
array[index / 2] = current;
array[index] = parent;
}else
break;
index = index/2;
}
}
private void hashInsertElement(T element){
int index = hash(element);
NodeValue nodeValue = nodeArray[index];
if(nodeValue == null){
Node<T> newNode = new Node<T>(element);
nodeValue = new NodeValue<>(newNode,newNode);
nodeArray[index] = nodeValue;
}else {
Node<T> newNode = new Node<T>(element);
Node lastNode = nodeValue.lastNode;
lastNode.next = newNode;
nodeValue.lastNode = newNode;
}
}
private int hash(T element){
return element.getKey() % hashTableLength;
}
public T peek(){
ReentrantLock lock = this.lock;
lock.lock();
try{
if(this.length == 0)
return null;
else {
T element = getMin();
int index = hash(element);
NodeValue nodeValue = nodeArray[index];
if(nodeValue == null)
throw new IllegalStateException("hash error");
else {
Node<T> node = nodeValue.firstNode;
return node.element;
}
}
}finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
ReentrantLock lock = this.lock;
lock.lock();
try{
while (this.length == 0)
notEmpty.await();
T element = deleteMin(); //删除二叉堆上的
int index = hash(element);
NodeValue<T> nodeValue = nodeArray[index];
if(nodeValue == null)
throw new IllegalStateException("hash error");
else {
Node<T> firstNode = nodeValue.firstNode;
T result = firstNode.element;
firstNode.element = null;
Node next = firstNode.next;
if(next == null)
nodeArray[index] = null;
else {
firstNode.next = null;
nodeValue.firstNode = next;
}
return result;
}
}finally {
lock.unlock();
}
}
/**
* 删除最小元素
* @return
*/
public T deleteMin(){
if(array == null)
return null;
T result = get(1);
if(length == 1)
array[1] = null;
else if(length == 2){
array[1] = array[2];
array[2] = null;
}else
deleteM();
index--;
length--;
return result;
}
private void deleteM(){
int index = 1;
int leftIndex = index<<1;
T left;
while((left=get(leftIndex)) != null){
T right = get(leftIndex+1);
if(right == null){
array[index] = left;
array[leftIndex] = null;
break;
}
if(compare(left,right) < 0){
array[index] = left;
array[leftIndex] = null;
}else {
array[index] = right;
leftIndex = leftIndex+1;
array[leftIndex] = null;
}
if(leftIndex<<1 >= capacity || get(leftIndex<<1) == null)
break;
index = leftIndex;
leftIndex = index<<1;
}
array[leftIndex] = array[this.index];
array[this.index] = null;
fixedInsertArray(leftIndex);
}
private int compare(T current,T parent){
return current.compareTo(parent);
}
class NodeValue<T>{
Node<T> firstNode;
Node<T> lastNode;
NodeValue(Node<T> firstNode,Node<T> lastNode){
this.firstNode = firstNode;
this.lastNode = lastNode;
}
}
class Node<T>{
T element;
Node<T> next;
Node(T element){
this.element = element;
}
}
}