TaskQueue類是在Timer文件中的TaskQueue,它是一個又堆實現的優先隊列。TaskQueue按任務剩下一次執行時間排序的優先級隊列,使用的數據結構是小頂堆(保證堆頂的元素最小) 堆的性質並不保證有序,只是保證能在O(1)找到最小值(小頂堆)或者最大值(大頂堆)java
堆本質上是一個徹底二叉樹,保證了根節點老是比葉子節點大或者小。由於這個優先級隊列主要是由來存放TimerTask的,因此它使用的是一個TimerTask的數組來實現的。
api
import java.util.Arrays; import java.util.TimerTask; class TaskQueue { /** * 使用數組存爲,數據是TimerTask類型 */ private TimerTask[] queue = new TimerTask[128]; /** * 任務隊列的大小,queue[0]沒有使用,queue[1]-queue[size]是排好序的 */ private int size = 0; int size() { return size; } /** * */ TimerTask getMin() { return queue[1]; } TimerTask get(int i) { return queue[i]; } /** * 這裏快速刪除,並無維護堆,多是大神考慮到只有在TimerTask的purge中調用了改方法 * purge方法中若是刪除了至少1個元素,就會調用heapify方法從新建堆 * 1 <= i <= size. */ void quickRemove(int i) { assert i <= size; queue[i] = queue[size]; queue[size--] = null; // 刪除多餘的引用,防止內存泄露 } boolean isEmpty() { return size==0; } /** * 清除隊列 */ void clear() { // 清除引用,避免內存泄露 for (int i=1; i<=size; i++) queue[i] = null; size = 0; } /** * 添加一個新任務到隊列做爲葉子節點,而後從這個節點開始從新建堆 */ void add(TimerTask task) { // 保證數組的大小可以存放 if (size + 1 == queue.length) queue = Arrays.copyOf(queue, 2*queue.length); queue[++size] = task; fixUp(size); } /** * 自底向上重建堆,k>>1 整數k右移1位表示除以2 k>>1 ==>k/2 * 根據堆的性質能夠知道一個節點k 的父節點能夠表示爲k/2 * 所以這個方法的從指定的節點k,依次檢查和它的父節點的關係 * 若是父節點大於子節點就交換父節點與子節點(小頂堆,堆頂是最小的元素) */ private void fixUp(int k) { while (k > 1) { int j = k >> 1; if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime) break; TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; k = j; } } /** *自頂向下重建堆,k<<1 整數k向左移1位表示乘以2 k<<1 ==>k*2 *根據堆的性質知道,對於一個節點k,它的子節點分別爲k*2 和k*2+1(若是存在) * *這個方法就是對於節點k若是存在子節點,則找到子節點中較小的一個和k進行比較交換 */ private void fixDown(int k) { int j; while ((j = k << 1) <= size && j > 0) { if (j < size && queue[j].nextExecutionTime > queue[j+1].nextExecutionTime) j++; // j indexes smallest kid if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime) break; TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; k = j; } } /** * 移除最小的(第一個),而後把最後一個元素移到堆頂,執行自頂向下從新建堆 */ void removeMin() { queue[1] = queue[size]; queue[size--] = null; fixDown(1); } /** * 最小元素改變,從新建堆 */ void rescheduleMin(long newTime) { queue[1].nextExecutionTime = newTime; fixDown(1); } /** * 重建堆,由於葉子節點知足條件了,因此從最後一個根節點開始 */ void heapify() { for (int i = size/2; i >= 1; i--) fixDown(i); } }
其實這個類真的值得仔細閱讀,代碼實現的真的很是優雅。它很是巧妙的從數組下標爲1的位置開始存放元素,使得fixUp方法和fixDown方法有一種賞心悅目的感受。數組
在TaskQueue中並無排序的操做,由於只須要每一次取最小的元素(堆頂的元素)就能夠了,堆不會保證有序,可是保證堆頂的元素必定是最值。其實有了上面的代碼寫一個排序代碼真的很是容易了,下面就是把數據TimerTask換爲int類型的實現,其實只是寫了一個堆排序的方法。數據結構
import java.util.Arrays; public class IntQueue { private int[] queue = new int[16]; private int size = 0; int size() { return size; } void add(int task) { // 保證數組的大小可以存放 if (size + 1 == queue.length) queue = Arrays.copyOf(queue, 2*queue.length); queue[++size] = task; fixUp(size); } /** * 自底向上建堆 */ private void fixUp(int k) { while (k > 1) { int j = k >> 1; if (queue[j] <= queue[k]) break; int tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; k = j; } } /** * */ void removeMin() { queue[1] = queue[size]; fixDown(1); } /** *自頂向下建堆 */ private void fixDown(int k) { int j; while ((j = k << 1) <= size && j > 0) { if (j < size && queue[j] > queue[j+1]) j++; // j indexes smallest kid if (queue[k] <= queue[j]) break; int tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; k = j; } } /** * 建堆 */ void heapify() { for (int i = size/2; i >= 1; i--) fixDown(i); } @Override public String toString() { return Arrays.toString(queue); } void sort() { while(size>1) { int tmp = queue[1]; queue[1]=queue[size]; queue[size] = tmp; size--; fixDown(1); } } public static void main(String[] args) { IntQueue queue = new IntQueue(); int [] data = new int [10]; for(int i=0;i<10;i++) data[i] = (int) (Math.random()*100); for(int i=0;i<data.length;i++) queue.add(data[i]); System.out.println(queue.toString()); queue.sort(); System.out.println(queue.toString()); } }