堆排序详解
来源:互联网 发布:矩阵如何计算 编辑:程序博客网 时间:2024/06/05 18:33
基础排序之选择排序
对于数组s = [2, 1, 3, 0, 4, 5, 8, 7, 6]进行升序排序
基本思路是: 双重for循环,每次选择最大的和最后一位数进行位置互换
for(int i = len(s) - 1; i >= 0; --i) { int k = i; for(int j = i - 1; j >= 0; --j) { if(s[k] < s[j]) k = j; } swap(s[k], s[i])}
上面大概就是选择排序的核心代码了,复杂度为O(n^2)
选择排序之树形表示法
同样用选择排序的思想进行选择最大的数并和最后一位数进行位置互换
但是和普通选择排序的区别在于:
扫描数组进行比较时不以线性扫描,而是以树形方式扫描
具体如下:
- s[7], s[8],
s[3]
比较选出最大的作为s[k]- s[3], s[4],
s[1]
, s[k]比较选出最大的作为s[k]- s[5], s[6],
s[2]
, s[k]比较选出最大的作为s[k]- s[1], s[2],
s[0]
, s[k]比较选出最大的作为s[k]- s[k]和最后一位数进行位置互换
以树形方式扫描整个数组关键在于扫描到所有非叶子节点i
,则该节点的两个子节点为2 * i +1
, 2 * i + 2
, 可是扫描所有非叶子节点的复杂度为O(n)
for(int i = len(s) - 1; i >= 0; --i) { k = i; for(int j = i / 2; j >= 0; --j) { // i/2表示最后一个非叶子节点 if(j * 2 +1 > i) continue; // 表示叶子节点,则继续寻找非叶子节点 if(s[k] < s[j * 2 + 1]) k = j * 2 + 1; if(j * 2 + 2 <= i && s[k] < s[j * 2 + 2]) k = j * 2 + 2; } swap(s[k], s[i])}
上述就是以树形方式进行选择排序,可是每次查询最大值时都要扫描整颗树,和普通选择排序并没有什么区别。
然而如果能在扫描树的时候把
i
,i * 2 + 1
,i * 2 + 2
的最大值保存在i节点上,则进行下一次查询的时候查询以i为根节点的树的最大值的时候就是s[i], 然后将s[i]和最后一位数进行替换,然后去更新s[i]
,s[i * 2 + 1]
,s[i * 2 + 2]
保证s[i]为以i为根结点的最大值,s[i * 2 + 1]
为以i * 2 + 1为根节点的最大值…
选择排序变形之堆排序
具体如下:
初始化树,保证每个节点是以该节点为根的树的最大值
- s[7], s[8], s[3]比较选出最大的和s[3]互换, 去更新和s[3]互换的子树
- s[3], s[4], s[1]比较选出最大的和s[1]互换,去更新和s[1]互换的子树
- s[5], s[6], s[2]比较选出最大的和s[2]互换,去更新和s[2]互换的子树
- s[1], s[2], s[0]比较选出最大的和s[0]互换,去更新和s[0]互换的子树
将s[0]和最后一位树进行互换,并更新以s[0]为根的树
代码如下
#include <iostream>#include <cstdio>#include <cstdlib>#include <string>#include <queue>#include <algorithm>#include <map>#include <iomanip>#define INF 999999999using namespace std;const int MAX = 10000;int len, arr[MAX];void heapAdjust (int *arr, int st, int end) { int tmp; while(st * 2 + 1 <= end) { // 更新最大堆,进行升序排序, 本次循环最坏情况log(end-st)次 tmp = st; if(arr[tmp] < arr[st * 2 + 1]) { tmp = st * 2 + 1; } if(st * 2 + 2 <= end && arr[tmp] < arr[st * 2 + 2]) { tmp = st * 2 + 2; } if(st == tmp) { // 不需要交换节点,则无需更新该节点下的子堆 break; } arr[st] = arr[st] ^ arr[tmp]; arr[tmp] = arr[st] ^ arr[tmp]; arr[st] = arr[st] ^ arr[tmp]; st = tmp; }}void output(int *arr, int len) { cout << "--------------------"; for(int i = 0; i < len; ++i) { cout << arr[i] << ' '; } cout << "------------------\n";}void heapSort(int *arr, int len) { // 复杂度nlog(n) for(int i = len / 2 - 1; i >= 0; --i) { // 建立堆,从最后一个非叶子节点开始建立, (2 * k + 1)或者(2 * k + 2) = n => 最后一个非叶子节点k = n/ 2 - 1 heapAdjust(arr, i, len - 1); } for(int i = len - 1; i > 0; --i) { // 筛选和更新堆, 本次循环n次 heapAdjust(arr, 0, i); arr[0] = arr[0] ^ arr[i]; arr[i] = arr[0] ^ arr[i]; arr[0] = arr[0] ^ arr[i]; // output(arr, len); }}int main() { cin >> len; for(int i = 0; i < len; ++i) { cin >> arr[i]; } heapSort(arr, len); for(int i = 0; i < len; ++i) { cout << arr[i] << ' '; } return 0;}
0 0
- 排序详解:堆排序
- 排序详解:堆排序
- [转]堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序算法详解
- 堆排序算法详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序详解
- 堆排序图片详解
- 堆排序详解
- 堆排序算法详解
- 堆排序详解
- h5新标签
- rw_我的阿勒泰5
- Sublime text3搭建Java开发编译运行环境
- Java游戏服务器成长之路——感悟篇
- woods of Vietnam
- 堆排序详解
- Android Studio导入Github项目时Plugin错误的解决办法
- android 中利用AChartEngine动态更新折线实现
- Linux那点事
- 基础题1
- 期中考试-B
- 正则表达式30分钟入门教程
- 菜鸟初学c++,一些零散小知识点
- 多个客户机之间配置ssh免秘钥登录