堆排序学习

353 阅读2分钟

堆排序(Heapsort)

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法:

  1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;

大顶堆.png

  1. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列;

小顶堆.png

算法描述
  1. 创建一个堆 H[0……n-1];
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
  4. 重复步骤 2,直到堆的尺寸为 1。
例子
数组: 4 6 8 5 9
第一次: 4 6 8 5 9 ===>>> 4 9 8 5 6
第二次: 4 9 8 5 6 ===>>> 9 4 8 5 6
第三次: 9 4 8 5 6 ===>>> 9 6 8 5 4
第四次: 9 6 8 5 4 ===>>> 4 6 8 5 9
第五次: 4 6 8 5 9 ===>>> 8 6 4 5 9
第六次: 8 6 4 5 9 ===>>> 5 6 4 8 9
第七次: 5 6 4 8 9 ===>>> 6 5 4 8 9
第八次: 6 5 4 8 9 ===>>> 4 5 6 8 9
最终 4 5 6 8 9
结束

运行图示.png

算法复杂度

空间复杂度: O(1)

时间复杂度:

O(n2)最坏结果O(n²) 最坏结果
O(nlog2n)平均结果O(nlog_2n) 平均结果
O(nlog2n)最好结果O(nlog_2n) 最好结果

排序不稳定,原来相等的两个参数排在前面的可能排在后面。

代码实现
public static void sort(int[] sourceArray) throws Exception {
  // 对 arr 进行拷贝,不改变参数内容
  int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
  int len = arr.length;
  buildMaxHeap(arr, len);
  for (int i = len - 1; i > 0; i--) {
    swap(arr, 0, i);
    len--;
    heapify(arr, 0, len);
  }
}

private static void buildMaxHeap(int[] arr, int len) {
  for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
    heapify(arr, i, len);
  }
}

private static void heapify(int[] arr, int i, int len) {
  int left = 2 * i + 1;
  int right = 2 * i + 2;
  int largest = i;
  if (left < len && arr[left] > arr[largest]) {
    largest = left;
  }
  if (right < len && arr[right] > arr[largest]) {
    largest = right;
  }
  if (largest != i) {
    swap(arr, i, largest);
    heapify(arr, largest, len);
  }
}

private static void swap(int[] arr, int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
  System.out.println(Arrays.toString(arr));
}

运行结果

输入数组:int[] arr = {4,6,8,5,9};
[4, 9, 8, 5, 6]
[9, 4, 8, 5, 6]
[9, 6, 8, 5, 4]
[4, 6, 8, 5, 9]
[8, 6, 4, 5, 9]
[5, 6, 4, 8, 9]
[6, 5, 4, 8, 9]
[4, 5, 6, 8, 9]
[5, 4, 6, 8, 9]
[4, 5, 6, 8, 9]

但是按照上面的步骤,这时候我们可以看到和演算结果一致,最后多了一轮,自己演示的时候会在结果正确的时候停止。