排序(5)---堆排序
2017-05-05 20:14
218 查看
堆排序
堆有序:二叉树的每个结点都大于等于他的两个子结点,被称为堆有序。
二叉堆:是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级储存。(不使用数组的第一个位置)
即:k的父结点为k/2;k的子结点为2k和2k+1。
堆中根结点也就是a[1]是二叉树的最大结点。
一棵大小为N的完全二叉树的高度为log2^N+1。
堆排序过程:
堆排序主要分为两部分:
一、是将数组构造为堆有序;
二、是下沉排序,即将堆末元素与堆首交换,然后输出新堆末元素,新堆首元素下沉。
代码:
改进:
下沉函数可以动过位移的方式回避交换函数
测试用例:
堆排序测试结果:
堆排序在排序复杂性的研究中有着重要的地位,因为他是我们所知的唯一能够同时最优化地利用空间和时间的方法——在最坏的情况下他也能保证使用~2NlgN次比较和恒定的额外时间。
但在现代系统中使用较少,因为他无法利用缓存。数组元素很少和相邻的其他元素进行比较,因此缓存未命中率要远远高于别的排序方式。
堆有序:二叉树的每个结点都大于等于他的两个子结点,被称为堆有序。
二叉堆:是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级储存。(不使用数组的第一个位置)
即:k的父结点为k/2;k的子结点为2k和2k+1。
堆中根结点也就是a[1]是二叉树的最大结点。
一棵大小为N的完全二叉树的高度为log2^N+1。
堆排序过程:
堆排序主要分为两部分:
一、是将数组构造为堆有序;
二、是下沉排序,即将堆末元素与堆首交换,然后输出新堆末元素,新堆首元素下沉。
代码:
template<typename Item> void eaxh(Item &a, Item &b) { Item t = a; a = b; b = t; } template<typename Item> void sink(vector<Item>&a, int k, int N)//下沉函数 {//(数组,下沉元素,数组长) while (2 * k <= N) { int j = 2 * k;//子结点 if (j < N&&a[j] < a[j + 1])j++;//选择较大的子结点 if (a[k]>=a[j])break; eaxh(a[k], a[j]);//下沉 k = j; } } template<typename Item> void heapsort(vector<Item>&a)//0位元素不接受排序 { int N = a.size()-1; for (int k = N / 2; k >= 1; k--)//堆有序 sink(a, k, N); while (N > 1)//下沉排序 { eaxh(a[1], a[N--]); sink(a, 1, N); } }
改进:
下沉函数可以动过位移的方式回避交换函数
template<typename Item> void sink(vector<Item>&a, int k, int N)//改进下沉函数 {//移位方式下沉元素 Item temp = a[k];//下沉元素 while (2 * k <= N) { int j = 2 * k; if (j < N&&a[j] < a[j + 1])j++; if (temp >= a[j])break; a[k] = a[j];//移位 k = j; } a[k] = temp;//a[k]为末尾子结点 }
测试用例:
int main() { uniform_int_distribution<int> u(0, 100000); default_random_engine e; vector<int> a; for (int i = 0; i <=1000000; ++i) a.push_back(u(e)); heapsort(a); //for (auto i = a.begin() + 1; i < a.end(); i++)//打印动态数组 // cout << *i <<" "; //cout << endl; cout << (double)clock() / CLOCKS_PER_SEC << endl; cout << endl; system("pause"); return 0; }测试结果:
算法|量级 | 10 | 100 | 1000 | 10000 | 100000 | 1000000 |
堆排序 | 0.104 | 0.104 | 0.109 | 0.168 | 0.722 | 7.418 |
改进 | 0.103 | 0.106 | 0.107 | 0.156 | 0.635 | 6.151 |
但在现代系统中使用较少,因为他无法利用缓存。数组元素很少和相邻的其他元素进行比较,因此缓存未命中率要远远高于别的排序方式。
相关文章推荐
- 排序总结系列七:堆排序
- 排序--堆排序
- 排序:堆排序
- 基于JAVA的排序算法之七--堆排序
- 复习排序-堆排序
- 冒泡排序、快速排序、堆排序
- 选择排序之堆排序
- 九度OJ 1202 排序 -- 堆排序
- 荷兰国旗快速排序及堆排序
- 直接插入排序,冒泡排序,快速排序,简单选择排序,堆排序,2-路归并排序,文件存储
- 锦标赛排序和堆排序
- 排序(希尔排序,堆排序,归并排序,快速排序)
- 选择排序之堆排序
- 数据结构实际应用----订单排序(堆排序求前N大)
- 程序员必知的8大排序(java实现)(二)(堆排序)
- 排序算法2--简单选择排序、堆排序
- java排序 -- 堆排序
- 基本的排序算法:冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序
- 选择排序(三)--堆排序
- 各种排序总结(三)堆排序