图解堆排序(一次弄懂堆结构以及堆排序)

简介: 图解堆排序(一次弄懂堆结构以及堆排序)

前言:

我们知道研究一个数据结构自然要研究它的逻辑结构物理结构,其中逻辑结构是我们真正关注的,因为一个数据结构是否优秀,它的各类操作的核心思想都是由逻辑结构决定的,而物理结构仅仅是去适应逻辑结构。而堆排序用到了堆这个数据结构,所以我们就先来研究一下堆的这两个结构。

堆的逻辑结构:

1、树结构的一种变形,是完全二叉树。树结构同样也是逻辑结构下的一种数据结构

2、满足“每个节点都大于等于其父节点(根节点除外)”的堆称为最小堆

3、满足“每个节点都小于等于其父节点(根节点除外)”的堆称为最大堆

具体图见下:

左边为大根堆,右边为小根堆

堆的物理结构:

物理结构探究的就是如何把这个逻辑结构在真实的计算机内存空间中存储下来。这个存储必须要能体现逻辑结构所有的一切逻辑特征。

常见的物理结构就是链表(随机存储)、数组(顺序存储)。对于堆和树,我们采取的物理结构往往是数组存储。然后通过下标去体现树的逻辑结构。

例如上面的小根堆和大根堆的对应的数组存储方式如下:

总的来说就是利用树的层次遍历的顺序一一把结点放到数组当中 。

堆排序用到树的一些性质(树堆相同):

1、令x为根节点下标,则x*2为其左子树下标,x*2+1为其右子树下标

2、最后一排叶子节点的个数为总节点数的一半

3、存储从数组下标1开始,若是0开始上面两条性质会改变。

堆结构基础操作方法:

1、heap数组就是存储树结构各节点的数组

2、size就是整个数组的长度,也是堆的节点数

3、当一个堆因加入、修改、删除等操作出现一个节点发生改变,小于原本的节点时,整体堆可能不再满足其堆的性质,这个时候就要通过down操作,把该节点通过逐级下沉(若是小根堆则要逐级上浮,用up函数),放到其应该在的位置,使整体结构仍满足堆的性质。

所以在堆的问题中最难的地方在于down和up两个操作

down操作:

down顾名思义就是把一个元素下沉到它应该在的地方。对应环境:小根堆中,一个元素值变大了,就要考虑下沉。或者大根堆中,一个元素值变小了,就要考虑下沉。

具体的步骤如下:(小根堆为例子)

1、定义一个变量t表示待调整数x应该在的位置,开始时赋值为x的初始位置,即t=x。

2、先将x与其左子树比较大小(即num[t] 比较 num[x/2]),如果比左子树要大,则将t赋值为左子树的位置(即t=x/2)。表示目前x应该在左子树这个地方。

3、再将t的值与右子树比较(即num[t] 比较 num[x/2+1]),如果目前t位置(x目前应该在的位置)的值大于右子树的值,那么说明x有更优的解,故将t=x/2+1。

(2,3步骤的本质就是找到x左右子树中较小的那一个,因为x就是要和较小值交换)

4、最后如果t和x不相等,则交换两者的位置。

图解如下:(小根堆为例子)

说明:1、图中27先于15、19中较小的15交换,完成第一轮下沉

2、再与18、28中的18交换,完成第二轮下沉。

3、之后,再不停重复这两个操作。直到27比下面两者都小或到达叶子结点为止。

up操作

up操作顾名思义就是把一个元素不停上浮到它应该在的地方。对应环境是:小根堆中,一个根节点元素值比原本要小了,就要考虑是否需要上浮。或者大根堆中,一个根节点变大了,就要考虑上浮

具体步骤如下:(选取小根堆为例子,大根堆的话要相反)

1、与根节点比较,如果小于根节点,则上浮。

2、再与下一层根节点比较,如果仍然小于则继续上浮

3、直到到达最上方,或不再小于根节点为止

图解如下:(大根堆为例子,让大家两种情况都看看)

堆排序:

了解完堆的基本操作就让我们来看看,这个利用堆结构特点来操作的排序算法。

对于小根堆:

1、将元素随意放到一个堆中,再对堆进行初始化,使其从杂乱状态变为小根堆

2、取出其顶部元素,自然就是整个堆中的最小值。

3、然后再把最尾部的元素上移到根节点,这个尾部元素自然很大,所以在对这个元素执行down操作,从而使堆重新变为小根堆的结构。

4、不停重复1 2操作直到全部取出元素。自然形成由小到大的序列

对于大根堆:

1、将元素随意放到一个堆中,再对堆进行初始化,使其从杂乱状态变为大根堆

2、取出其顶部元素,自然就是整个堆中的最大值。

3、然后再把最尾部的元素上移到根节点,这个尾部元素自然很小,所以在对这个元素执行down操作,从而使堆重新变为大根堆的结构。

4、不停重复1 2操作直到全部取出元素。自然形成由大到小的序列

注意:堆排序算法并没有用到up操作

图解堆排序:

上图就体现了从取出元素到调整新的有序堆的全过程 ,大家好好琢磨肯定能明白的!

画图不易,大家给个免费的赞呗。如果觉得写的不错,也可以按下可爱的五角星收藏

堆排序完整代码如下:

#include<iostream>
using namespace std;
const int n=100001;
void down(int x,int a[],int num){
    int k=x;
    if(x*2<=num&&a[x*2]<a[k])k=x*2;
    if(x*2+1<=num&&a[x*2+1]<a[k])k=x*2+1;//首先判断是否存在左右子树再进行判断,否则会造成非法空间访问
    //交换并进入下一层递归
    if(a[k]<a[x]){ 
        swap(a[k],a[x]);//交换值
        down(k,a,num);//下次从a[x]所在的新的位置继续向下down
    }//如果a【x】的值此时已经小于左右子树中的最小值,那么直接放置并且退出循环即可
    
}
int main(){
    int num,k;//num表示总共有多少待排序的数,k表示要输出前k个数
    int a[n];
    cin>>num>>k;
    for(int i=1;i<=num;i++){//从1开始,为了方便下标计算
        cin>>a[i];
    }
    //初始化小根堆。从小到大就是小根堆,反之就是大根堆.时间复杂度为O(n)
    for(int i=num/2;i>0;i--){
        down(i,a,num);
    }
    //初始化后开始堆排序
    for(int i=1;i<=k;i++){
        cout<<a[1]<<" ";//这里第一次错了,debug40分钟
        a[1]=a[num--];
        down(1,a,num);
    }
    return 0;
}
相关文章
|
监控 API UED
Elasticsearch 异步搜索 Async search 实战
1、Elasticsearch 异步搜索定义 异步搜索 API 可异步执行搜索请求、监控其进度并检索可用的部分结果。 如下的官方介绍动画,能更加生动的介绍清楚异步检索。 传统检索 VS 异步检索,在数据量比较大时: 传统检索可能导致超时,以至于无数据返回;或者需要等待很久,用户体验差。 异步检索,可以快速响应数据,用户无需等待。
Elasticsearch 异步搜索 Async search 实战
|
存储 搜索推荐
【七大排序】堆排序详解
【七大排序】堆排序详解
579 3
|
9月前
|
监控 Ubuntu Linux
Windows11 WSL2 Ubuntu编译安装perf工具
通过以上步骤,你已经在Windows 11的WSL2中成功编译并安装了 `perf`工具。尽管在WSL2中可能会遇到一些限制,但大部分基本性能分析功能应当可以正常使用。使用 `perf`进行性能分析,可以帮助你更好地理解和优化系统及应用程序的性能。
658 14
|
存储 关系型数据库 Java
红黑树,B+树,B树的原理
红黑树(Red-Black Tree)、B树(B-Tree)和 B+树(B+ Tree)都是自平衡的树结构,用于高效地进行查找、插入和删除操作。它们在数据库和文件系统等应用中有广泛的应用。
557 2
|
10月前
|
JavaScript 前端开发 Docker
如何通过pm2以cluster模式多进程部署next.js(包括docker下的部署)
通过这些步骤,可以确保您的Next.js应用在多核服务器上高效运行,并且在Docker环境中实现高效的容器化管理。
991 44
|
存储 机器学习/深度学习 人工智能
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
|
存储 Java 程序员
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
本文详细讲解了Spring框架中IOC容器如何存储和取出Bean对象,包括五大类注解(@Controller、@Service、@Repository、@Component、@Configuration)和方法注解@Bean的用法,以及DI(依赖注入)的三种注入方式:属性注入、构造方法注入和Setter注入,并分析了它们的优缺点。
211 0
SpringIOC和DI的代码实现,Spring如何存取对象?@Controller、@Service、@Repository、@Component、@Configuration、@Bean DI详解
【数据结构】大根堆和小根堆
【数据结构】大根堆和小根堆
580 0
|
机器学习/深度学习 存储 算法
深度学习之大规模模型训练
基于深度学习的大规模模型训练涉及训练具有数百万甚至数十亿参数的深度神经网络,以处理复杂的任务,如自然语言处理、计算机视觉和语音识别。
428 2

热门文章

最新文章