1、介紹ios
堆,也是計算中一種很經常使用的數據結構,它以樹的形式存在。 對於樹的結構,由於有父節點和子節點的概念,因此通常經過父指針和子指針來實現。可是,也有一種特殊的樹不須要使用指針而能夠直接經過數組來實現,這種樹就是徹底二叉樹(除了最後一層不用全滿,其餘層必須全滿,並且最後一層的葉子結點都靠左對齊)。今天咱們要討論的二叉堆就是一棵徹底二叉樹,二叉堆也是堆的一種,只不過二叉堆擁有本身的特色,它分爲最大堆和最小堆。算法
二叉堆特色:數組
最大堆:全部的父節點值都不小於其孩子節點值。(注意「其」字,僅限於當前父節點和它的子節點的比較)數據結構
最小堆:全部的父節點值都不大於其孩子節點值。(注意「其」字,僅限於當前父節點和它的子節點的比較)測試
算法: parent = floor(i/2),leftChild = 2*i, rightChild = 2*i+1 [注意: 存儲的角標從1開始]。ui
二叉堆圖示:spa
2、使用debug
以前的篇幅介紹過鏈隊列和順序隊列,它們都是普通的隊列,採用先進先出的方式來對元素進行操做。但是,有的時候需求並非僅僅如此,可能會來一個優先級更高的元素操做,這個時候把它按照普通隊列的方式進行處理明顯是不合適的。並且,普通隊列的入隊和出隊的時間複雜度也不是最優的。此時採用二叉堆構建優先隊列,是一個折中的選擇,時間複雜度是最優的,如圖所示:3d
3、代碼指針
定義
#include <iostream> #include <stdlib.h> #include <math.h> #include <algorithm> using namespace std; #define QUEUE_OVERFLOW -1 #define OK 1 #define ERROR 0 typedef int Status; typedef int QElemType; typedef struct BinaryHeap { int capacity; //容量 int count; //個數 QElemType *array; //數組 }BinaryHeapQueue; //構建二叉堆優先隊列 Status constructBinaryHeapQueue(BinaryHeapQueue &bq, int capacity); //將元素添加到隊列 Status enQueueByShiftUp(BinaryHeapQueue &bq, QElemType e); //從隊列中取出元素 Status deQueueByShiftDown(BinaryHeapQueue &bqt); //獲取隊列元素個數 QElemType eleCount(BinaryHeapQueue &bq); //判斷隊列是否爲空 Status isEmpty(BinaryHeapQueue &bq); //判斷隊列是否已滿 Status isFull(BinaryHeapQueue &bq);
實現
//構建一個二叉堆 Status constructBinaryHeapQueue(BinaryHeapQueue &bq, int capacity) { assert(capacity > 0); //數組元素從下標1的位置開始存儲,因此多分配一塊內存 bq.array = (QElemType *)malloc((capacity + 1) * sizeof(QElemType)); bq.capacity = capacity+1; bq.count = 0; if (!bq.array) exit(QUEUE_OVERFLOW); //存儲分配失敗 return OK; } //將元素e添加隊列 Status enQueueByShiftUp(BinaryHeapQueue &bq, QElemType e) { if (isFull(bq)){ cout<<"隊列已滿,當前元素: "<<e<<" 沒法被添加到隊列"<<endl; return ERROR; } //保存元素 bq.array[bq.count+1] = e; cout<<"入隊列元素: "<<"array["<<bq.count+1<<"] = "<<e<<endl; //若是這個入隊元素的值是比父節點值大,則往上移動 int chiIndex = bq.count + 1; int parIndex = floor(chiIndex/2); while (bq.array[parIndex] < bq.array[chiIndex] && parIndex > 0) { swap(bq.array[parIndex], bq.array[chiIndex]);
//從新賦值下標,進入循環 chiIndex = parIndex; parIndex = floor(chiIndex / 2); } //個數自增 bq.count ++; return OK; } //從隊列中取出隊首元素保存到e中 Status deQueueByShiftDown(BinaryHeapQueue &bq) { if (isEmpty(bq)){ cout<<"隊列已空"<<endl; return ERROR; } //取出元素,並將尾部元素放到下標1的位置 QElemType e = bq.array[1]; bq.array[1] = bq.array[bq.count]; cout<<"出隊列元素: "<<"array[1] = "<<e<<endl; //個數自減 bq.count --; //若是當前下標1位置父節點的值是比孩子節點小,則往下移動 int parIndex = 1; int l_chiIndex = parIndex * 2; int r_chiIndex = parIndex * 2 + 1; while (r_chiIndex <= bq.count && bq.count > 1){ if (bq.array[parIndex] <= bq.array[l_chiIndex] || bq.array[parIndex] <= bq.array[r_chiIndex]) { //左孩子比右孩子值大,父節點和左孩子交換 if (bq.array[l_chiIndex] > bq.array[r_chiIndex]) { swap(bq.array[parIndex],bq.array[l_chiIndex]); parIndex = l_chiIndex; } else { swap(bq.array[parIndex],bq.array[r_chiIndex]); parIndex = r_chiIndex; } //從新賦值下標,進入循環 l_chiIndex = parIndex * 2; r_chiIndex = parIndex * 2 + 1; } } return OK; } //獲取隊列元素個數 QElemType eleCount(BinaryHeapQueue &bq) { QElemType count = bq.count; cout<<"隊列元素個數: count = "<<count<<endl; return count; } //判斷隊列是否爲空 Status isEmpty(BinaryHeapQueue &bq) { return bq.count == 0; } //判斷隊列是否已滿 Status isFull(BinaryHeapQueue &bq) { return bq.count == bq.capacity-1; }
4、結果
測試
int main() { ///建立二叉堆優先隊列(本代碼以最大堆爲例) ------ 最小堆實現邏輯與其相似 BinaryHeapQueue heapQueue; constructBinaryHeapQueue(heapQueue, 5); ///添加元素到隊列 enQueueByShiftUp(heapQueue, 60); enQueueByShiftUp(heapQueue, 23); enQueueByShiftUp(heapQueue, 40); enQueueByShiftUp(heapQueue, 60); enQueueByShiftUp(heapQueue, 80); ///獲取元素的個數 eleCount(heapQueue); ///先取出一個元素,再入隊兩個元素 cout<<endl; deQueueByShiftDown(heapQueue); enQueueByShiftUp(heapQueue, 100); enQueueByShiftUp(heapQueue, 200); ///獲取元素的個數 eleCount(heapQueue); cout<<endl; ///取出元素從隊列 deQueueByShiftDown(heapQueue); deQueueByShiftDown(heapQueue); deQueueByShiftDown(heapQueue); deQueueByShiftDown(heapQueue); deQueueByShiftDown(heapQueue); deQueueByShiftDown(heapQueue); ///獲取元素的個數 eleCount(heapQueue); return 0; }
打印
/Users/xiayuanquan/CLionProjects/treeHeap/cmake-build-debug/treeHeap 入隊列元素: array[1] = 60 入隊列元素: array[2] = 23 入隊列元素: array[3] = 40 入隊列元素: array[4] = 60 入隊列元素: array[5] = 80 隊列元素個數: count = 5 出隊列元素: array[1] = 80 入隊列元素: array[5] = 100 隊列已滿,當前元素: 200 沒法被添加到隊列 隊列元素個數: count = 5 出隊列元素: array[1] = 100 出隊列元素: array[1] = 60 出隊列元素: array[1] = 60 出隊列元素: array[1] = 40 出隊列元素: array[1] = 23 隊列已空 隊列元素個數: count = 0 進程已結束,退出代碼 0