详解堆排序「优先队列」

215. 数组中的第K个最大元素

 

排序算法千千万,今天来讲堆排序!!

关于「详解快排及其应用」,可见 详解快排及其应用

关于「详解归并排序及其应用」,可见 详解归并排序及其应用

算法思想

「快排」和「归并」都是一次性将所有元素排好顺序,但有一些场景,我们每次可能只需要获得最小值即可

「堆排序」就是这样的特点,并非一次性全部排好序,而只有堆顶元素是最小值,每次需要获取最小值时,只需要去堆顶取即可

借鉴 Java 中的优先队列,我们的堆只实现几个核心的 API

定义:当一棵二叉树的每个结点都大于等于它的两个子结点时,它被称为堆有序

根据定义可知,根结点是堆有序的二叉树中的最大结点

定义:二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级储存 (不使用数组的第一个位置)

根据定义可知,在一个堆中,位置 k 的结点的父结点的位置为 k2,而它的两个子结点的位置则分别为 2k2k+1

我们用长度为N + 1的私有数组pq[]来表示一个大小为N的堆,我们不会使用pq[0],堆元素放在pq[1]pq[N]

注意:二叉堆可以分为大根堆和小根堆,其中大根堆就是上面定义中介绍的,而小根堆是每个节点都小于等于它的两个子节点,即:根结点是最小结点。本篇文章基于「小根堆」来实现!!!

插入元素

每次插入一个新的元素时,首先将该元素放在数组的最后一个空位置,然后执行由下至上的堆有序化操作,即「上浮」

假设一个有序堆,如下图所示:

2

此时,插入一个新的元素4,如下图所示:

3

然后执行由下至上的堆有序化操作,如下图所示:

13

由下至上的堆有序化 (上浮) 实现代码如下:

删除元素

每次删除堆顶元素时,首先将该元素与最后一个元素交换,然后将最后一个元素删除,最后执行由上至下的堆有序化操作,即「下沉」

在上面插入元素后的基础上删除堆顶元素,下图所示:

12

然后执行由上至下的堆有序化操作,如下图所示:

14

由上至下的堆有序化 (下沉) 实现代码如下:

算法模版

核心的两个操作介绍完了,下面给出完整的代码模版:(小根堆)