实现带有优先级的queue,方式很多种,我们今天说的是根据数据结构和算法中第六版中提供的方式,positionList的方式,你可以理解这个positionLIist为一个LinkedList ,当然这本书中还讲解了根据完全二叉树的方式实现优先级队列,咱们先不讲,
首先带有优先级的队列要定义以下接口
Entry 接口定义了用来存储的键值对,键还有其它功能就是比较大小 /* * <p> * @author <714037465@qq.com> * @since 2018/8/2812:55 **/ public interface Entry<K, V> { K getKey(); V getValue(); }
PriorityQueue 用来定义带有优先级队列的方法,稍后我们回去实现这个方法,也可以看到insert,min,remove都返回了一个entry, insert:方法存储键值对(entry), min:方法返回最小的k,也就是优先级最高的key, remove:方法根据min方法找到优先级最高的entry,然后将entry从list中删除, /*** <p> * * @author <714037465@qq.com> * @since 2018/8/2812:53 **/ public interface PriorityQueue<K, V> { int size(); boolean isEmpty(); Entry<K, V> insert(K k, V v) throws IllegalArgumentException; Entry<K, V> min(); Entry<K, V> remove(K k, V v); }
DefaultComparator类实现了Comparator,对比的默认实现方式,用来在insert的时候,比较entry的k , /*** <p> * @author <714037465@qq.com> * @since 2018/8/2812:58 **/ public class DefaultComparator<E> implements Comparator<E> { @Override public int compare(E o1, E o2) { if (o1 == null) { System.out.println(o1); } return ((Comparable<E>) o1).compareTo(o2); } }
这样基础的这三个接口和类就定义完成,我们实现的这个优先级队列,是要基于这三个类实现的,下面这两个类则会将这些接口和类串联起来,实现这个带有优先级的功能,下面则是实现的方式
首先我们先定义一个抽象类,AbstractPriorityQueue,这个类中我们主要实现两个功能,1.1:对比,compare方法,通过构造方法的方式,初始化Comparator,可以是它,也可以是自定义的对比方式,然后再compare中使用初始化的Comparator进行对比,1.2就是定义PQentry,用来初始化键值对,以及获取k,和v的方法,当然了AbstractPriorityQueue 要实现PriorityQueue接口
/** * <p> * * @author <714037465@qq.com> * @since 2018/8/2813:03 **/ public abstract class AbstractPriorityQueue<K, V> implements PriorityQueue<K, V> { private Comparator comp; public AbstractPriorityQueue(Comparator<K> comparator) { comp = comparator; } public AbstractPriorityQueue() { this(new DefaultComparator<K>()); } protected int compare(Entry<K, V> a, Entry<K, V> b) { if(a.getKey()==null){ System.out.println("a.getKey=" + a.getKey() + "\t\t" + "b.getKey()==" + b.getKey()); } return comp.compare(a.getKey(), b.getKey()); } public boolean checkKey(K k) { return (comp.compare(k, k) == 0); } public boolean isEmpty() { return size() == 0; } public static class PQEntry<K, V> implements Entry<K, V> { private K k; private V v; public PQEntry(K k1, V v1) { this.k = k1; this.v = v1; } @Override public K getKey() { return k; } @Override public V getValue() { return v; } } }
这是最终的实现类,SortedPriorityQueue,通过继承刚刚实现的抽线类AbstractPriorityQueue,这样我们就可以顺理成章的使用抽象类中定义的PQentry 和对比的方法了,此外要说的是这里的insert方法稍微复杂些,起核心原理就是,当集合中的元素还是null的时候,将这个值加到这个队列的第一个位置,调用addFirst方法,当时新加入的entry中的k不等于null,并且小于集合中最左侧也就是最前方的k,compare(newest, walk.getElement()) < 0),交换位置,并且将交换完成的位置重新赋值给walker,当时新加入的entry中的k不等于null,并k大于集合最小的值,就把它放在这个最小值的后面
public class SortedPriorityQueue<K, V> extends AbstractPriorityQueue<K, V> { /*** primary collection of priority queue entries ***/ private PositionalList<Entry<K, V>> list = new LinkedPositionalList<>(); /***∗ Creates an empty priority queue based on the natural ordering of its keys. ***/ public SortedPriorityQueue() { super(); } /***Creates an empty priority queue using the given comparator to order keys. ***/ public SortedPriorityQueue(Comparator<K> comp) { super(comp); } /***Inserts a key-value pair and returns the entry created. ***/ public Entry<K, V> insert(K key, V value) throws IllegalArgumentException { checkKey(key); // auxiliary key-checking method (could throw exception) Entry<K, V> newest = new PQEntry<>(key, value); Position<Entry<K, V>> walk = list.last(); // walk backward, looking for smaller key while (walk != null && compare(newest, walk.getElement()) < 0) walk = list.before(walk); if (walk == null) list.addFirst(newest); // new key is smallest else list.addAfter(walk, newest); // newest goes after walk return newest; } /***Returns (but does not remove) an entry with minimal key. ***/ @Override public Entry<K, V> min() { if (list.isEmpty()) return null; return list.first().getElement(); } /*** Removes and returns an entry with minimal key. ***/ @Override public Entry<K, V> remove(K k, V v) { if (list.isEmpty()) return null; return list.remove(list.first()); } /*** Returns the number of items in the priority queue. ***/ public int size() { return list.size(); } public static void main(String[] args) { SortedPriorityQueue sortedPriorityQueue = new SortedPriorityQueue(); sortedPriorityQueue.insert(1, "www"); sortedPriorityQueue.insert(2, "www"); sortedPriorityQueue.insert(3, "www"); sortedPriorityQueue.insert(4, "www"); sortedPriorityQueue.insert(-1, "www"); System.out.println("last min key is " + sortedPriorityQueue.min().getKey()); }