博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
堆排序算法的java实现
阅读量:4566 次
发布时间:2019-06-08

本文共 4424 字,大约阅读时间需要 14 分钟。

     堆积排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素。堆排序是不稳定的排序方法,辅助空间为O(1), 最坏时间复杂度为O(nlog2n) ,堆排序的堆序的平均性能较接近于最坏性能。

中心思想是在使用数组存储的完全二叉树内从下往上每次构造大顶堆或者小顶堆,然后将找出来的堆顶数字放到数组结尾,剩下数组继续构造堆结构。

主要是参考了网上比较常见的两种堆排序的java实现,自己加了一些注释

实现1

采用递归,每次父节点与最大子节点交换后递归构造被交换后的子树

public static void heapSort(int[] array) {        if (array == null || array.length <= 1) {            return;        }        buildMaxHeap(array);        System.out.println("buildMaxHeap " + Arrays.toString(array));        for (int i = array.length - 1; i >= 1; i--) {            exchangeElements(array, 0, i);            maxHeap(array, i, 0);            System.out.println("maxHeap " + Arrays.toString(array) + " i is "                    + i);        }    }    private static void buildMaxHeap(int[] array) {        if (array == null || array.length <= 1) {            return;        }        int half = array.length / 2 - 1;        // 根据二叉树性质,深度为k的二叉树至多有2的k次方-1个结点(k≥1)        // 所以如果最末尾节点为右节点,array.length为奇数,那么上一层父节点的编号应该为(array.length-1)/2=array.length/2        // 所以如果最末尾节点为左节点,array.length为偶数,那么上一层父节点的编号也为array.length/2        // 由于数组下标从0开始,所以应该要在堆对应的编号基础上-1        // 从下往上把比较中最大的值往顶上冒,冒过后要把被换下来的值对应的子树再做一遍堆调整。        for (int i = half; i >= 0; i--) {            maxHeap(array, array.length, i);        }    }    private static void maxHeap(int[] array, int heapSize, int index) {        // 堆编号x ,数组编号index ,a=index+1;        // 所以左节点数组编号=2a-1=index * 2 + 1        // 右节点数组编号=2a+1-1=index * 2 + 2        int left = index * 2 + 1;        int right = index * 2 + 2;        int largest = index;        if (left < heapSize && array[left] > array[index]) {            largest = left;        }        if (right < heapSize && array[right] > array[largest]) {            largest = right;        }        if (index != largest) {            exchangeElements(array, index, largest);// 将子节点更大的值换到父节点            System.out.println("maxHeap " + Arrays.toString(array)                    + " index is " + index + " left is " + left + " right is "                    + right + " largest is " + largest + " heapSize is "                    + heapSize);            maxHeap(array, heapSize, largest);// 原有父节点的值放到了子节点后可能不满足堆的性质,需要调整修改后largest节点对应的子树        }    }    private static void exchangeElements(int[] array, int index1, int index2) {        int temp = array[index1];        array[index1] = array[index2];        array[index2] = temp;    }

 

 

实现2

while循环,同样父子节点交换后记录被换过的子节点位置,使用while (2 * k + 1 <= lastIndex)循环判断对应的子树是否符合堆性质并调整

public static void heapSort2(int[] array) {        for (int i = 0; i < array.length; i++) {            maxHeap2(array, array.length - 1 - i);            exchangeElements(array, 0, array.length - 1 - i);            System.out.println(Arrays.toString(array));        }    }    private static void exchangeElements(int[] array, int index1, int index2) {        int temp = array[index1];        array[index1] = array[index2];        array[index2] = temp;    }    private static void maxHeap2(int[] data, int lastIndex) {        //lastIndex= array.length - 1        //所以(lastIndex+1)/2-1等于上层最后一个有子节点的节点在数组中的索引        //(lastIndex+1)/2-1=(lastIndex-1)/2        for (int i = (lastIndex - 1) / 2; i >= 0; i--) {            // 保存当前正在判断的节点            int k = i;                                            // 若当前节点的左节点存在            while (2 * k + 1 <= lastIndex) {
// // biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点 int biggerIndex = 2 * k + 1; if (biggerIndex < lastIndex) { // 若右子节点存在,比较左右子节点大小,右节点不存在biggerIndex为左节点 if (data[biggerIndex] < data[biggerIndex + 1]) { // 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值 biggerIndex++; } } if (data[k] < data[biggerIndex]) { // 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k exchangeElements(data, k, biggerIndex); k = biggerIndex; //k记录了原来的父节点被换到了什么位置,原来的父节点下来后不一定比子节点更大 //while循环继续去判断它对应的子树符不符合堆的性质并调整 System.out.println("k is "+k+" "+Arrays.toString(data)); } else { //父节点已经比子节点大了,不需要调整 break; } //System.out.println(); } } }

 

 

 

 

 

 

 

参考资料

转载于:https://www.cnblogs.com/dongxiao-yang/p/6270699.html

你可能感兴趣的文章
Kafka序列化和反序列化与示例
查看>>
win10下VS2010中文输入法切换为英文卡死
查看>>
retinex相关代码汇总
查看>>
Cortex-M3 异常返回值EXC_RETURN
查看>>
kettle 转换字段遇到问题(couldn't get row from result set)——摘
查看>>
nginx首页根据IP跳转
查看>>
【2019-08-20】有点目标,有点计划,有点目的
查看>>
【2019-09-10】美,真的跟年龄无关
查看>>
【2019-09-28】少,但更好
查看>>
【2019-09-13】耐心观察是一种技能
查看>>
mysql数据库2-常用命令
查看>>
安卓开发环境搭建(转)
查看>>
Harris角点检测
查看>>
Struts2的处理流程及为Action的属性注入值
查看>>
设计中最常用的CSS选择器
查看>>
Maven项目打包成可执行Jar文件
查看>>
nginx http proxy 正向代理
查看>>
对BFC的总结
查看>>
23醒
查看>>
win7每天出现taskeng.exe进程的解决方案
查看>>