详细记录一下自己理解的过程,方便后续查看,结合例子理解了整个过程,程序实现按照思路写就可以了。
理论部分的根结点从1开始编号!!
1. 堆
堆是一棵完全二叉树
大根堆: 任何一个父节点的值不小于其左右孩子结点的值,即:
k e y [ i ] ≥ k e y [ 2 i ] & & k e y [ i ] ≥ k e y [ 2 i + 1 ] key[i] \geq key[2i] \quad \&\& \quad key[i] \geq key[2i+1] key[i]≥key[2i]&&key[i]≥key[2i+1]
堆顶元素记录的是最大的关键字。
小根堆: 任何一个父节点的值不大于其左右孩子结点的值,即:
k e y [ i ] ≤ k e y [ 2 i ] & & k e y [ i ] ≤ k e y [ 2 i + 1 ] key[i] \leq key[2i] \quad \&\& \quad key[i] \leq key[2i+1] key[i]≤key[2i]&&key[i]≤key[2i+1]
堆顶元素记录的是最小的关键字。
2. 堆排序
2.1 步骤
升序用大根堆,降序就用小根堆
在升序排序中,我们会将堆反复调整为大根堆,这样在将堆顶元素与其子树结点交换的过程中,才能将最大的关键字(堆顶元素)调整到后面,从而得到一个有序序列。
堆排序主要有以下两个步骤:
- 建初堆:从 ⌊ n / 2 ⌋ \lfloor n / 2\rfloor ⌊n/2⌋开始,依次将 ⌊ n / 2 ⌋ 、 ⌊ n / 2 ⌋ − 1 ⋯ , 1 \lfloor n / 2\rfloor 、\lfloor n / 2\rfloor-1 \cdots, 1 ⌊n/2⌋、⌊n/2⌋−1⋯,1作为根的子树都调整为堆
- 交换并调整,从 i = n i =n i=n开始
* 交换 r [ 1 ] \mathrm{r}[1] r[1] 和 r [ i ] \mathrm{r}[i] r[i], 则 r [ i ] \mathrm{r}[i] r[i] 为关键字最大( r [ 1 ] ⋯ r [ i ] \mathrm{r}[1] \cdots \mathrm{r}[i] r[1]⋯r[i]最大)的记录,将 r [ 1 ] ⋯ r [ i − 1 ] \mathrm{r}[1] \cdots \mathrm{r}[i-1] r[1]⋯r[i−1] 重新调整为堆,
* i = i − 1 i = i - 1 i=i−1,循环 n n n 次, 直到交换 r [ 1 ] \mathrm{r}[1] r[1] 和 r [ 2 ] \mathrm{r}[2] r[2] 为止,得到一个有序序列 r [ 1 ] ⋯ r [ n ] \mathrm{r}[1] \cdots \mathrm{r}[n] r[1]⋯r[n] 。
【建初堆】
要将一个无序序列调整为堆,就必须将其所对应的完全二叉树中以每一结点为根的子树都调整为堆。只有一个结点的树必是堆,而在完全二叉树中,所有序号大于 ⌊ n / 2 ⌋ \lfloor n / 2\rfloor ⌊n/2⌋ 的结点都是叶子结点,因此以这些结点为根的子树均已是堆。这样,只需利用筛选法,从最后一个分支结点 ⌊ n / 2 ⌋ \lfloor n / 2\rfloor ⌊n/2⌋开始,依次将序号为 ⌊ n / 2 ⌋ 、 ⌊ n / 2 ⌋ − 1 、 ⋯ 、 1 \lfloor n / 2\rfloor、\lfloor n / 2\rfloor - 1、\cdots、1 ⌊n/2⌋、⌊n/2⌋−1、⋯、1的结点作为根的子树都调整为堆即可。
【筛选法调整堆】大根堆
设需要调整以 r [ j ] \mathrm{r}[j] r[j]为根节点的子树
从 r [ 2 j ] \mathrm{r}[2 j] r[2j
堆排序详解

本文详细介绍了堆排序算法的基本概念,包括大根堆与小根堆的特点,以及如何通过堆排序实现数组的升序与降序排列。文章通过实例演示了堆排序的具体步骤,并提供了两种不同编号方式下的C++实现代码。
最低0.47元/天 解锁文章
169

被折叠的 条评论
为什么被折叠?



