3

漫画:什么是堆排序?

 3 years ago
source link: https://www.cxyxiaowu.com/5393.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
漫画:什么是堆排序?-吴师兄学编程
当前位置:吴师兄学编程 > 算法 > 漫画算法 > 漫画:什么是堆排序?

点击上方“程序员小灰”,选择关注公众号

有趣有内涵的文章第一时间送达!

在上一篇五分钟学算法漫画中,小灰介绍了 二叉堆 这样一种强大的数据结构:

五分钟学算法漫画:什么是二叉堆?(修正版)

那么,这个二叉堆怎样来使用呢?我们这一期将会详细讲述。

五分钟学算法漫画:什么是堆排序?

五分钟学算法漫画:什么是堆排序?

让我们回顾一下二叉堆和最大堆的特性:

1.二叉堆本质上是一种完全二叉树

2.最大堆的堆顶是整个堆中的最大元素

当我们删除一个最大堆的堆顶(并不是完全删除,而是替换到最后面),经过自我调节,第二大的元素就会被交换上来,成为最大堆的新堆顶。

五分钟学算法漫画:什么是堆排序?

正如上图所示,当我们删除值为10的堆顶节点,经过调节,值为9的新节点就会顶替上来;当我们删除值为9的堆顶节点,经过调节,值为8的新节点就会顶替上来…….

由于二叉堆的这个特性,我们每一次删除旧堆顶,调整后的新堆顶都是大小仅次于旧堆顶的节点。那么我们只要反复删除堆顶,反复调节二叉堆,所得到的集合就成为了一个有序集合,过程如下:

删除节点9,节点8成为新堆顶:

五分钟学算法漫画:什么是堆排序?

删除节点8,节点7成为新堆顶:

五分钟学算法漫画:什么是堆排序?

删除节点7,节点6成为新堆顶:

五分钟学算法漫画:什么是堆排序?

删除节点6,节点5成为新堆顶:

五分钟学算法漫画:什么是堆排序?

删除节点5,节点4成为新堆顶:

五分钟学算法漫画:什么是堆排序?

删除节点4,节点3成为新堆顶:

五分钟学算法漫画:什么是堆排序?

删除节点3,节点2成为新堆顶:

五分钟学算法漫画:什么是堆排序?

到此为止,我们原本的最大堆已经变成了一个从小到大的有序集合。之前说过二叉堆实际存储在数组当中,数组中的元素排列如下:

五分钟学算法漫画:什么是堆排序?

由此,我们可以归纳出堆排序算法的步骤:

1. 把无序数组构建成二叉堆。

2. 循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。

五分钟学算法漫画:什么是堆排序?

五分钟学算法漫画:什么是堆排序?

public class HeapSort {

  1. /**

  2. * 下沉调整

  3. * @param array     待调整的堆

  4. * @param parentIndex    要下沉的父节点

  5. * @param parentIndex    堆的有效大小

  6. */

  7. public static void downAdjust(int[] array, int parentIndex, int length) {

  8.    // temp保存父节点值,用于最后的赋值

  9.    int temp = array[parentIndex];

  10.    int childIndex = 2 * parentIndex + 1;

  11.    while (childIndex < length) {

  12.        // 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子

  13.        if (childIndex + 1 < length && array[childIndex + 1] > array[childIndex]) {

  14.            childIndex++;

  15.        }

  16.        // 如果父节点小于任何一个孩子的值,直接跳出

  17.        if (temp >= array[childIndex])

  18.            break;

  19.        //无需真正交换,单向赋值即可

  20.        array[parentIndex] = array[childIndex];

  21.        parentIndex = childIndex;

  22.        childIndex = 2 * childIndex + 1;

  23.    }

  24.    array[parentIndex] = temp;

  25. }

  26. /**

  27. * 堆排序

  28. * @param array     待调整的堆

  29. */

  30. public static void heapSort(int[] array) {

  31.    // 1.把无序数组构建成二叉堆。

       for (int i = (array.length-2)/
    2; i >= 0; i--) {

  32.        downAdjust(array, i, array.length);

  33.    }

  34.    System.out.println(Arrays.toString(array));

  35.    // 2.循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。

  36.    for (int i = array.length - 1; i > 0; i--) {

  37.        // 最后一个元素和第一元素进行交换

  38.        int temp = array[i];

  39.        array[i] = array[0];

  40.        array[0] = temp;

  41.        // 下沉调整最大堆

  42.        downAdjust(array, 0, i);

  43.    }

  44. }

  45. public static void main(String[] args) {

  46.    int[] arr = new int[] {1,3,2,6,5,7,8,9,10,0};

  47.    heapSort(arr);

  48.    System.out.println(Arrays.toString(arr));

  49. }

五分钟学算法漫画:什么是堆排序?

五分钟学算法漫画:什么是堆排序?

二叉堆的节点下沉调整(downAdjust 方法)是堆排序算法的基础,这个调节操作本身的时间复杂度是多少呢?

假设二叉堆总共有n个元素,那么下沉调整的最坏时间复杂度就等同于二叉堆的高度,也就是O(logn)

我们再来回顾一下堆排序算法的步骤:

1. 把无序数组构建成二叉堆。

2. 循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。

第一步,把无序数组构建成二叉堆,需要进行n/2次循环。每次循环调用一次 downAdjust 方法,所以第一步的计算规模是  n/2 * logn,时间复杂度 O(nlogn)

第二步,需要进行n-1次循环。每次循环调用一次 downAdjust 方法,所以第二步的计算规模是 (n-1) * logn ,时间复杂度 O(nlogn)

两个步骤是并列关系,所以整体的时间复杂度同样是 O(nlogn)

五分钟学算法漫画:什么是堆排序?

五分钟学算法漫画:什么是堆排序?

五分钟学算法漫画:什么是堆排序?

五分钟学算法漫画:什么是堆排序?

五分钟学算法漫画:什么是堆排序?

—————END—————

喜欢本文的朋友们,欢迎长按下图关注订阅号程序员小灰,收看更多精彩内容

五分钟学算法漫画:什么是堆排序?

原文始发于微信公众号(程序员小灰):五分钟学算法漫画:什么是堆排序?


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK