您的位置:首页 > 理论基础 > 数据结构算法

基于堆的优先队列及堆排序

2017-05-17 22:38 190 查看
许多应用程序需要处理有序的元素,例如事件循环中要先处理高的事件。在这种情况下,我们设计的数据结构需要支持两种操作:删除最大元素和插入元素,这种数据类型就叫做优先队列,它可以用来解决TopM问题(找出M个最大的元素)或者多向归并问题(将多个有序的输出流合并成一个有序的输出流),在这两种情况下,问题的输入都可能是无限的,不可能先读取所有输入再进行排序,而优先队列适合解决这种问题。

先来看一下堆的概念,堆是二叉堆的简称,是一种每个节点的元素都大于两个子节点的完全二叉树,在优先队列中一般用数组表示。

优先队列的代码如下:

package chapter2;

/**
* Created by jia on 17-5-17.
*/
//基于堆实现的优先队列
public class MaxPQ<T extends Comparable<T>> {
private T[] pq;  //基于堆的完全二叉树
private int n;   //数据存储于pq[1..n]中,pq[0]没有用到

public MaxPQ(int num) {
pq = (T[]) new Comparable[num+1];
}

public boolean isEmpty() {
return n == 0;
}

public int size() {
return n;
}

public void insert(T t) {
pq[++n] = t;
swim(n);
}

public T delMax() {
T max = pq[1];      //根结点的元素值最大
swap(1, n--);    //把最大值和最后一个元素交换,并将数组大小减一
pq[n+1] = null;     //删除最大值
sink(1);         //恢复堆的有序性
return max;
}

//递归地把节点i跟其父节点比较以构造二叉堆
private void swim(int i) {
while (i > 1 && pq[i].compareTo(pq[i/2]) > 0) {
swap(i, i/2);
i /= 2;
}
}

//递归地把节点i跟其两个子节点比较以构造二叉堆
private void sink(int i) {
while (2*i <= n) {
int j = 2*i;
if (j < n && pq[j].compareTo(pq[j+1]) < 0) j++;
if (pq[i].compareTo(pq[j]) >= 0) break;
swap(i, j);
i = j;
}
}

private void swap(int i, int j) {
T temp = pq[i];
pq[i] = pq[j];
pq[j] = temp;
}
}


堆排序的主要思想是构造一个最大元素的优先队列,然后再重复调用删除最大元素的方法来将它们按照顺序删除。堆排序分为两个阶段,先进行堆的构造,然后再用sink函数进行排序。代码如下:

package chapter2;

/**
* Created by jia on 17-5-17.
*/
public class HeapSort {
public static void sort(Comparable[] a) {
//此时只能以a[0]为起点,为此要修改sink等函数
int n = a.length - 1;
//先用for循环构造一个最大堆
for (int i = (n-1)/2; i >= 0; i--) {
sink(a, i, n);
}
ArrayPrint.print(a);

//再用sink函数进行排序
while (n > 0) {
swap(a, 0, n);   //每次循环都将当前的最大值放到a
处
sink(a, 0, --n);  //再把n减去1,然后找出从0到n的最大值,放到a[0]处,下轮循环会把此值交换到a

}
}

private static void swap(Comparable[] a, int i, int j) {
Comparable temp = a[i];
a[i] = a[j];
a[j] = temp;
}

private static void sink(Comparable[] a, int i, int n) {
//n代表sink函数截止的最后一个数组索引值
while (2*i +1 <= n) {
//以a[0]为起点的数组其元素a[i]的两个子节点是2*i+1和2*i+2
int j = 2*i + 1;
if (j < n && a[j].compareTo(a[j+1]) < 0) j++;
if (a[i].compareTo(a[j]) >= 0) break;
swap(a, i, j);
i = j;
}
}

public static void main(String[] args) {
String[] a = "21s1gwhfiajnc493tquwofadjst873ewigdshjk8y0qfwedsknlc49-ufqewojd;c2".split("");
sort(a);
ArrayPrint.print(a);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  堆排序 数据结构