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

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

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

实现1

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

  1. public static void heapSort(int[] array) {
  2. if (array == null || array.length <= 1) {
  3. return;
  4. }
  5.  
  6. buildMaxHeap(array);
  7.  
  8. System.out.println("buildMaxHeap " + Arrays.toString(array));
  9.  
  10. for (int i = array.length - 1; i >= 1; i--) {
  11. exchangeElements(array, 0, i);
  12.  
  13. maxHeap(array, i, 0);
  14.  
  15. System.out.println("maxHeap " + Arrays.toString(array) + " i is "
  16. + i);
  17. }
  18.  
  19. }
  20.  
  21. private static void buildMaxHeap(int[] array) {
  22. if (array == null || array.length <= 1) {
  23. return;
  24. }
  25.  
  26. int half = array.length / 2 - 1;
  27. // 根据二叉树性质,深度为k的二叉树至多有2的k次方-1个结点(k≥1)
  28. // 所以如果最末尾节点为右节点,array.length为奇数,那么上一层父节点的编号应该为(array.length-1)/2=array.length/2
  29. // 所以如果最末尾节点为左节点,array.length为偶数,那么上一层父节点的编号也为array.length/2
  30. // 由于数组下标从0开始,所以应该要在堆对应的编号基础上-1
  31.  
  32. // 从下往上把比较中最大的值往顶上冒,冒过后要把被换下来的值对应的子树再做一遍堆调整。
  33. for (int i = half; i >= 0; i--) {
  34. maxHeap(array, array.length, i);
  35. }
  36. }
  37.  
  38. private static void maxHeap(int[] array, int heapSize, int index) {
  39. // 堆编号x ,数组编号index ,a=index+1;
  40. // 所以左节点数组编号=2a-1=index * 2 + 1
  41. // 右节点数组编号=2a+1-1=index * 2 + 2
  42.  
  43. int left = index * 2 + 1;
  44. int right = index * 2 + 2;
  45.  
  46. int largest = index;
  47. if (left < heapSize && array[left] > array[index]) {
  48. largest = left;
  49. }
  50.  
  51. if (right < heapSize && array[right] > array[largest]) {
  52. largest = right;
  53. }
  54.  
  55. if (index != largest) {
  56. exchangeElements(array, index, largest);// 将子节点更大的值换到父节点
  57.  
  58. System.out.println("maxHeap " + Arrays.toString(array)
  59. + " index is " + index + " left is " + left + " right is "
  60. + right + " largest is " + largest + " heapSize is "
  61. + heapSize);
  62.  
  63. maxHeap(array, heapSize, largest);// 原有父节点的值放到了子节点后可能不满足堆的性质,需要调整修改后largest节点对应的子树
  64. }
  65. }
  66.  
  67. private static void exchangeElements(int[] array, int index1, int index2) {
  68. int temp = array[index1];
  69. array[index1] = array[index2];
  70. array[index2] = temp;
  71. }

实现2

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

  1. public static void heapSort2(int[] array) {
  2. for (int i = 0; i < array.length; i++) {
  3. maxHeap2(array, array.length - 1 - i);
  4. exchangeElements(array, 0, array.length - 1 - i);
  5. System.out.println(Arrays.toString(array));
  6. }
  7.  
  8. }
  9.  
  10. private static void exchangeElements(int[] array, int index1, int index2) {
  11. int temp = array[index1];
  12. array[index1] = array[index2];
  13. array[index2] = temp;
  14. }
  15.  
  16. private static void maxHeap2(int[] data, int lastIndex) {
  17.  
  18. //lastIndex= array.length - 1
  19. //所以(lastIndex+1)/2-1等于上层最后一个有子节点的节点在数组中的索引
  20. //(lastIndex+1)/2-1=(lastIndex-1)/2
  21. for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
  22. // 保存当前正在判断的节点
  23. int k = i;
  24.  
  25. // 若当前节点的左节点存在
  26. while (2 * k + 1 <= lastIndex) {//
  27.  
  28. // biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点
  29. int biggerIndex = 2 * k + 1;
  30. if (biggerIndex < lastIndex) {
  31. // 若右子节点存在,比较左右子节点大小,右节点不存在biggerIndex为左节点
  32. if (data[biggerIndex] < data[biggerIndex + 1]) {
  33. // 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值
  34. biggerIndex++;
  35. }
  36. }
  37. if (data[k] < data[biggerIndex]) {
  38. // 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k
  39. exchangeElements(data, k, biggerIndex);
  40. k = biggerIndex; //k记录了原来的父节点被换到了什么位置,原来的父节点下来后不一定比子节点更大
  41. //while循环继续去判断它对应的子树符不符合堆的性质并调整
  42. System.out.println("k is "+k+" "+Arrays.toString(data));
  43.  
  44. } else {
  45. //父节点已经比子节点大了,不需要调整
  46. break;
  47. }
  48.  
  49. //System.out.println();
  50. }
  51. }
  52.  
  53. }

参考资料

http://blog.csdn.net/apei830/article/details/6584645

http://blog.csdn.net/kimylrong/article/details/17150475

堆排序算法的java实现的更多相关文章

  1. 堆排序算法 java 实现

    堆排序算法 java 实现 白话经典算法系列之七 堆与堆排序 Java排序算法(三):堆排序 算法概念 堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特 ...

  2. 必须知道的八大种排序算法【java实现】(三) 归并排序算法、堆排序算法详解

    一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...

  3. 【java排序】 归并排序算法、堆排序算法

    一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...

  4. 常见排序算法(附java代码)

    常见排序算法与java实现 一.选择排序(SelectSort) 基本原理:对于给定的一组记录,经过第一轮比较后得到最小的记录,然后将该记录与第一个记录的位置进行交换:接着对不包括第一个记录以外的其他 ...

  5. 几大排序算法的Java实现

    很多的面试题都问到了排序算法,中间的算法和思想比较重要,这边我选择了5种常用排序算法并用Java进行了实现.自己写一个模板已防以后面试用到.大家可以看过算法之后,自己去实现一下. 1.冒泡排序:大数向 ...

  6. 常见的排序算法之Java代码解释

    一 简要介绍 一般排序均值的是将一个已经无序的序列数据重新排列成有序的 常见的排序分为: 1 插入类排序 主要就是对于一个已经有序的序列中,插入一个新的记录.它包括:直接插入排序,折半插入排序和希尔排 ...

  7. 基本排序算法的java实现

    本例子实现了一些常见的排序算法,注释中也有一些关于这些算法的思想的描述,这里不做多说,直接上代码. import java.awt.List; import java.util.ArrayList; ...

  8. 7种基本排序算法的Java实现

    7种基本排序算法的Java实现 转自我的Github 以下为7种基本排序算法的Java实现,以及复杂度和稳定性的相关信息. 以下为代码片段,完整的代码见Sort.java 插入排序 /** * 直接插 ...

  9. 常见排序算法总结 -- java实现

    常见排序算法总结 -- java实现 排序算法可以分为两大类: 非线性时间比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序. 线性时间 ...

随机推荐

  1. @Transactional注解事务不起作用

    @Transactional注解事务不起作用 问题:今天在项目中碰到一个事务问题,使用@Transactional注解事务,抛出异常不会滚. 解决一:https://blog.csdn.net/u01 ...

  2. FZU-2267 The Bigger the Better(字符串,模拟)

     Problem 2267 The Bigger the Better Accept: 132    Submit: 935Time Limit: 1500 mSec    Memory Limit ...

  3. eleasticsearch重要配置

    elasticsearch重要配置=====================================日志和数据目录-----------------path:    logs: /var/lo ...

  4. SQL注入漏洞原理

    系统中安全性是非常重要的,为了保证安全性很多解决方案被应用到系统中,比如架设防火墙防止数据库服务器直接暴露给外部访问者.使用数据库的授权机制防止未授权的用户访问数据库,这些解决方案可以很大程度上避免了 ...

  5. 网络监控工具ntopng

    网络监控工具ntopng   ntopng是Kali提供的一个网络监控软件,用于显示当前网络的使用情况.它能列出当前使用网络的主机,并且显示每台主机发送和接受的数据包.同时,它提供强大的数据处理功能, ...

  6. MySQL 三节点企业版

    https://promotion.aliyun.com/ntms/act/rds/mysqlenterprise.html

  7. Android可伸缩列表ExpandableListView

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  8. 【spring data jpa】【mybatis】通过反射实现 更新/保存 实体的任意字段的操作

    代码如下: //代码示例:例如保存时,传入下面两个字段 String filed;String content; //User代表要更新的实体,user即本对象 //filed代表要更改的字段,例如u ...

  9. 如何开启Linux双网卡的转发功能

    原文地址:http://blog.csdn.net/lllzd/article/details/8587624 说明:在<把arm开发板做成USB网卡(RNDIS /Ethernet Gadge ...

  10. 本地缓存localstorage使用

    最近做项目遇到一个问题,即从“个人中心”点击进入“修改支付宝”,需要自动获取用户手机号怎么做? 修改支付宝的api不提供用户手机号数据,但是发现个人中心提供,于是想通过localstorage在个人中 ...