堆排序是用大顶堆或者小顶堆的性质来实现排序。
先解释一下优先队列,优先队列就是从这个队列里面出来的数字总是这个队列里面数字最大或者最小的那一个,而堆就是一个优先队列的具体实现,大顶堆是一个完全二叉树,父节点大于等于子节点,所以他的顶(根)是最大的,小顶堆反之。
所以我们先实现一个大顶堆。
package sort;
/**
* 使用二叉堆的优先队列,每个节点大于等于两个子节点
* 并且是完全二叉树,每个节点的与数组的索引是一一对应的
* @author asus
*
* @param <Item>
*/
public class MaxPQ<Item extends Comparable<Item>>
{
private Item[] pq;
private int size = 0;
public MaxPQ()
{
pq = (Item[]) new Comparable[2];
}
public MaxPQ(int max)
{
pq = (Item[]) new Comparable[max + 1];
}
/**
* 将数组存入pq形成优先队列,但不改变数组
* @param a
*/
public MaxPQ(Item[] a)
{
int len = a.length;
pq = (Item[]) new Comparable[len + 1];
for(int i = 1;i < len;i++)
{
pq[i] = a[i - 1];
}
pq[len] = a[len - 1];
size = len;
for(int i = size/2;i >= 1;i--)
{
sink(i);
}
}
/**
* 插入操作,先在二叉树尾部插入一个数
* 再将这个数上浮
* @param i
*/
public void insert(Item i)
{
if(size == pq.length - 1)
resize(pq.length*2);
pq[++size] = i;
swim(size);
}
/**
* 删除最大的一个数
* 将pq[1]也就是数的根与最后一个数交换
* 再将新的根下沉
* 最后返回原来的根
* @return
*/
public Item delMax()
{
Item t = pq[1];
exch(1,size--);
sink(1);
pq[size+1] = null;
return t;
}
public Item max()
{
return pq[1];
}
public boolean isEmpty()
{
return size == 0;
}
public int size()
{
return size;
}
private void swim(int k)
{
while(k > 1 && less(k/2,k))
{
exch(k,k/2);
k = k/2;
}
}
private void sink(int k)
{
while(2*k <= size)
{
int i = 2*k;
if(i < size && less(i,i + 1))
i++;
if(less(k,i))
{
exch(k,i);
k = i;
}
else break;
}
}
private void exch(int i,int j)
{
Item temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;
}
private boolean less(int i,int j)
{
return pq[i].compareTo(pq[j]) < 0;
}
private void resize(int max)
{
Item[] temp = (Item[]) new Comparable[max];
for(int i = 1;i < pq.length;i++)
{
temp[i] = pq[i];
}
pq = temp;
}
}
然后堆排序实现就很简单啦,将一个数组全部加入大顶堆,一个个拿出来就是已经排好序的啦,当然可以修改一下这个大顶堆的代码,让他更适合实现堆排序。
堆排序的时间复杂度是nlogn。