優先級隊列(java.util.PriorityQueue)

實現方式的選擇?

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 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章