堆排序的二三事
来源:互联网 发布:数据迁移的重要性 编辑:程序博客网 时间:2024/06/02 19:28
1.可以用做外排序。
比如查找N个数据(假设数据量内存放不下)中最大的前K个,
取这N个数据中的前K个建一个小堆,
因为是小堆,所以,堆顶数据必然是最小的。
此时,读取剩余数据,只要是大于堆顶数据,就交换堆顶数据和读到的数据。
然后调整堆,让堆顶继续是最小数据。
(永远保证堆里面保存着读之前所有数据中最大的前K个)
一直读取,直到所有数据读结束。 此时堆里就保存着这N个数据中最大的前K个。
如果是最小的前K个,同理,建大堆。
2.堆也可以直接对一组数据排序。
如果是排成升序,建大堆。
大堆保证了堆顶数据是最大的,且每个节点都是大堆。
堆顶既然已经是最大的数据,堆顶的数据已经有序,所以把堆顶的数据放在数组最后面(因为是升序)
再用原堆底的数据来填补堆顶。(即交换 堆顶和堆低)。
此时再对除堆低以外的数据继续建大堆,然后交换堆低和堆顶,直到只剩最后一个数据,
此时数组有序。
同理,排降序,则建小堆。
1.最大前K个数据如下:
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>#include <windows.h>#include <vector>#include <assert.h>#include <utility>using namespace std;template<class T>class Less{public:bool operator()(const T& left, const T& right) const{return left < right;}};template<class T>class Great{public:bool operator()(const T& left, const T& right) const{return left > right;}};template<class T, class Compare = Great<T>>class Heap{public:Heap(){}Heap(T* a, size_t n){_a.reserve(n);for (size_t i = 0; i < n; i++){_a.push_back(a[i]);}//建堆for (int i = (_a.size() - 2) / 2; i >= 0; --i){AdjustDown(i);}}void AdjustDown(int root) //向下调整{Compare com;int parent = root;int child = parent * 2 + 1;while (child < _a.size()){if (child + 1 < _a.size() && com(_a[child + 1], _a[child])) //选出 最大的一个孩子{++child;}if (com(_a[child], _a[parent])) //让父亲是最大的{swap(_a[child], _a[parent]);parent = child;child = child * 2 + 1;}else{break;}}}void AdjustUp(int child) //向上调整{Compare com;int parent = (child - 1) / 2;while (){if (com(_a[parent], _a[child])){swap(_a[parent], _a[child]);child = patent;parent = (child - 1) / 2;}else{break;}}}protected:vector<T> _a;};void AdjustDown(int* heap, int n, int root){assert(heap);int parent = root;int child = parent * 2 + 1;while (child < n){if (child + 1 < n && heap[child + 1] < heap[child]){++child;}if (heap[child] < heap[parent]){swap(heap[child], heap[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void TopK(){const size_t N = 10000;const size_t K = 10;int a[N] = { 0 };for (size_t i = 0; i < N; i++){a[i] = rand() % N;}a[0] = N + 100;a[100] = N + 101;a[2] = N + 102;a[50] = N + 105;a[1000] = N + 100;a[1005] = N + 1550;a[888] = N + 130;a[9998] = N + 100;a[9999] = N + 100;a[9444] = N + 100;int heap[K] = { 0 };for (size_t i = 0; i < K; i++){heap[i] = a[i];}// 建小堆 堆顶为最小数据for (int i = (K - 2) / 2; i >= 0; i--){AdjustDown(heap, K, i);}//大于堆顶的数据,放入堆 调整一次for (int i = K; i < N; i++){if (a[i] > heap[0]){heap[0] = a[i];AdjustDown(heap, K, 0);}}for (size_t i = 0; i < K; i++){cout << heap[i] << " ";}cout << endl;}int main(){int a[] = { 10,11, 13, 12, 16, 18, 15, 17, 14, 19 };Heap<int>hp(a, sizeof(a) / sizeof(a[0]));TopK();system("pause");return 0;}
2.最大前K个
void AdjustDown(int a[], int root, int len) //向下调整 //{assert(a);int parent = root;int child = parent * 2 + 1;while (child < len) //检查孩子节点是否存在{if (child + 1 < len && a[child] < a[child + 1]){child++;}if (a[parent] < a[child]) //孩子中最大的那个大于父节点则交换 (大堆,必须保证父节点是最大的){swap(a[child], a[parent]);parent = child; //检查孩子节点 是否是大堆child = parent * 2 + 1;}elsebreak;}}void HeapSort(int a[], int len) //升序,建大堆{assert(a);for (int i = (len - 1) / 2; i >= 0; i--){AdjustDown(a, i, len); //建大堆,必须保证根节点(堆顶)是最大的。}int end = len;while (end > 0) {swap(a[end], a[0]); //用最后一个节点替换根节点。AdjustDown(a, 0, end);end--; //此时最后一个节点已经是最大节点(已经有序),去掉最后一个节点。}}
阅读全文
0 0
- 堆排序的二三事
- 堆的建立&堆排序
- 【堆/排序】堆排序的两种建堆方法
- 简单的排序---堆排序
- 堆排序 - 不稳定的排序
- 堆排序的实现
- 堆排序的实现
- 堆的排序
- 堆的排序
- 堆的排序
- 堆排序的实现
- 基于堆的排序
- 堆的排序
- 堆排序的实现
- 堆排序的实现
- 堆排序的几个问题
- 堆排序的实现
- 堆排序的实现
- office 2013 删除注册表
- 区间的价值 V2
- JAVA面试题(01)
- Haskell语言学习笔记(19)File IO
- Struts简介和原理
- 堆排序的二三事
- struts2 第四次
- shell 脚本中获取变量时控制开始字符位置--使用冒号加数字
- 关于函数(一)const与函数
- 微信小程序四(设置底部导航)
- Java web学习笔记3-servlet
- POJ 1061
- react native常用组件
- [LeetCode] 191. Number of 1 Bits