【堆排序】-详细例子以及C++实现

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

详细记录一下自己理解的过程,方便后续查看,结合例子理解了整个过程,程序实现按照思路写就可以了。

理论部分的根结点从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/2n/21,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[i1] 重新调整为堆,
    * i = i − 1 i = i - 1 i=i1,循环 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/2n/211的结点作为根的子树都调整为堆即可。

筛选法调整堆大根堆
设需要调整以 r [ j ] \mathrm{r}[j] r[j]为根节点的子树
r [ 2 j ] \mathrm{r}[2 j] r[2j

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值