堆(優先隊列)priority queue
特殊的隊列,取出元素的順序是依照元素的優先權(關鍵字)大小,而出元素進入隊列的先后順序
操作:查找最大值(最小值),刪除(最大值)
數組:
鏈表:
有序數組:
有序鏈表:
采用二叉搜索樹? NO
采用完全二叉樹 YES
堆的連個特性
結構性:用數組表示的完全二叉樹:
有序性:任一結點的關鍵字是其字樹所有結點的最大值(或最小值)
最大堆(MaxHeap)也稱大頂堆:最大值
最小堆(MinHeap)也稱“小頂堆”:最小值
從根節點到任意結點路徑上結點序列的有序性
操作:插入任意一個元素,刪除最 大值元素
最大堆的刪除:取出根節點(最大值)元素,同時刪除堆的一個結點
最大堆的建立:將已存在的N個元素按最大堆的要求存放在一個以為數組中
1 #include <stdio.h>
2 #include <stdlib.h>
3 //最大堆
4
5 #define MaxData 1000 //哨兵,該值應該根據具體情況定義為大於堆中所有可能元素的值
6
7 typedef int ElementType; 8
9 typedef struct HeapNode * MaxHeap; 10 struct HeapNode { 11 int Capacity; //堆的最大容量
12 int Size; //堆中當前元素個數
13 ElementType *Data; //用於存儲元素的數組
14 };
建一個空的最大堆:
1 //建立一個空的最大堆
2 MaxHeap InitHeap(int maxsize) 3 { 4 MaxHeap H = (MaxHeap)malloc(sizeof(struct HeapNode)); 5 H->Data = (ElementType*)malloc(sizeof(struct HeapNode) * (maxsize + 1)); //堆中的元素是從下標為1開始存儲的,但是為了保證這個堆能存下maxsize個元素,所以要分配maxsize + 1個內存單元
6 H->Capacity = maxsize; 7 H->Size = 0; 8 H->Data[0] = MaxData; //將0下標的單元存儲哨兵
9 for (int i = 1; i < maxsize + 1; i++) 10 H->Data[i] = 0; 11 return H; 12 }
判斷堆是否已滿或是否為空:
1 int IsEmpty(MaxHeap H) 2 { 3 return H->Size == 0; 4 } 5
6 //判斷堆是否已滿
7 int IsFull(MaxHeap H) 8 { 9 return H->Size == H->Capacity; 10 }
插入一個元素:
1 //最大堆中插入一個元素
2 void Insert(MaxHeap H, ElementType item) 3 { 4 int i; 5 if (IsFull(H)) 6 { 7 printf("The heap is full\n"); 8 return; 9 } 10 i = ++H->Size; //i為插入后堆中最后一個元素的位置
11 for (; H->Data[i / 2] < item; i /= 2) 12 H->Data[i] = H->Data[i / 2]; //循環退出時,父節點的數據已經大於item, item已經找到了正確的位置
13 H->Data[i] = item; //將item賦給正確的下標單元
14 }
刪除一個元素:
1 ElementType Delete(MaxHeap H) 2 { 3 ElementType temp, Max; 4 int parent = 1, child; 5 if (IsEmpty(H)) 6 { 7 printf("The heap is empty!\n"); 8 return 0; 9 } 10 Max = H->Data[1]; //現將最大值即根節點的值記錄下來
11 temp = H->Data[H->Size--]; //用最后的結點元素暫時代替根節點的數據,然后將堆的數據大小減1 12
13 //如果2 * parent > 0,那么說明parent已經是根節點了
14 for (; 2 * parent <= H->Size; parent = child) 15 { 16 child = 2 * parent; 17
18 //如果Child != H->Size說明child不是最后一個結點,該parent結點還有右節點, 19 //並且如果右節點的值大於左結點,那么child++;
20 if (child != H->Size && (H->Data[child + 1] < H->Data[child])) 21 child++; //child指向左右子節點的較大者
22 if (temp > H->Data[child]) break; //如果孩子結點已經小於temp了, 說明找到了合適的位置
23 else
24 H->Data[parent] = H->Data[child]; 25 } 26 H->Data[parent] = temp; 27 return Max; 28 }
最大堆的建立:
1.第一步,將N個元素按輸入順序存入二叉樹中,這一步需要求滿足完全二叉樹的結構特性,而不管其有序性
2.從最后一個右孩子的結點開始調整,做類似刪除元素時的下濾操作,逐個結點調整,直至根節點
1 //創建一個最大堆
2 MaxHeap CreateMaxHeap() 3 { 4 int dt, i = 0, j; 5 int parent, child; 6 ElementType X; 7 MaxHeap H = InitHeap(20); //先創建一個空的最大堆,然后往里面填充元素
8 while (scanf_s("%d", &dt) != EOF) 9 { 10 H->Data[i + 1] = dt; 11 i++; 12 H->Size++; 13 } 14 for (j = i / 2; j >= 1; j--) //從i / 2開始逐一向下過濾
15 { 16 //下面的操作和刪除元素是一模一樣的,只是不用將的元素個數減一
17 X = H->Data[j]; 18 for (parent = j; 2 * parent <= H->Size; parent = child) 19 { 20 child = 2 * parent; 21 if (child != H->Size && H->Data[child] < H->Data[child + 1]) 22 child++; 23 if (H->Data[child] < X) 24 break; 25 else
26 H->Data[parent] = H->Data[child]; 27 } 28 H->Data[parent] = X; 29 } 30 return H; 31 }
打印堆中的元素:
1 //打印堆中元素
2 void printHeap(MaxHeap H) 3 { 4 for (int i = 1; i <= H->Size; i++) 5 printf("%d ", H->Data[i]); 6 printf("\n"); 7 }
先序建立樹:
1 void PreOrderCreateHeap(MaxHeap H, int index) 2 { 3 int dt; 4 scanf_s("%d", &dt); 5 if (dt == 0) 6 { 7 return; 8 } 9 H->Size++; 10 H->Data[index] = dt; 11 printf("please enter the left child of %d :", dt); 12 PreOrderCreateHeap(H, 2 * index); 13 printf("please enter the right child of %d: ", dt); 14 PreOrderCreateHeap(H, 2 * index + 1); 15 }
主函數:
1 int main() 2 { 3 MaxHeap H = CreateMaxHeap(); 4 PreOrderCreateHeap(H, 1); 5 printHeap(H); 6
7 return 0; 8 }