java语言堆排序(Heap Sort)详解

╰半夏微凉° 2022-10-17 00:39 163阅读 0赞

首先阐述一下其基本思想:

①、基本思想:堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

②、算法描述:

将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
③、动图演示:
93824bbcbb3c16dbfd58a0e64d2c7c3c.png

④、完整的测试代码演示:

  1. import java.util.Arrays;
  2. import java.util.Comparator;
  3. import java.util.PriorityQueue;
  4. /**
  5. * @author wanghuainan
  6. * @date 2021/5/28 16:13
  7. */
  8. public class NandaoHeapSort {
  9. //自定义比较器
  10. public static class Naodaocomparator implements Comparator<Integer>{
  11. @Override
  12. public int compare(Integer o1, Integer o2) {
  13. return o2 - o1;
  14. }
  15. }
  16. public static void main(String[] args) {
  17. //默认小根堆
  18. PriorityQueue<Integer> testHeap = new PriorityQueue<>(new Naodaocomparator());
  19. testHeap.add(6);
  20. testHeap.add(0);
  21. testHeap.add(3);
  22. testHeap.add(2);
  23. System.out.println("非删除弹出:"+testHeap.peek());
  24. testHeap.add(1);
  25. testHeap.add(8);
  26. System.out.println(testHeap.peek());
  27. while (!testHeap.isEmpty()) {
  28. System.out.println(testHeap.poll());
  29. }
  30. int testTime = 5;
  31. int maxSize = 20;
  32. int maxValue = 20;
  33. boolean successed = true;
  34. for(int i = 0;i < testTime; i++){
  35. int[] arr1 = generateRandomArray(maxSize,maxValue);
  36. int[] arr2 = copyArray(arr1);
  37. heapSort(arr1);
  38. comparator(arr2);
  39. if(!isEq(arr1,arr2)){
  40. successed = false;
  41. break;
  42. }
  43. }
  44. System.out.println(successed ? "Nice":"fail失败了");
  45. int[] arr = {6,1,3,2,4,5,9,6};
  46. printArray(arr);
  47. heapSort(arr);
  48. printArray(arr);
  49. }
  50. //打印数组
  51. private static void printArray(int[] arr) {
  52. if(arr == null){
  53. return;
  54. }
  55. for(int i = 0;i < arr.length;i++){
  56. System.out.print(arr[i] + " ");
  57. }
  58. System.out.println();
  59. }
  60. //比较两个数组是否相等
  61. private static boolean isEq(int[] arr1, int[] arr2) {
  62. if((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)){
  63. return false;
  64. }
  65. if(arr1 == null && arr2 == null){
  66. return true;
  67. }
  68. if(arr1.length != arr2.length){
  69. return false;
  70. }
  71. for(int i = 0;i < arr1.length;i++){
  72. if(arr1[i] != arr2[i]){
  73. return false;
  74. }
  75. }
  76. return true;
  77. }
  78. // 堆排序额外空间复杂度O(1)
  79. private static void heapSort(int[] arr1) {
  80. if(arr1 == null || arr1.length < 2){
  81. return;
  82. }
  83. // O(N*logN)
  84. for(int i = 0;i < arr1.length;i++){
  85. heapInsert(arr1,i);
  86. }
  87. // O(N)
  88. for(int i = arr1.length - 1;i >= 0;i--){
  89. heapify(arr1,i,arr1.length);
  90. }
  91. int heapSize = arr1.length;
  92. swap(arr1,0,--heapSize);
  93. // O(N*logN)
  94. while (heapSize > 0){
  95. heapify(arr1,0,heapSize);
  96. swap(arr1,0,--heapSize);
  97. }
  98. }
  99. //数值交换
  100. private static void swap(int[] arr1, int i, int j) {
  101. int temp = arr1[i];
  102. arr1[i] = arr1[j];
  103. arr1[j] = temp;
  104. }
  105. // arr[index]位置的数,能否往下沉
  106. private static void heapify(int[] arr1,int index, int heapSize) {
  107. int left = 2 * index + 1;// 左孩子的下标
  108. while (left < heapSize){// 下方还有孩子的时候
  109. /**
  110. * 两个孩子中,谁的值大,把下标给largest
  111. * 1)只有左孩子,left -> largest
  112. * 2) 同时有左孩子和右孩子,右孩子的值<= 左孩子的值,left -> largest
  113. * 3) 同时有左孩子和右孩子并且右孩子的值> 左孩子的值, right -> largest
  114. */
  115. int maxSize = left + 1 < heapSize && arr1[left]< arr1[left + 1] ? left + 1 : left;
  116. // 父和较大的孩子之间,谁的值大,把下标给largest
  117. maxSize = arr1[index] < arr1[maxSize] ? maxSize : index;
  118. if(maxSize == index){
  119. break;
  120. }
  121. swap(arr1,maxSize,index);
  122. index = maxSize;
  123. left = 2 * index + 1;
  124. }
  125. }
  126. // arr[index]刚来的数,往上浮
  127. private static void heapInsert(int[] arr1,int index) {
  128. while (arr1[index] > arr1[(index - 1) / 2]){
  129. swap(arr1,index,(index - 1) / 2);
  130. index = (index - 1) / 2;
  131. }
  132. }
  133. //JDK默认排序方法
  134. private static void comparator(int[] arr2) {
  135. Arrays.sort(arr2);
  136. }
  137. //数组复制
  138. private static int[] copyArray(int[] arr1) {
  139. if (arr1 == null ){
  140. return null;
  141. }
  142. int[] arr2 = new int[arr1.length];
  143. for(int i = 0;i < arr1.length;i++){
  144. arr2[i] = arr1[i];
  145. }
  146. return arr2;
  147. }
  148. //对数器生成数组
  149. private static int[] generateRandomArray(int maxSize, int maxValue) {
  150. int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
  151. for(int i = 0;i < arr.length;i++){
  152. arr[i] = (int)((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
  153. }
  154. return arr;
  155. }
  156. }

核心方法为:

  1. // 堆排序额外空间复杂度O(1)
  2. private static void heapSort(int[] arr1) {
  3. if(arr1 == null || arr1.length < 2){
  4. return;
  5. }
  6. // O(N*logN)
  7. for(int i = 0;i < arr1.length;i++){
  8. heapInsert(arr1,i);
  9. }
  10. // O(N)
  11. for(int i = arr1.length - 1;i >= 0;i--){
  12. heapify(arr1,i,arr1.length);
  13. }
  14. int heapSize = arr1.length;
  15. swap(arr1,0,--heapSize);
  16. // O(N*logN)
  17. while (heapSize > 0){
  18. heapify(arr1,0,heapSize);
  19. swap(arr1,0,--heapSize);
  20. }
  21. }

此示例详细分享了堆排序的原理,里面也有对数器的核心代码,均为通用性,实用性很高。

发表评论

表情:
评论列表 (有 0 条评论,163人围观)

还没有评论,来说两句吧...

相关阅读