堆的原理及实现
文章目錄
- 1 堆的原理
- 2 堆的實(shí)現(xiàn)
- 2.1 堆的創(chuàng)建
- 2.2 向堆中插入新元素
- 2.3 堆頂元素出堆
1 堆的原理
先看一下堆長什么樣:
最大堆的特點(diǎn):
看一下如下幾個符不符合最大堆的定義:
(A、B不是,C是最大堆。)
看一下堆的特點(diǎn):
- 堆是你見過的最有個性的樹!它是用數(shù)組表示的樹!
對于i子結(jié)點(diǎn):
- i的左子結(jié)點(diǎn)為:2 * i + 1
- i的右子結(jié)點(diǎn)為:2 * i + 2
- i的父結(jié)點(diǎn):(i - 1) / 2
2 堆的實(shí)現(xiàn)
2.1 堆的創(chuàng)建
在數(shù)組中快速創(chuàng)建堆:
算法實(shí)現(xiàn)如下:
堆數(shù)據(jù)結(jié)構(gòu)的定義:
#define DEFAULT_CAPCITY 128typedef struct _Heap{int *arr; //存儲堆元素的數(shù)組int size; //當(dāng)前已存儲的元素個數(shù)int capacity; //當(dāng)前存儲的容量 }Heap;建最大堆:
bool initHeap(Heap &heap, int *orginal, int size); static void buildHeap(Heap &heap); static void adjustDown(Heap &heap, int index);/*初始化堆*/ bool initHeap(Heap &heap, int *orginal, int size){int capacity = DEFAULT_CAPCITY>size? DEFAULT_CAPCITY:size;heap.arr = new int[capacity];if(!heap.arr) return false;heap.capacity = capacity;heap.size = 0;//如果存在原始數(shù)據(jù)則構(gòu)建堆if(size>0){memcpy(heap.arr, orginal, size*sizeof(int));heap.size = size;buildHeap(heap);}else {heap.size = 0;}return true; }/*將當(dāng)前的節(jié)點(diǎn)和子節(jié)點(diǎn)調(diào)整成最大堆*/ void adjustDown(Heap &heap, int index) { int cur=heap.arr[index];//當(dāng)前待調(diào)整的節(jié)點(diǎn)int parent,child;/*判斷否存在大于當(dāng)前節(jié)點(diǎn)子節(jié)點(diǎn),如果不存在 ,則堆本身是平衡的,不需要調(diào)整;如果存在,則將最大的子節(jié)點(diǎn)與之交換,交換后,如果這個子節(jié)點(diǎn)還有子節(jié)點(diǎn),則要繼續(xù)按照同樣的步驟對這個子節(jié)點(diǎn)進(jìn)行調(diào)整*/for(parent=index; (parent*2+1)<heap.size; parent=child){child=parent*2+1;//取兩個子節(jié)點(diǎn)中的最大的節(jié)點(diǎn)if(((child+1)<heap.size)&&(heap.arr[child]<heap.arr[child+1])){child++;}//判斷最大的節(jié)點(diǎn)是否大于當(dāng)前的父節(jié)點(diǎn)if(cur>=heap.arr[child]){//不大于,則不需要調(diào)整,跳出循環(huán)break;}else {//大于當(dāng)前的父節(jié)點(diǎn),進(jìn)行交換,然后從子節(jié)點(diǎn)位置繼續(xù)向下調(diào)整heap.arr[parent]=heap.arr[child];heap.arr[child]=cur;}} }/* 從最后一個父節(jié)點(diǎn)(size/2-1 的位置)逐個往前調(diào)整所有父節(jié)點(diǎn) (直到根節(jié)點(diǎn)),確保每一個父節(jié)點(diǎn)都是一個最大堆,最后整體上形成一個最大堆 */ void buildHeap(Heap &heap){int i;for(i=heap.size/2-1; i>=0; i--){adjustDown(heap, i);} }2.2 向堆中插入新元素
代碼實(shí)現(xiàn):
這樣的話我們就可以有另一種創(chuàng)建堆的方式:
/*初始化堆*/ bool initHeap(Heap &heap, int *orginal, int size) {int capacity = DEFAULT_CAPCITY>size ? DEFAULT_CAPCITY : size;heap.arr = new int[capacity];if (!heap.arr) return false;heap.capacity = capacity;heap.size = 0;//如果存在原始數(shù)據(jù)則構(gòu)建堆if(size > 0){/*方式一: 直接調(diào)整所有元素memcpy(heap.arr, orginal, size*sizeof(int));heap.size = size;//建堆buildHeap(heap);*///方式二: 一次插入一個for(int i=0; i<size; i++){insert(heap, orginal[i]);}}return true; }2.3 堆頂元素出堆
如果我們將堆頂?shù)脑貏h除,那么頂部有一個空的節(jié)點(diǎn),怎么處理?
當(dāng)插入節(jié)點(diǎn)的時候,我們將新的值插入數(shù)組的尾部。現(xiàn)在我們來做相反的事情:我們?nèi)〕鰯?shù)組中的最后一個元素,將它放到堆的頂部,然后再修復(fù)堆屬性。
/* 刪除優(yōu)先隊(duì)列中最大的節(jié)點(diǎn),并獲得節(jié)點(diǎn)的值*/ bool pop(Heap& heap, int &value) {if (!heap || (heap->size==0)) return false;value = heap.arr[0];pq.arr[0] = heap.arr[--heap.size];//heap.arr[0] = heap.arr[heap.size-1];//heap.size--;adjustDown(heap, 0);// 向下執(zhí)行堆調(diào)整return true; }參考資料:
總結(jié)
- 上一篇: 请求模式解决共享资源冲突
- 下一篇: Qt中线程的生命期问题