当前位置: 首页 > news >正文

【经典排序算法】堆排序(精简版)

什么是堆排序:

堆排序(Heapsort)是指利用堆(完全二叉树)这种数据结构所设计的一种排序算法,它是选择排序的一种。需要注意的是排升序要建大堆,排降序建小堆。
堆排序排序的特性总结:
1. 堆排序使用堆来选数,效率就高了很多。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(1)
4. 稳定性:不稳定
在开始堆排序之前有两个重要的概念:
大堆:父节点>=子节点的堆。
小堆:父节点<=子节点的堆。
堆是什么:堆是完全二叉树。
在逻辑结构方面我们可以将一个数组想象成一个堆。
在物理结构方面看堆其实是一个数组。
如下:
9e7a542e352d48298130264c153196ef.png

 

在我看来,堆排序中最重要的是向上调整和向下调整算法。

堆排序是基于这两个算法来进行的。

向上调整算法:

目的:
 当向堆中插入新元素时,为了维护堆的性质,需要对该元素进行向上调整。向上调整法就是从新插入的节点开始,通过与其父节点的比较和交换,确保该节点的值不大于(对于大根堆)或不小于(对于小根堆)其父节点的值。

//以大堆为例
void Adjustup(int* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] > a[parent])swap(a[child], a[parent]);elsebreak;child = parent;parent = (child - 1) / 2;}
}

向下调整算法:

目的:
 当向堆中插入新元素时,为了维护堆的性质,需要对该元素进行向上调整。向上调整法就是从新插入的节点开始,通过与其父节点的比较和交换,确保该节点的值不大于(对于大根堆)或不小于(对于小根堆)其父节点的值。

//向下调整算法
//大堆为例
void Adjustdown(int* a, int parent, int n)//n是数组a的元素个数
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] < a[child + 1]){++child;}if (a[child] > a[parent]){swap(a[child], a[parent]);}elsebreak;parent = child;child = parent * 2 + 1;}
}

需要注意的是对堆进行向上向下调整算法是要确保堆左子树和右子树是大堆/小堆。

下面我们来实现一下堆排序的完整代码:

void swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
//以大堆为例
void Adjustup(int* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] > a[parent])swap(a[child], a[parent]);elsebreak;child = parent;parent = (child - 1) / 2;}
}
//向下调整算法
//大堆为例
void Adjustdown(int* a, int parent, int n)//n是数组a的元素个数
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && a[child] < a[child + 1]){++child;}if (a[child] > a[parent]){swap(a[child], a[parent]);}elsebreak;parent = child;child = parent * 2 + 1;}
}
void HeapSort(int* a, int n)
{//首先利用向上调整算法建一个大堆(即父节点>=子节点的完全二叉树二叉树)for (int i = 1;i < n;i++){Adjustup(a, i);}int end = n - 1;while (end > 0){swap(a[0], a[end]);Adjustdown(a, 0, end);--end;}
}

上述堆排序代码是针对数组升序编写的,这里就不写降序的代码了,降序的堆排序和升序的如出一辙。

试验结果如下:

#include <iostream>
using namespace std;
int main()
{int arr[] = { 77,99,2,1,2,8,6,7,0 };HeapSort(arr, sizeof(arr) / sizeof(arr[0]));for (auto e : arr){cout << e << " ";}cout << endl;return 0;
}

bd2d14aa4ef64e6ca2c65a66eea7acd9.png

 

 

相关文章:

  • 如何配置云WAF以实现更有效的流量分发
  • MK SD NAND(贴片式SD卡)在电力AI模块中的应用案例
  • 人工智能对我们的生活影响有多大?
  • IDE集成开发环境
  • Apache POI对Excel进行读写操作
  • 【Python Cookbook】S1E08 在两个字典中寻找相同点
  • springboot kafka 提高拉取数量
  • Kamailio dialog timeout
  • 【设计模式】创建型-建造者模式
  • oracle mysql索引区别
  • 微信小程序-页面导航
  • 流量回放平台与传统测试工具的对比分析
  • MySQL复合查询操作【 函数接口集合 | 多表查询 | 子查询 | 表的内连外连】
  • 在Github找自己想要的的项目
  • 基于VGG16使用图像特征进行迁移学习的时装推荐系统
  • 【剑指offer】让抽象问题具体化
  • ES学习笔记(12)--Symbol
  • gitlab-ci配置详解(一)
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • js操作时间(持续更新)
  • js面向对象
  • mongodb--安装和初步使用教程
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • Odoo domain写法及运用
  • PAT A1050
  • session共享问题解决方案
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • Vue官网教程学习过程中值得记录的一些事情
  • 百度小程序遇到的问题
  • 分布式任务队列Celery
  • 基于OpenResty的Lua Web框架lor0.0.2预览版发布
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 聊聊directory traversal attack
  • 爬虫模拟登陆 SegmentFault
  • 区块链技术特点之去中心化特性
  • 探索 JS 中的模块化
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 小程序 setData 学问多
  •  一套莫尔斯电报听写、翻译系统
  • 用element的upload组件实现多图片上传和压缩
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • raise 与 raise ... from 的区别
  • ​第20课 在Android Native开发中加入新的C++类
  • # 透过事物看本质的能力怎么培养?
  • #1014 : Trie树
  • #14vue3生成表单并跳转到外部地址的方式
  • (13)Hive调优——动态分区导致的小文件问题
  • (MATLAB)第五章-矩阵运算
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (Windows环境)FFMPEG编译,包含编译x264以及x265
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (实战篇)如何缓存数据
  • (数据结构)顺序表的定义
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子