集合框架源码分析六之堆结构的实现(PriorityQueue)

来源:互联网 发布:京东商城javaweb源码 编辑:程序博客网 时间:2024/05/21 19:23
有关堆的描述请见我另外一篇博客
http://zhouyunan2010.iteye.com/blog/1217462


Java代码  收藏代码
  1. /** 
  2. * 
  3. * 优先队列是用了一种叫做堆的高效的数据结构, 
  4. * 堆是用二叉树来描述的,对任意元素n,索引从0开始,如果有子节点的话,则左子树为 
  5. * 2*n+1,右子树为2*(n+1)。 
  6. * 以堆实现的队列如果不为空的话,queue[0]即为最小值。 
  7.  
  8. * PS:此优先队列中的元素并不是升序排列的,只能说是"基本有序" 
  9. * 但是queue[0]为树根而且必定是最小元素 
  10. */  
  11. class PriorityQueue<E> extends AbstractQueue<E>  
  12. implements java.io.Serializable {  
  13.   
  14. private static final long serialVersionUID = -7720805057305804111L;  
  15.   
  16. /** 
  17.  * 队列初始容量大小 
  18.  */  
  19. private static final int DEFAULT_INITIAL_CAPACITY = 11;  
  20.   
  21. /** 
  22.  * 用来存储元素的数组 
  23.  */  
  24. public transient Object[] queue;  
  25.   
  26. /** 
  27.  * 队列中元素个数 
  28.  */  
  29. private int size = 0;  
  30.   
  31. /** 
  32.  *  
  33.  * 比较器,如果为空,则使用元素的自然顺序进行排序, 
  34.  * 反正任意两元素必须是可比的 
  35.  */  
  36. private final Comparator<? super E> comparator;  
  37.   
  38. /** 
  39.  *  
  40.  * 队列发生机构性的改变,比如进行添加,移除等操作,此变量都会加1, 
  41.  * modCount主要使用来检测是否对队列进行了并发操作 
  42.  */  
  43. private transient int modCount = 0;  
  44.   
  45. /** 
  46.  * 创建一个初始容量为11的空队列 
  47.  */  
  48. public PriorityQueue() {  
  49.     this(DEFAULT_INITIAL_CAPACITY, null);  
  50. }  
  51.   
  52. /** 
  53.  * 指定队列的初始容量,如果initialCapacity<1将抛出 
  54.  * IllegalArgumentException异常 
  55.  */  
  56. public PriorityQueue(int initialCapacity) {  
  57.     this(initialCapacity, null);  
  58. }  
  59.   
  60. /** 
  61.  *  
  62.  * 以指定初始容量与具体比较器对象的方式创建一个队列 
  63.  * 比较器是用来排序的,大家都懂的。 
  64.  */  
  65. public PriorityQueue(int initialCapacity,  
  66.                      Comparator<? super E> comparator) {  
  67.     if (initialCapacity < 1)  
  68.         throw new IllegalArgumentException();  
  69.     this.queue = new Object[initialCapacity];   //数组初始化  
  70.     this.comparator = comparator;       //比较器初始化  
  71. }  
  72.   
  73. /** 
  74.  *  
  75.  * 创建一个包含指定集合c的所有元素的优先队列, 
  76.  * 如果c是一个SortedSet或另一个优先队列,本队列中的元素 
  77.  * 顺序与前者相同,否则按其他比较顺序重新排列 
  78.  */  
  79. public PriorityQueue(Collection<? extends E> c) {  
  80.     initFromCollection(c);  
  81.     if (c instanceof SortedSet)     //如果是SortedSet,则获取它的比较器  
  82.         comparator = (Comparator<? super E>)  
  83.             ((SortedSet<? extends E>)c).comparator();  
  84.     else if (c instanceof PriorityQueue)        //如果是PriorityQueue,则获取它的比较器  
  85.         comparator = (Comparator<? super E>)    
  86.             ((PriorityQueue<? extends E>)c).comparator();  
  87.     else {  
  88.         comparator = null;  
  89.         //从一个无序序列构建一个堆  
  90.         heapify();  
  91.     }  
  92. }  
  93.   
  94. /** 
  95.  * 以指定PriorityQueue中的元素,及其Comparator比较器 
  96.  * 创建一个新的优先队列 
  97.  */  
  98. public PriorityQueue(PriorityQueue<? extends E> c) {  
  99.     comparator = (Comparator<? super E>)c.comparator();  
  100.     initFromCollection(c);  
  101. }  
  102.   
  103. /** 
  104.  * 以指定SortedSet中的元素,及其Comparator比较器 
  105.  * 创建一个新的优先队列 
  106.  */  
  107. public PriorityQueue(SortedSet<? extends E> c) {  
  108.     comparator = (Comparator<? super E>)c.comparator();  
  109.     initFromCollection(c);  
  110. }  
  111.   
  112. /** 
  113.  *  
  114.  * 以指定集合中的元素对数组进行初始化 
  115.  */  
  116. private void initFromCollection(Collection<? extends E> c) {  
  117.     Object[] a = c.toArray();  
  118.     //如果c.toArray()不能正确的返回一个数组对象,就复制它为一个数组对象  
  119.     if (a.getClass() != Object[].class)       
  120.         a = Arrays.copyOf(a, a.length, Object[].class);  
  121.     queue = a;      //初始化数组  
  122.     size = a.length;    //初始化size  
  123. }  
  124.   
  125. /** 
  126.  *  
  127.  * 动态数组容量扩充的方法 
  128.  * @param minCapacity 最小容量 
  129.  */  
  130. private void grow(int minCapacity) {  
  131.     if (minCapacity < 0// overflow  
  132.         throw new OutOfMemoryError();  
  133.     int oldCapacity = queue.length;     //原始容量大小  
  134.     //如果原始容量小于64则扩充为原来的2倍,否则扩充为原来的1.5倍  
  135.     int newCapacity = ((oldCapacity < 64)?  
  136.                        ((oldCapacity + 1) * 2):  
  137.                        ((oldCapacity / 2) * 3));  
  138.     if (newCapacity < 0// overflow  
  139.         newCapacity = Integer.MAX_VALUE;  
  140.     if (newCapacity < minCapacity)     
  141.         newCapacity = minCapacity;  
  142.     queue = Arrays.copyOf(queue, newCapacity);  //这个方法真好用  
  143. }  
  144.   
  145. /** 
  146.  *  
  147.  * 向优先队列中插入一个元素 
  148.  * e为null则则抛出NullPointerException 
  149.  * e为不相符的类型则抛出ClassCastException 
  150.  * 具体实现见offer方法 
  151.  */  
  152. public boolean add(E e) {  
  153.     return offer(e);  
  154. }  
  155.   
  156.   
  157. public boolean offer(E e) {  
  158.     if (e == null)  
  159.         throw new NullPointerException();  
  160.     modCount++;     //添加了元素,modCount++  
  161.     int i = size;  
  162.     if (i >= queue.length)   //如果已经添加的元素个数已经超出了数组的容量则进行容量扩充  
  163.         grow(i + 1);  
  164.     size = i + 1;  
  165.     if (i == 0)     //如果添加之前是空队列  
  166.         queue[0] = e;  
  167.     else          
  168.         siftUp(i, e);  
  169.     return true;  
  170. }  
  171.   
  172. /** 
  173.  * 取出最小元素,即根元素,即第1个元素 
  174.  */  
  175. public E peek() {  
  176.     if (size == 0)  
  177.         return null;  
  178.     return (E) queue[0];  
  179. }  
  180.   
  181. /** 
  182.  * 由于内部是用数组存储数据,只需要遍历数组即可 
  183.  */  
  184. private int indexOf(Object o) {  
  185.     if (o != null) {  
  186.         for (int i = 0; i < size; i++)  
  187.             if (o.equals(queue[i]))  
  188.                 return i;  
  189.     }  
  190.     return -1;  
  191. }  
  192.   
  193. /** 
  194.  *  
  195.  * 从队列中移除指定元素,如果有多个,移除第一个 
  196.  * 方法:首先根据indexOf查找此元素的索引,然后根据索引移除元素 
  197.  */  
  198. public boolean remove(Object o) {  
  199.     int i = indexOf(o);       
  200.     if (i == -1)  
  201.         return false;  
  202.     else {  
  203.         removeAt(i);  
  204.         return true;  
  205.     }  
  206. }  
  207.   
  208. /** 
  209.  * 如果队列中存在o则移除它 
  210.  */  
  211. boolean removeEq(Object o) {  
  212. for (int i = 0; i < size; i++) {  
  213.     if (o == queue[i]) {  
  214.             removeAt(i);  
  215.             return true;  
  216.         }  
  217.     }  
  218.     return false;  
  219. }  
  220.   
  221. /** 
  222.  * 查看队列中是否包含o 
  223.  */  
  224. public boolean contains(Object o) {  
  225.     return indexOf(o) != -1;  
  226. }  
  227.   
  228. /** 
  229.  * toArray 
  230.  */  
  231. public Object[] toArray() {  
  232.     return Arrays.copyOf(queue, size);  
  233. }  
  234.   
  235. /** 
  236.  *  老方法了,不多说 
  237.  */  
  238. public <T> T[] toArray(T[] a) {  
  239.     if (a.length < size)  
  240.         // Make a new array of a's runtime type, but my contents:  
  241.         return (T[]) Arrays.copyOf(queue, size, a.getClass());  
  242.     System.arraycopy(queue, 0, a, 0, size);  
  243.     if (a.length > size)  
  244.         a[size] = null;  
  245.     return a;  
  246. }  
  247.   
  248. /** 
  249.  * 返回此队列的一个迭代器 
  250.  */  
  251. public Iterator<E> iterator() {  
  252.     return new Itr();  
  253. }  
  254.   
  255. private final class Itr implements Iterator<E> {  
  256.     /** 
  257.      * 数组中的索引 
  258.      */  
  259.     private int cursor = 0;  
  260.   
  261.     /** 
  262.      *  
  263.      * 最近一次调用next方法返回的元素的索引 
  264.      * 如果此索引的元素被移除了,重置lastRet为-1 
  265.      */  
  266.     private int lastRet = -1;  
  267.   
  268.     /** 
  269.      *  
  270.      * 保存移除元素时所遇到的特殊情况, 
  271.      * 一般调用removeAt(int)方法返回的是null,如果值返回不为空则遇到特殊情况 
  272.      * 要将返回的值保存在forgetMeNot队列中,cursor大于size时从forgetMeNot中取 
  273.      * 见removeAt方法 
  274.      */  
  275.     public ArrayDeque<E> forgetMeNot = null;  
  276.   
  277.     /** 
  278.      * 最后最近一次调用next方法返回的元素 
  279.      */  
  280.     private E lastRetElt = null;  
  281.   
  282.     /** 
  283.      * 检测是否有并发操作 
  284.      */  
  285.     private int expectedModCount = modCount;  
  286.   
  287.     public boolean hasNext() {  
  288.         return cursor < size ||  
  289.             (forgetMeNot != null && !forgetMeNot.isEmpty());  
  290.     }  
  291.   
  292.     public E next() {  
  293.         if (expectedModCount != modCount)  
  294.             throw new ConcurrentModificationException();  
  295.         if (cursor < size)  
  296.             return (E) queue[lastRet = cursor++];  
  297.         if (forgetMeNot != null) {  
  298.             lastRet = -1;  
  299.             lastRetElt = forgetMeNot.poll();  
  300.             if (lastRetElt != null)  
  301.                 return lastRetElt;  
  302.         }  
  303.         throw new NoSuchElementException();  
  304.     }  
  305.   
  306.     public void remove() {  
  307.         if (expectedModCount != modCount)  
  308.             throw new ConcurrentModificationException();  
  309.         if (lastRet != -1) {  
  310.             E moved = PriorityQueue.this.removeAt(lastRet);  
  311.             lastRet = -1;  
  312.             if (moved == null)  
  313.                 cursor--;  
  314.             else {  
  315.                 if (forgetMeNot == null)  
  316.                     forgetMeNot = new ArrayDeque<E>();  
  317.                 forgetMeNot.add(moved);  
  318.             }  
  319.         } else if (lastRetElt != null) {  
  320.             PriorityQueue.this.removeEq(lastRetElt);  
  321.             lastRetElt = null;  
  322.         } else {  
  323.             throw new IllegalStateException();  
  324.     }  
  325.         expectedModCount = modCount;  
  326.     }  
  327. }  
  328.   
  329. public int size() {  
  330.     return size;  
  331. }  
  332.   
  333. /** 
  334.  * 移除队列中所有元素 
  335.  * 移除后队列为空 
  336.  */  
  337. public void clear() {  
  338.     modCount++;  
  339.     for (int i = 0; i < size; i++)  
  340.         queue[i] = null;  
  341.     size = 0;  
  342. }  
  343.   
  344. /** 
  345.  * 移除第一个元素(最小的元素) 
  346.  * 并重新调整堆结构 
  347.  */  
  348.   
  349. public E poll() {  
  350.     if (size == 0)  
  351.         return null;  
  352.     int s = --size;  
  353.     modCount++;  
  354.     E result = (E) queue[0];  
  355.     E x = (E) queue[s];  
  356.     queue[s] = null;  
  357.     if (s != 0)  
  358.         siftDown(0, x);  
  359.     return result;  
  360. }  
  361.   
  362. /** 
  363.  *  
  364.  * 移除队列中的第i个元素 
  365.  * 移除元素时要重新调整堆, 
  366.  * 移除成功返回值也可能为null 
  367.  */  
  368. public E removeAt(int i) {  
  369.     assert i >= 0 && i < size;  
  370.     modCount++;     //移除元素,队列结构改变modCount++  
  371.     int s = --size;  
  372.     if (s == i) // 如果是最后一个元素,直接移除  
  373.         queue[i] = null;  
  374.     else {  
  375.         E moved = (E) queue[s]; //这是最后一个元素  
  376.         queue[s] = null;        //首先将其设为null  
  377.         /*用i的较小子节点替换i,即把i移出去, 
  378.                         其子孙节点依次上升,最后一个子孙叶子节点以moved替换*/  
  379.         siftDown(i, moved);       
  380.           
  381.         /*前面一步已经调整好了堆结构,这一步可能是为了处理特殊情况(我没遇到过这种特殊情况) 
  382.           queue[i] == moved,queue[i]是已经调整过的值*/  
  383.         if (queue[i] == moved) {  
  384.             siftUp(i, moved);  
  385.             if (queue[i] != moved)  
  386.                 return moved;  
  387.         }  
  388.     }  
  389.     return null;  
  390. }  
  391.   
  392. /** 
  393.  * 添加元素后,重新调整堆的过程,这里从下向上调整x的位置。 
  394.  * 这比初始构建堆更简单 
  395.  */  
  396. private void siftUp(int k, E x) {  
  397.     if (comparator != null)  
  398.         siftUpUsingComparator(k, x);  
  399.     else  
  400.         siftUpComparable(k, x);  
  401. }  
  402.   
  403. private void siftUpComparable(int k, E x) {  
  404.     Comparable<? super E> key = (Comparable<? super E>) x;  
  405.     while (k > 0) {      //<=0就不用调整了  
  406.         int parent = (k - 1) >>> 1;        //x的父节点  
  407.         Object e = queue[parent];  
  408.         if (key.compareTo((E) e) >= 0)   //如果x小于parent则终止调整  
  409.             break;  
  410.         queue[k] = e;   //否则父节点向下移,x为父节点  
  411.         k = parent;     //从x处继续调整  
  412.     }  
  413.     queue[k] = key;  
  414. }  
  415.   
  416. /** 
  417.  * 同上 
  418.  */  
  419. private void siftUpUsingComparator(int k, E x) {  
  420.     while (k > 0) {  
  421.         int parent = (k - 1) >>> 1;  
  422.         Object e = queue[parent];  
  423.         if (comparator.compare(x, (E) e) >= 0)  
  424.             break;  
  425.         queue[k] = e;  
  426.         k = parent;  
  427.     }  
  428.     queue[k] = x;  
  429. }  
  430.   
  431. /** 
  432.  * 
  433.  * 节点的调整:从此节点开始,由上至下进行位置调整。把小值上移。 
  434.  * 可以称之为一次筛选,从一个无序序列构建堆的过程就是一个不断筛选的过程. 
  435.  * 直到筛选到的节点为叶子节点,或其左右子树均大于此节点就停止筛选。 
  436.  */  
  437. private void siftDown(int k, E x) {  
  438.     if (comparator != null)       
  439.         siftDownUsingComparator(k, x);  
  440.     else        //如果比较器为空,则按自然顺序比较元素  
  441.         siftDownComparable(k, x);  
  442. }  
  443.   
  444. /** 
  445.  * 比较器为空的一趟筛选过程。 
  446.  * PS:元素必须自己已经实现了Comparable方法 
  447.  * 否则将抛出异常 
  448.  */  
  449. private void siftDownComparable(int k, E x) {  
  450.     Comparable<? super E> key = (Comparable<? super E>)x;   //父节点值  
  451.     int half = size >>> 1;        // loop while a non-leaf  
  452.     while (k < half) {       //如果还不是叶子节点  
  453.         int child = (k << 1) + 1//左子节点索引,先假设其值最小  
  454.         Object c = queue[child];  
  455.         int right = child + 1;      //右子节点索引  
  456.         if (right < size &&  
  457.             ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)   //如果左节点大于右节点  
  458.             c = queue[child = right];   //右节点为最小值  
  459.         if (key.compareTo((E) c) <= 0)   //如果父节点小于左右节点中的最小值,则停止筛选  
  460.             break;  
  461.         queue[k] = c;   //小值上移  
  462.         k = child;      //沿着较小值继续筛选  
  463.     }  
  464.     queue[k] = key; //把最先的父节点的值插入到正确的位置  
  465. }  
  466.   
  467. /** 
  468.  * 比较器不为空的一趟筛选过程 
  469.  * 一样的 
  470.  */  
  471. private void siftDownUsingComparator(int k, E x) {  
  472.     int half = size >>> 1;  
  473.     while (k < half) {  
  474.         int child = (k << 1) + 1;  
  475.         Object c = queue[child];  
  476.         int right = child + 1;  
  477.         if (right < size &&  
  478.             comparator.compare((E) c, (E) queue[right]) > 0)  
  479.             c = queue[child = right];  
  480.         if (comparator.compare(x, (E) c) <= 0)  
  481.             break;  
  482.         queue[k] = c;  
  483.         k = child;  
  484.     }  
  485.     queue[k] = x;  
  486. }  
  487.   
  488. /** 
  489.  * 构造初始堆的过程 
  490.  */  
  491. private void heapify() {  
  492.     for (int i = (size >>> 1) - 1; i >= 0; i--)     //从最后一个非终端节点(size/2 - 1)开始调整位置  
  493.         siftDown(i, (E) queue[i]);  
  494. }  
  495.   
  496. /** 
  497.  * 返回比较器 
  498.  */  
  499. public Comparator<? super E> comparator() {  
  500.     return comparator;  
  501. }  
  502.   
  503. /** 
  504.  * 序列化此队列 
  505.  */  
  506. private void writeObject(java.io.ObjectOutputStream s)  
  507.     throws java.io.IOException{  
  508.     // Write out element count, and any hidden stuff  
  509.     s.defaultWriteObject();  
  510.   
  511.     // Write out array length, for compatibility with 1.5 version  
  512.     s.writeInt(Math.max(2, size + 1));  
  513.   
  514.     // Write out all elements in the "proper order".  
  515.     for (int i = 0; i < size; i++)  
  516.         s.writeObject(queue[i]);  
  517. }  
  518.   
  519. /** 
  520.  * 读取序列化的文件 
  521.  */  
  522. private void readObject(java.io.ObjectInputStream s)  
  523.     throws java.io.IOException, ClassNotFoundException {  
  524.     // Read in size, and any hidden stuff  
  525.     s.defaultReadObject();  
  526.   
  527.     // Read in (and discard) array length  
  528.     s.readInt();  
  529.   
  530.     queue = new Object[size];  
  531.   
  532.     // Read in all elements.  
  533.     for (int i = 0; i < size; i++)  
  534.         queue[i] = s.readObject();  
  535.   
  536.     heapify();  //重新构建堆  
  537. }  



注:转载地址 http://zhouyunan2010.iteye.com/blog/1244846

原创粉丝点击