了解堆排序,我们首先来了解树形选择排序
树形选择排序也称作锦标赛排序
基本思想就是:将待排序的n个数,两两进行比较,取出较小的,也就是 ⌊ n / 2 ⌋ \lfloor n/2\rfloor ⌊n/2⌋)个数。然后采用同样的方法,选择每两个数较小的数,直到选出最小的数。
这里采用属树形结构,选出来的最小的数就是根节点,在将其输出后,为了再次输出次小的数,将根节点所对应的叶子结点的关键字置为 ∞ \infty ∞,再进行上述的过程,直到将所有待排序的数进行输出。
- 图示如下:
在树形选择排序中,每选择一个关键字则需要进行 ⌊ log 2 n ⌋ \lfloor\log_2 n \rfloor ⌊log2n⌋次比较,其时间复杂度为 ( n log 2 n ) (n\log_2 n ) (nlog2n)。与简单的选择排序相比,降低了比较次数,但是却增加了n-1个额外的空间。为了解决这个问题,我们引入了堆排序。
堆排序:是树形选择排序的进一步改进。
我们先说明堆的概念:
设有n个元素的序列,
k
1
k_1
k1,
k
2
k_2
k2,
.
.
.
...
...,
k
n
k_n
kn,当且仅当满足下列条件,我们称之为堆 。
k
i
≤
{
k
2
∗
i
,
(
n
=1,2,3,...,
⌈
n
/
2
⌉
)
k
2
∗
i
+
1
,
(
k
=1,2,3,...,
⌈
n
/
2
⌉
)
k_i\leq \begin{cases} k_2*_i, & \text {( $n$ =1,2,3,...,$\lceil n/2\rceil$)} \\ k_2*_i+1, & \text{( $k$ =1,2,3,...,$\lceil n/2\rceil$)} \end{cases}
ki≤{k2∗i,k2∗i+1,( n =1,2,3,...,⌈n/2⌉)( k =1,2,3,...,⌈n/2⌉)
我们画图示意:
如果某数列是堆,那么
k
1
k_1
k1是某数列最大值或者最小值,分别称为大顶堆或者小顶堆
堆排序的思想:利用堆进行排序的一个过程,我们就用大顶堆来说,现将数列转换成一个大顶堆,那么此时根节点就是最大的,输出根节点,然后将剩下的数重新调整为一个大顶堆,直到只剩一个结点结束
既然思想知道,那么实现这个算法,我们需要解决两个问题:
- 1、怎样才能将数列调整为堆的形式
- 2、输出一个根节点后,怎样调整剩下的结点将其重新置为堆的形式
第一个问题解决方法:建堆其实是一个筛选(从根节点到叶子结点的调整过程)的过程,先将
n
n
n个数转换成一个完全二叉树,最后一个结点就是
⌊
n
/
2
⌋
\lfloor n/2 \rfloor
⌊n/2⌋个结点的孩子结点,对这个结点的子树开始筛选,使得该子树为堆,之后依次向前进行筛选,直到根节点结束
图示:
第二个问题解决方法:在剩下的n-1个结点中,将最后一个元素的放在堆顶,此时堆的结构被破坏,那么原因就仅仅是根节点的缘故,将根节点与左右孩子中较小的进行交换,往下依次进行比较交换,直到叶子结点,此时堆就已然建成。