实现方式的选择?
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