1. 程式人生 > >PriorityQueue主要原始碼解析

PriorityQueue主要原始碼解析

簡介:PriorityQueue優先佇列,是Queue的實現類,但不具有先進先出的特點,而是根據自然排序或者自定義排序進行內部排序的,自然排序下(如儲存Integer,String)會根據從小到大排序,自定義排序可以根據自己定義的比較方法排序。

1.Priority的底層是陣列,初始化長度為11,下面是PriorityQueue的主要建立方法

    private static final int DEFAULT_INITIAL_CAPACITY = 11;

    private transient Object[] queue;

    //呼叫無參構造時初始化一個長度為11的陣列
    public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

    //直接指定陣列長度
    public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

    //指定陣列長度和比較器
    public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

2.新增元素:add(E e)和offer(E e),兩個方法其實是一樣的,add方法內部就是呼叫offer方法

新增一個元素時,先判斷當前元素加入是否越界,即用引數size(表示當前數組裡的元素個數)判斷是否大於佇列長度,若大於則呼叫grow()方法擴充套件佇列,然後將size+1,若元素為空,將元素放在首位,否則呼叫siftUp()方法將元素存入陣列


    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);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }

 佇列擴充套件方法

 private void grow(int minCapacity) {
        int oldCapacity = queue.length;
        // 當原陣列長度小於64,每次將長度+2,否則擴充套件成原來的1.5倍
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                         (oldCapacity + 2) :
                                         (oldCapacity >> 1));

        // 若新陣列長度大於MAX_ARRAY_SIZE,則呼叫hugeCapacity比較minCapacity是否大於MAX_ARRAY_SIZE,若大於就把新陣列長度賦為Integer.MAX_VALUE,否則為MAX_ARRAY_SIZE
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //然後將佇列中的元素複製到新陣列中
        queue = Arrays.copyOf(queue, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

 siftUp()將元素存入陣列

    // 判斷是否有自定義比較器,沒有則有自然排序
    private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }

    //自然排序:k即陣列最後元素的下標,從後往前遍歷,有元素比x大的,即往後移一位,知道有元素比x小,對出迴圈,將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;
    }

3.刪除元素

poll():刪除並返回佇列頭的元素,如果沒有元素可取,返回null

remove():刪除並返回佇列頭的元素,如果沒有元素可取,報異常

remove(Object o):遍歷陣列查詢元素的下標,刪除下標

peek():返回佇列頭的元素,不刪除

    //將第一個元素刪除,然後將後面的元素往前移,將最後的元素賦為null
    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;
    }

    public E remove() {
        E x = poll();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

    public boolean remove(Object o) {
        int i = indexOf(o);
        if (i == -1)
            return false;
        else {
            removeAt(i);
            return true;
        }
    }

    public E peek() {
        if (size == 0)
            return null;
        return (E) queue[0];
    }

siftDown():將元素往前移

    private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

    private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // loop while a non-leaf
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }

    private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }

4.例子


import java.util.Comparator;
import java.util.Iterator;
import java.util.PriorityQueue;

public class QueueTest {
	public static void main(String[] args) {
        //自然排序
		PriorityQueue<Integer> queue=new PriorityQueue<>();//初始化長度為11
		queue.offer(1);
		queue.add(1);
		queue.add(3);
		queue.add(2);
		int i=0;
		while(i++<10){
//			System.out.println(queue.peek());//輸出1,1,1,1,...,1,1
//			System.out.println(queue.poll());//輸出1,2,3,null,null,null,...,用poll時,如果佇列為空,即返回null
//			System.out.println(queue.remove());//輸出1,2,3,然後報異常
		}
		
		//自定義排序,引入自定義比較器,否則會報類轉換異常
		PriorityQueue<Student> students=new PriorityQueue<>(10, new Comparator<Student>() {

			@Override
			public int compare(Student o1, Student o2) {
				// TODO Auto-generated method stub
				return o1.getAge()-o2.getAge();
			}
		});
		students.add(new Student(10, "張三"));
		students.add(new Student(8, "李四"));
		students.add(new Student(12, "王五"));
		for(Student student:students){
			System.out.println(student);
		}
		
		Iterator<Student> iterator = students.iterator();
		while(iterator.hasNext()){
			Student next = iterator.next();
			System.out.println(next.getAge()+"=="+next.getName());
		}
		
		
	}
}

Student類

package newCode;

public class Student {
	private int age;
	private String name;
	public Student(int age,String name) {
		// TODO Auto-generated constructor stub
		this.age=age;
		this.name=name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [age=" + age + ", name=" + name + "]";
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}