堆排序在排序算法里面算是非常常用也非常经典的一个算法。堆排序适合于大量数据的排序,堆排序的前续工作花费的时间比较多,下面我们以大根堆为例说说: 大根堆,就是根节点是最大的元素,所以每次把最大的元素选出来,与最后的一个元素交换,然后再把前n-1个元素(也就是除最后一个元素)进行一个堆的重构,让其具有大根堆的性质,重复上面的过程,直到只剩一个元素为止。这个过程其实是个选择排序的过程,但是少了交换的次数,堆排序的时间复杂度是nlogn。
package sort;
public class MySort {
/**
* 堆排序包括两个步骤 (1)初始堆(堆的定义:(a)堆是一个完全二叉树(b)根结点的值或者大于左右子树的值或者小于左右子树的值(c)左右子树也是一个堆)
* (2)调整堆(当初始小顶堆之后,堆顶元素是最小的元素,取出最小的元素与最后一个元素相交换,再把剩下i-1个元素调整成堆,依次调整直到1为止)
* 非终端节点调整 初始堆时从i/2向上调整成堆 把第一个元素与最后一个元素交换之后从第1个元素开始调整成新堆
*
* @author TD_LSW
*
*/
private static int heapSize;
//双亲编号
private static int parent(int i) {
return i / 2;
}
//左孩子编号
private static int leftChild(int i) {
return 2 * i + 1;
}
//右孩子编号
private static int rightChild(int i) {
return 2 * i + 2;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MySort mySort = new MySort();
int a[] = { 0, 4, 1, 3, 2, 16, 9, 10, 14, 8, 7,10,22,16 };
heapSize = a.length;
mySort.heapSort(a);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
/**
* 堆排序:首先使用建立最大堆的算法建立好最大堆,然后将堆顶元素(最大值)与最后一个值交换,同时使得
* 堆的长度减小1 ,调用保持最大堆性质的算法调整,使得堆顶元素成为最大值,此时最后一个元素已被排除在外
*/
private void heapSort(int[] a) {
// TODO Auto-generated method stub
build_MaxHeap(a);
for (int i = heapSize - 1; i >= 1; i--) {
int temp = a[0];
a[0] = a[i];
a[i] = temp;
heapSize--;
keep_MaxHeap(a, 0);
}
}
/**
* 保持最大堆的性质
* @param a,堆中的数组元素
* @param i,对以该元素为根元素的堆进行调整,假设前提:左右子树都是最大堆
*
* 由于左右孩子都是最大堆,首先比较根元素与左右孩子,找出最大值,假如不是根元素,则调整两个元素的值;
* 由于左孩子(右孩子)的值与根元素交换,有可能打破左子树(右子树)的最大堆性质,因此继续调用,直至叶子元素。
*/
private void keep_MaxHeap(int[] a, int i) {
// TODO Auto-generated method stub
int left = leftChild(i);
int right = rightChild(i);
int temp = 0;
if (left < heapSize && a[left] > a[i]) {
temp = left;
} else {
temp = i;
}
if (right < heapSize && a[right] > a[temp]) {
temp = right;
}
if (temp == i) {
return;
} else {
int tempData = a[i];
a[i] = a[temp];
a[temp] = tempData;
keep_MaxHeap(a, temp);
}
}
/**
* 建立最大堆。在数据中,a.length/2+1一直到最后的元素都是叶子元素,也就是平凡最大堆,
* 因此从其前一个元素开始,一直到第一个元素,重复调用keep_MaxHeap函数,使其保持最大堆的性质
* @param a
*/
private void build_MaxHeap(int[] a) {
// TODO Auto-generated method stub
for (int i = heapSize / 2; i >= 0; i--) {
keep_MaxHeap(a, i);
}
}
}