堆排序

来源:互联网 发布:51单片机难的设计题目 编辑:程序博客网 时间:2024/06/06 02:49

堆排序(Heapsort)

          堆分为大根堆和小根堆,是完全二叉树大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,根据大根堆的要求可知,最大的值一定在堆顶。

堆排序步骤示例

(1)、建堆: 建堆的核心内容是调整堆,使二叉树满足堆的定义(每个节点的值都不大于其父节点的值)。调堆的过程应该从最后一个非叶子节点开始,假设有数组A = {1, 3, 4, 5, 7, 2, 6, 8, 0}。那么调堆的过程如下图,数组下标从0开始,A[3] = 5开始。分别与左孩子和右孩子比较大小,如果A[3]最大,则不用调整,否则和孩子中的值最大的一个交换位置,在图1中因为A[7] > A[3] > A[8],所以A[3]与A[7]对换,从图1转到图2。

(2)、调堆:如果初始数组是非降序排序,不需要调堆,本身满足堆的定义,运行时间为O(1),为最好情况;如果初始数组是如图5,只有A[0] = 1不满足堆的定义,经过与子节点的比较调整到图6,但是图6仍然不满足堆的定义,所以要递归调整,一直到满足堆的定义或者到堆底为止。如果递归调堆到堆底才结束,那么是最坏情况,运行时间为O(h) (h为需要调整的节点的高度,堆底高度为0,堆顶高度为floor(logn) )。建堆完成之后,堆如图7是个大根堆。将A[0] = 8 与 A[heapLen-1]交换,然后heapLen减一,如图8,然后AdjustHeap(A, heapLen-1, 0),如图9。如此交换堆的第一个元素和堆的最后一个元素,然后堆的大小heapLen减一,对堆的大小为heapLen的堆进行调堆,如此循环,直到heapLen == 1时停止,最后得出结果如图12。


注:子节点在数组中的下标与父节点的在数组中的下标之间的关系

堆排序示例代码

/** *  堆排序 * @author bianjie * */public class Heapsort {/** * 建堆 *  * @param data *            数据 * @param length *            数据长度 */public static void buildHeap(int data[], int length) {// 起始的第一个父节点int startIndex = length / 2 - 1;for (; startIndex >= 0; startIndex--) {// 调堆adjustHeap(data, length ,startIndex);}}/** * 调整堆的大小位置 * @param data 数据数组 * @param dataLength 数据长度 * @param parentIndex 父节点,需注意父节点与子节点的关系得到的下标 */public static void adjustHeap(int data[], int dataLength, int parentIndex) {//因为数组的首个下标为0,而堆中对应的节点比起大1,所以计算左右子节点的时候需注意//不能直接用2*parentIndex和(2*parentIndex+1)作为左右节点在数组中的下标//当然你也可以一开始就调节他们之间下标一一对应关系,就可以用// 子左节点下标int leftChildIndex = 2 * (parentIndex + 1) - 1;// 子右节点下标int rightChildIndex = 2 *(parentIndex + 1);// 节点中的最大值的下标,初始设置为父节点为最大值int maxValueIndex = parentIndex;while (leftChildIndex <= dataLength || rightChildIndex <= dataLength) {// 左节点存在且大于父节点if (leftChildIndex < dataLength && data[leftChildIndex] > data[maxValueIndex]) {maxValueIndex = leftChildIndex;}// 右节点存在且大于父节点if (rightChildIndex < dataLength &&  data[rightChildIndex] > data[maxValueIndex]) {maxValueIndex = rightChildIndex;}// 存在子节点的值比父节点的值大,交换两者的值if (maxValueIndex != parentIndex) {// 进行数据位置交换swapData(data, parentIndex, maxValueIndex);// 打印数据printData(data);adjustHeap(data,dataLength,parentIndex);// 打乱了事先的低端排序,需要重新进行检验是否满足堆排序parentIndex = maxValueIndex;leftChildIndex =  2 * (parentIndex + 1) - 1;rightChildIndex = 2 * (parentIndex + 1);}else{break;}}}/** * 排序 * @param data 数据数组 */public static void sortHeap(int data[]) {int dataLength = data.length;// 建堆buildHeap(data, dataLength);//辅助显示排序的结果标志int time = 1;while (dataLength > 1) {//一趟排序完得到的堆顶的最大值进行首尾位置调换,//同时将数据长度减一,起到保存已经得到的最大值的数据数列位置swapData(data, 0, --dataLength);printData(data);System.out.println("------ 第   "+(time++)+" 趟排序完成---");//重新进行建堆,调堆buildHeap(data, dataLength);}}/** * 打印数据 *  * @param data */public static void printData(int data[]) {for (int i : data) {System.out.print(i + " ");}System.out.println();}/** * 交换数据 *  * @param data 数据数组 * @param firstIndex 要交换的第一个数据下标 * @param secondIndex 要交换的第二个数据下标 */public static void swapData(int[] data, int firstIndex, int secondIndex) {int temp = data[firstIndex];data[firstIndex] = data[secondIndex];data[secondIndex] = temp;}public static void main(String[] args) {int data[] = { 1, 3, 4, 5, 7, 2, 6, 8, 0 };printData(data);sortHeap(data);}}


运行结果