




/**
* @description: 堆
* @author: michael ming
* @date: 2019/5/26 22:22
* @modified by:
*/
#include <iostream>
#include <limits.h>
using namespace std;
class MinHeap
{
int *arr;
int capacity;
int heap_size;
public:
MinHeap(int cap)
{
heap_size = 0;
capacity = cap;
arr = new int [capacity];
}
~MinHeap()
{
delete [] arr;
}
int heapsize()
{
return heap_size;
}
bool full()
{
return capacity == heap_size;
}
void MinHeapify(int i)
{
Heapify(i,heap_size);
}
void Heapify(int i, int size)
{
int l = left(i), r = right(i);
int min = i;
if(l < size && arr[l] < arr[i])
min = l;
if(r < size && arr[r] < arr[min])
min = r;
if(min != i)
{
swap(arr[i], arr[min]);
Heapify(min,size);
}
}
int parent(int i)
{
return (i-1)/2;
}
int left(int i)
{
return 2*i+1;
}
int right(int i)
{
return 2*i+2;
}
void delMin()
{
if(heap_size <= 0)
return;
arr[0] = arr[heap_size-1];
heap_size--;
MinHeapify(0);
}
int getMin()
{
return arr[0];
}
void insert(int val)
{
if(heap_size == capacity)
{
cout << "overflow!" << endl;
return;
}
heap_size++;
int i = heap_size-1;
arr[i] = val;
while(i > 0 && arr[parent(i)] > arr[i])
{
swap(arr[parent(i)], arr[i]);
i = parent(i);
}
}
void sort()
{
int size = heap_size;
for(int i = heap_size-1; i >= 0; --i)
{
swap(arr[i], arr[0]);
Heapify(0,--size);
}
}
void print()
{
for(int i = 0; i < heap_size; ++i)
cout << arr[i] << " ";
}
};
int main()
{
MinHeap minheap(8);
minheap.insert(6);
minheap.insert(8);
minheap.insert(12);
minheap.insert(4);
minheap.insert(15);
minheap.insert(0);
minheap.insert(5);
minheap.insert(9);
minheap.insert(10);
minheap.delMin();
cout << minheap.getMin() << endl;
return 0;
}

堆排序代码见:https://blog.csdn.net/qq_21201267/article/details/80993672#t7
/**
* @description: 合并有序小文件
* @author: michael ming
* @date: 2019/5/29 22:10
* @modified by:
*/
#include "heap.cpp"
int main()
{
int file0[10] = {11, 21, 31, 41, 51, 61, 71, 81, 91, 101};
int file1[8] = {1, 2, 3, 4, 5, 6, 7, 80};
int file2[9] = {13, 23, 33, 43, 53, 63, 73, 83, 93};
int file3[10] = {12, 22, 32, 42, 52, 62, 72, 82, 92, 102};
int file4[7] = {15, 25, 35, 45, 55, 65, 72};
int len0 = 10, len1 = 8, len2 = 9, len3 = 10, len4 = 7;
int i0, i1, i2, i3, i4, j;
i0 = i1 = i2 = i3 = i4 = j = 0;
const int new_len = len0+len1+len2+len3+len4;
int bigFile[new_len];
MinHeap intheap(5);
intheap.insert(file0[i0]);
intheap.insert(file1[i1]);
intheap.insert(file2[i2]);
intheap.insert(file3[i3]);
intheap.insert(file4[i4]);
int top;
while(intheap.heapsize())
{
top = intheap.getMin();
bigFile[j++] = top;
intheap.delMin();
if(i0 < len0-1 && top == file0[i0]) //可以用list做,就不用查找最小的是哪个文件的
{
intheap.insert(file0[++i0]);
}
else if(i1 < len1-1 && top == file1[i1])
{
intheap.insert(file1[++i1]);
}
else if(i2 < len2-1 && top == file2[i2])
{
intheap.insert(file2[++i2]);
}
else if(i3 < len3-1 && top == file3[i3])
{
intheap.insert(file3[++i3]);
}
else if(i4 < len4-1 && top == file4[i4])
{
intheap.insert(file4[++i4]);
}
}
for(i0 = 1, j = 0; j < new_len; i0++,++j)
{
cout << bigFile[j] << " ";
if(i0%10 == 0)
cout << endl;
}
return 0;
}
b. 高性能定时器 多个定时器,需要每隔很短的时间(比如1秒)扫描一遍,查询哪个任务时间到了,需要开始执行,这样有时候很多扫描是徒劳的,如果任务列表很长,扫描很耗时。采用小顶堆,最先执行的放在堆顶,就只需要在堆顶时间到时执行堆顶任务即可,避免无谓的扫描。
a. 针对静态数据(数据不变) 建立大小为K的小顶堆,遍历数组,数组元素与堆顶比较,比堆顶大,就把堆顶删除,并插入该元素到堆 b. 针对动态数据(数据不断插入更新的) 在动态数据插入的时候就与堆顶比较,看是否入堆,始终维护这个堆,需要的时候直接返回,最坏O(n*lgK)
/**
* @description: 用堆求最大的k个元素
* @author: michael ming
* @date: 2019/5/30 0:06
* @modified by:
*/
#include "heap.cpp"
int main()
{
int i = 0;
const int len = 10;
int data[len] = {2, 8, 1, 7, 12, 24, 6, 10, 90, 100};
MinHeap intheap(5);//求前5大元素
while(!intheap.full())
{
if(i < len)
intheap.insert(data[i++]);
}
while(i < len)
{
if(data[i] > intheap.getMin())
{
intheap.delMin();
intheap.insert(data[i]);
}
i++;
}
intheap.sort();
intheap.print();
return 0;
}
静态数据:先排序,中间位置的数就是中位数 动态数据:动态变化,中位数位置总在变动,每次都排序的话,效率很低,借助堆可以高效的解决。

插入数据到某个堆里后,两个堆数据量(应相等或者大堆比小堆多1)若不满足括号要求,则将某个堆的堆顶元素移动到另一个堆,直到满足括号要求,堆化复杂度O(lgn),大堆的堆顶就是中位数,求中位数复杂度O(1)。
同理,可以求99%响应时间(就是大于前面99%数据的那个数据) 跟上面过程类似,只是大堆中保存 n x 0.99 个数据,小堆存 n x 0.01 个数据
/**
* @description: 利用大小两个堆求中位数
* @author: michael ming
* @date: 2019/5/30 20:37
* @modified by:
*/
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> v)
{
for (int i = 0; i < v.size(); ++i)
cout << v[i] << " ";
cout << endl;
}
int main()
{
const int len = 7;
int staticArr[len] = {7,-1,9,0,8,77,24};//-1,0,7,*8*,9,24,77
vector<int> maxheap, minheap;
for(int i = 0; i < len; ++i)
{
if(maxheap.empty())
{
maxheap.push_back(staticArr[i]);
continue;
}
//----选择插入哪个堆-----
if(!maxheap.empty() && staticArr[i] <= maxheap[0])
{
maxheap.push_back(staticArr[i]);
push_heap(maxheap.begin(),maxheap.end());//默认采用 < , 大堆
}
else if(!maxheap.empty() && staticArr[i] > maxheap[0])
{
minheap.push_back(staticArr[i]);
push_heap(minheap.begin(),minheap.end(),greater<int>());//小堆,采用 >
}
//----平衡两个堆的节点比列----
if(maxheap.size() > minheap.size() && maxheap.size() - minheap.size() > 1)
{
minheap.push_back(maxheap[0]);//大堆顶进入小堆
push_heap(minheap.begin(),minheap.end(),greater<int>());
pop_heap(maxheap.begin(),maxheap.end());//堆顶到末尾了
maxheap.pop_back();//删除到末尾的"堆顶"
}
else if(maxheap.size() < minheap.size())
{
maxheap.push_back(minheap[0]);
push_heap(maxheap.begin(),maxheap.end());//默认采用 < , 大堆
pop_heap(minheap.begin(),minheap.end(),greater<int>());
minheap.pop_back();
}
}
if(maxheap.size())
cout << "中位数为:" << maxheap[0] << endl;
return 0;
}stl heap操作:http://www.cplusplus.com/reference/algorithm/pop_heap/

对上面程序稍加改造,对动态数据进行求解中位数
/**
* @description: 中位数求解,利用大小堆,动态数据插入
* @author: michael ming
* @date: 2019/5/30 23:13
* @modified by:
*/
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
void printVec(vector<int> v)
{
for (int i = 0; i < v.size(); ++i)
cout << v[i] << " ";
cout << endl;
}
int main()
{
int num;
vector<int> maxheap, minheap, allnum;
while(cin >> num)
{
allnum.push_back(num);
if(maxheap.empty())
{
maxheap.push_back(num);
cout << "排序后的数组:" << endl;
printVec(allnum);
cout << "中位数为:" << maxheap[0] << endl;
continue;
}
//----选择插入哪个堆-----
if(!maxheap.empty() && num <= maxheap[0])
{
maxheap.push_back(num);
push_heap(maxheap.begin(),maxheap.end());//默认采用 < , 大堆
}
else if(!maxheap.empty() && num > maxheap[0])
{
minheap.push_back(num);
push_heap(minheap.begin(),minheap.end(),greater<int>());//小堆,采用 >
}
//----平衡两个堆的节点比列----
if(maxheap.size() > minheap.size() && maxheap.size() - minheap.size() > 1)
{
minheap.push_back(maxheap[0]);//大堆顶进入小堆
push_heap(minheap.begin(),minheap.end(),greater<int>());
pop_heap(maxheap.begin(),maxheap.end());//堆顶到末尾了
maxheap.pop_back();//删除到末尾的"堆顶"
}
else if(maxheap.size() < minheap.size())
{
maxheap.push_back(minheap[0]);
push_heap(maxheap.begin(),maxheap.end());//默认采用 < , 大堆
pop_heap(minheap.begin(),minheap.end(),greater<int>());
minheap.pop_back();
}
sort(allnum.begin(),allnum.end());
cout << "排序后的数组:" << endl;
printVec(allnum);
if(maxheap.size())
cout << "中位数为:" << maxheap[0] << endl;
}
return 0;
}