實現方式的選擇?
1, 用鏈表實現,插入數據以常數時間,但是訪問最小(大)項要對鏈表進行線性掃描。若保持鏈表的有序性,訪問訪問最小(大)項以常數時間,但是插入確實線性時間。
2, 用二叉堆實現,具有這些優點(1)通過簡單的數組實現,(2)最壞的情況,以O(logN)時間inser和deleteMin,(3)常數平均時間insert,最壞情況下常數時間findMin;
二叉堆的介紹:
二叉堆:是一顆完全二叉樹,可以用數組來表示,父親在,左孩子在位置2i,右孩子在2i+1處。(爲了滿足這個條件,我們將數組0位置放空,從一開始存數)
最小(大)堆:父親節點的數永遠小(大)於孩子的數;
二叉堆插入操作如下圖所示:(抄網上的圖哈)
向上過濾的策略,就是將要插入的元素放在下一個可用的位置,然後不斷地與父親節點比較,一直向上冒,知道父節點的值小於它(針對最小堆而言)或爲空;代碼如下所示:
public boolean add(AnyType x){
if(currentSize + 1 == array.length){
doubleArray();
}2
int hole = ++currentSize;
array[0] = x; //暫時保存該插入值
for(;array[hole/2].compareTo(x)>0;hole=hole/2){
array[hole]=array[hole/2];
}
array[hole] = x;
return true;
}
顯然插入所需的時間爲:O(logN)
刪除操作:(抄網上的圖,做些更改)
向下過濾的策略,取出根節點的數,取出數組最後的元素X填補根節點的空缺。開始向下過濾。根節點的數與兩個孩子比較獲取其最小值來交換位置,依次類推,直到父節點的值小於兩個孩子的值。
//代碼如下所示:
public AnyType remove(){
AnyType minItem = array[1];
//將最後一個元素填補根節點的空缺
array[1] = array[currentSize - 1];
//從下標1(即根節點)開始向下過濾
percolateDown(1);
return minItem;
}
public boolean percolateDown(int i){
int child;
AnyType x = array[i];
for(;2i<=array.length;i=child){
child = 2*i;
//先從兩個孩子中選取較小的孩子(如果只有一個孩子,那麼跳過);
if(child != currentSize && array[child+1].compareTo(array[child])<0){
child++;
}
if(array[child].compareTo(array[i])<0){
array[i] = array[child];
array[child] = x;
}else{
break;
}
}
}
顯然deleteMin所需的時間爲:O(logN)
buildHeap(構造堆)操作:
對所有的父節點(編號由大到小的)調用percolateDown,向下過濾,公共需要調用currentSize/2次數;
代碼如下所示:
Private void buildHeap(){
For(int i= currentSize/2;i>0;i--){
percolateDown(i);
}
}
所需的時間是線性的O(N)(證明:略)
Java.util.Queue類,隊列中的元素必須實現Comparator接口,否則會出錯,源碼如下所示(截取了部分對分析有用的代碼):
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
//默認的隊列的容量大小
private static final int DEFAULT_INITIAL_CAPACITY = 11;
//該數組用來保存數據的哈
private transient Object[] queue;
//該隊列當前的數據的多少
private int size = 0;
//保存比較的對象
private final Comparator<? super E> comparator;
//隊列的最大長度,每次add數據的時候,若隊列滿了會自動擴展,MAX_ARRAY_SIZE爲數組的最大長度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
public boolean add(E e) {
return offer(e);
}
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;//這個可以暫時不需要管它(用來記錄更改的次數)
int i = size;
if (i >= queue.length)
grow(i + 1); //隊列滿了,grow函數進行擴展
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e);//向上過濾哈。。
return true;
}
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 siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
private void siftUpComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = key;
}
private void siftUpUsingComparator(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;
}
}
到此,基本介紹完畢,寫了下如何用queue的代碼,如下所示:
package jihe;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
public class PriorityQueueTest{
public static void main(String[] args) {
//自然順序排序
Queue q = new PriorityQueue();
for(int i=10;i>0;i--){
q.add(i);
}
while(!q.isEmpty()){
System.out.print(q.remove()+" ");
}
System.out.println();
//根據類本身提供的compareTo方法排序
Queue<person> q1 = new PriorityQueue<person>();
for(int i=0;i<10;i++){
q1.add(new person(i));
}
while(!q1.isEmpty()){
System.out.print(q1.remove().height+" ");
}
System.out.println();
//由Comparator提供的排序哈
Queue<person> q2 = new PriorityQueue<person>(10,new xx());
for(int i=0;i<10;i++){
q2.add(new person(i));
}
while(!q2.isEmpty()){
System.out.print(q2.remove().height+" ");
}
}
}
class person implements Comparable<person>{
public int height;//懶得提供公有的方法哈,定義爲公有的變量。。。見諒哈
public person(int height){
this.height = height;
}
@Override
public int compareTo(person o) {
// TODO Auto-generated method stub
if(this.height < o.height){
return -1;
}
return 1;
}
}
class xx implements Comparator<person>{
@Override
public int compare(person o1, person o2) {
// TODO Auto-generated method stub
if(o1.height>o2.height){
return -1;
}
return 1;
}
}
輸出結果:
1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8 9
9 8 7 6 5 4 3 2 1 0