数据结构--堆 Heap
文章目錄
- 1. 概念
- 2. 操作和存儲(chǔ)
- 2.1 插入一個(gè)元素
- 2.2 刪除堆頂元素
- 3. 堆排序(不穩(wěn)定排序)
- 3.1 建堆
- 3.2 排序
- 3.3 思考:為什么快速排序要比堆排序性能好?兩者都是O(nlogn)
- 4. 堆應(yīng)用
- 4.1 優(yōu)先級(jí)隊(duì)列
- 4.2 用堆求 Top K(前K大數(shù)據(jù))
- 4.3 求中位數(shù)
- 4.4 思考:海量關(guān)鍵詞搜索記錄,求topK
1. 概念
- 堆是一種特殊的樹(shù)
a. 堆是完全二叉樹(shù)(除最后一層,其他層都是滿(mǎn)的,最后一層節(jié)點(diǎn)都靠左)
b. 每一個(gè)節(jié)點(diǎn)都大于等于(或者都小于等于)其子樹(shù)中每個(gè)節(jié)點(diǎn)的值
2. 操作和存儲(chǔ)
- 完全二叉樹(shù)適合用數(shù)組存儲(chǔ),節(jié)省空間(不需要左右指針)
2.1 插入一個(gè)元素
2.2 刪除堆頂元素
/*** @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; }3. 堆排序(不穩(wěn)定排序)
3.1 建堆
- 方法1:一個(gè)一個(gè)的插入這種方式
- 方法2:從倒數(shù)第一個(gè)有葉子節(jié)點(diǎn)的節(jié)點(diǎn)開(kāi)始,檢查其子節(jié)點(diǎn)是否滿(mǎn)足堆,依次往前,直到堆頂,建堆的復(fù)雜度O(n)
3.2 排序
- 建堆結(jié)束后,最大元素在堆頂,與最后一個(gè)元素交換(不穩(wěn)定),然后對(duì)剩余的 n-1 個(gè)元素重新構(gòu)建堆,重復(fù)這個(gè)過(guò)程,最后只剩1個(gè)元素,排序結(jié)束,建堆復(fù)雜度O(nlogn)
堆排序代碼見(jiàn):https://blog.csdn.net/qq_21201267/article/details/80993672#t7
3.3 思考:為什么快速排序要比堆排序性能好?兩者都是O(nlogn)
4. 堆應(yīng)用
4.1 優(yōu)先級(jí)隊(duì)列
- 優(yōu)先級(jí)隊(duì)列用堆實(shí)現(xiàn)是最直接、最高效的。優(yōu)先出隊(duì),就是堆頂取出
a. 合并有序小文件
把多個(gè)有序的小文件的第一個(gè)元素取出,放入堆中,取出堆頂?shù)酱笪募?#xff0c;然后再?gòu)男∥募腥〕鲆粋€(gè)加入到堆,這樣就把小文件的元素合并到大文件中了。
b. 高性能定時(shí)器
多個(gè)定時(shí)器,需要每隔很短的時(shí)間(比如1秒)掃描一遍,查詢(xún)哪個(gè)任務(wù)時(shí)間到了,需要開(kāi)始執(zhí)行,這樣有時(shí)候很多掃描是徒勞的,如果任務(wù)列表很長(zhǎng),掃描很耗時(shí)。采用小頂堆,最先執(zhí)行的放在堆頂,就只需要在堆頂時(shí)間到時(shí)執(zhí)行堆頂任務(wù)即可,避免無(wú)謂的掃描。
4.2 用堆求 Top K(前K大數(shù)據(jù))
a. 針對(duì)靜態(tài)數(shù)據(jù)(數(shù)據(jù)不變)
建立大小為K的小頂堆,遍歷數(shù)組,數(shù)組元素與堆頂比較,比堆頂大,就把堆頂刪除,并插入該元素到堆
b. 針對(duì)動(dòng)態(tài)數(shù)據(jù)(數(shù)據(jù)不斷插入更新的)
在動(dòng)態(tài)數(shù)據(jù)插入的時(shí)候就與堆頂比較,看是否入堆,始終維護(hù)這個(gè)堆,需要的時(shí)候直接返回,最壞O(n*lgK)
4.3 求中位數(shù)
靜態(tài)數(shù)據(jù):先排序,中間位置的數(shù)就是中位數(shù)
動(dòng)態(tài)數(shù)據(jù):動(dòng)態(tài)變化,中位數(shù)位置總在變動(dòng),每次都排序的話,效率很低,借助堆可以高效的解決。
插入數(shù)據(jù)到某個(gè)堆里后,兩個(gè)堆數(shù)據(jù)量(應(yīng)相等或者大堆比小堆多1)若不滿(mǎn)足括號(hào)要求,則將某個(gè)堆的堆頂元素移動(dòng)到另一個(gè)堆,直到滿(mǎn)足括號(hào)要求,堆化復(fù)雜度O(lgn),大堆的堆頂就是中位數(shù),求中位數(shù)復(fù)雜度O(1)。
同理,可以求99%響應(yīng)時(shí)間(就是大于前面99%數(shù)據(jù)的那個(gè)數(shù)據(jù))
跟上面過(guò)程類(lèi)似,只是大堆中保存 n x 0.99 個(gè)數(shù)據(jù),小堆存 n x 0.01 個(gè)數(shù)據(jù)
stl heap操作:http://www.cplusplus.com/reference/algorithm/pop_heap/
對(duì)上面程序稍加改造,對(duì)動(dòng)態(tài)數(shù)據(jù)進(jìn)行求解中位數(shù)
4.4 思考:海量關(guān)鍵詞搜索記錄,求topK
- 用散列表去重,并累加搜索次數(shù)
- 再建立大小為K的小頂堆,遍歷散列表,次數(shù)大于堆頂?shù)?#xff0c;頂替堆頂入堆
- (以上在散列表很大時(shí),需要內(nèi)存超過(guò)單機(jī)內(nèi)存,怎么辦?)
- 建立n個(gè)空文件,對(duì)搜索關(guān)鍵詞求哈希值,哈希值對(duì)n取模,得到該關(guān)鍵詞被分到的文件號(hào)(0到n-1)
- 對(duì)每個(gè)文件,利用散列和堆,分別求出topK,然后把n個(gè)topK(比如10個(gè)Top 20,200很小了吧)放在一起,出現(xiàn)次數(shù)最多的K(20)個(gè)關(guān)鍵詞就是這海量數(shù)據(jù)里搜索最頻繁的。
總結(jié)
以上是生活随笔為你收集整理的数据结构--堆 Heap的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 动态规划应用--搜索引擎拼写纠错
- 下一篇: cms安装教程Linux,DoraCMS