1、基本思想:
定义
2、java实现:
package com.ynu.www.tool; public class HeapSort { private static int[] sort = new int[] { 1, 0, 10, 20, 3, 5, 6, 4, 9, 8, 12, 17, 34, 11 }; public static void main(String[] args) { buildMaxHeapify(sort);//创建初始最大堆 需要从第一个非叶子节点开始调用<span style="font-family: Arial, Helvetica, sans-serif;">maxHeapify()方法</span><span style="font-family: Arial, Helvetica, sans-serif;"> </span> heapSort(sort);//堆排序,将根节点跟最后一个叶子节点交换,然后对剩下的前n-1个节点调用maxHeapify()方法<span style="font-family: Arial, Helvetica, sans-serif;"> </span> print(sort);//打印树结构,也比较特别,用到log2,求层次 } private static void buildMaxHeapify(int[] data) { // 从最后一个的父节点开始 int startIndex = getParentIndex(data.length - 1); // 从尾端开始创建最大堆,每次都是正确的堆 for (int i = startIndex; i >= 0; i--) { maxHeapify(data, data.length, i); } } /** *创建最大堆 * *@param data 进行创建最大堆的数组 *@param heapSize需要创建最大堆的大小,为了保证验证左孩子,右孩子跟父节点大小比较的时候,保证不超过data的大小。 *@param index 当前需要创建最大堆的位置 */ private static void maxHeapify(int[] data, int heapSize, int index) { // 当前点与左右子节点比较 int left = getChildLeftIndex(index); int right = getChildRightIndex(index); int largest = index; if (left < heapSize && data[index] < data[left]) { largest = left; } if (right < heapSize && data[largest] < data[right]) { largest = right; } // 得到最大值后可能需要交换,如果交换了,其子节点可能就不是最大堆了,需要重新调整 if (largest != index) { int temp = data[index]; data[index] = data[largest]; data[largest] = temp; maxHeapify(data, heapSize, largest); } } /** *排序,最大值放在末尾,data虽然是最大堆,在排序后就成了递增的 * * @paramdata */ private static void heapSort(int[] data) { // 末尾与头交换,交换后调整最大堆 for (int i = data.length - 1; i > 0; i--) { int temp = data[0]; data[0] = data[i]; data[i] = temp; maxHeapify(data, i, 0); } } /** *父节点位置 * *@paramcurrent *@return */ private static int getParentIndex(int current) { return (current - 1) >> 1; } /** *左子节点position注意括号,加法优先级更高 * * @paramcurrent *@return */ private static int getChildLeftIndex(int current) { return (current << 1) + 1; } /** *右子节点position * *@paramcurrent *@return */ private static int getChildRightIndex(int current) { return (current << 1) + 2; } private static void print(int[] data) { int pre = -2; for (int i = 0; i < data.length; i++) { if (pre < (int) getLog(i + 1)) { pre = (int) getLog(i + 1); System.out.println(); } System.out.print(data[i] + "|"); } } /** *以2为底的对数 * *@paramparam *@return */ private static double getLog(double param) { return Math.log(param) / Math.log(2); } }
<p style="margin-top: 10px; margin-bottom: 10px; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); background-color: rgb(248, 248, 248); text-indent: 28px; font-family: 宋体; font-size: 14px; line-height: 28px;"> </p>
3、算法分析:
堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。
堆排序的最坏时间复杂度为O(nlgn)。堆排序的平均性能较接近于最坏性能。
由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。
堆排序是就地排序,辅助空间为O(1),
它是不稳定的排序方法。
4、补充:
>表示大于,如:if(a>b)...结果是boolean类型
>>表示右移,如:int i=15; i>>2的结果是3,移出的部分将被抛弃。
转为二进制的形式可能更好理解,0000 1111(15)右移2位的结果是0000 0011(3),0001 1010(18)右移3位的结果是0000 0011(3)。
>>>叫什么我也不是很清楚,但是我知道它表示的含义:
j>>>i 与 j/(int)(Math.pow(2,i))的结果相同,其中i和j是整形。