堆和優先隊列

1 二叉堆和優先隊列的概念

1.1 二叉堆

     二叉堆是一個數組,它能夠被當作一個近似的徹底二叉樹,樹上每個結點對應數組中的一個元素。除了最底層外,該樹是徹底充滿的,並且是從左到右填充。表示堆的數組A包括兩個屬性:A.length給出數組元素的個數,A.heap_size表示有多少個堆元素存儲在該數組中,這裏,0<=A.heap_size<=A.length。算法

     以下圖所示:api

    

     堆能夠分紅兩種:最大堆和最小堆。在最大堆中,任何節點的值都大於等於其孩子的值,故根節點是數組中的最大數所在節點。反之,最小堆中,任何節點的值都小於等於其孩子的值,故根節點是數組中最小值所在節點。數組

     最小堆以下:數據結構

    

1.2 優先隊列

     優先隊列是一種用來維護由一組元素構成的集合S的數據結構,其中的每個元素都有一個相關的值,稱爲關鍵字。優先隊列也分爲兩種:最大優先隊列和最小優先隊列。ide

     一個最大優先隊列支持如下操做:ui

•INSERT(S,x):把元素x插入集合S中;spa

•MAXIMUM(S):返回S中具備最大關鍵字的元素;3d

•EXTRACT_MAX(S):去掉而且返回S中的具備最大關鍵字的元素;code

•INCREASE_KEY(S,x,k):將元素x的關鍵字值增長到k。blog

相應地,最小優先隊列支持的操做包括INSERT、MINIMUM、EXTRAT_MIN和DECRESE_KEY。

2 堆的實現

2.1 堆的插入

     因爲二叉堆就是一個簡單的一維Int數組,故不須要初始化,直接插入即可。

     每次插入都將新數據放到數組的最後的位置,最小堆原理如圖:

     http://pic002.cnblogs.com/img/yc_sunniwell/201006/2010062815070251.png

     假設要在這個二叉堆裏入隊一個單元,鍵值爲2,那隻需在數組末尾加入這個元素,而後儘量把這個元素往上挪,直到挪不動,通過了這種複雜度爲Ο(logn)的操做,二叉堆仍是二叉堆。

     核心代碼以下:

 1 //A爲該數組,i是新數據所在下標 
 2 void Insert(int A[], int i,int heap_size)  
 3 {  
 4     int j, temp;  
 5       
 6     temp = A[i];  
 7     j = i / 2;      //父結點  
 8     while (j >= 1 && i != 1)  
 9     {  
10         if (A[j] <= temp)  
11             break;  
12           
13         A[i] = A[j];     //把較大的子結點往下移動,替換它的子結點  
14         i = j;  
15         j = i  / 2;  
16     }  
17     A[i] = temp;
18     heap_size ++;  
19 }
View Code

2.2 堆的刪除

     按定義,堆中每次都只能刪除第1個數據。爲了便於重建堆,實際的操做是將最後一個數據的值賦給根結點,而後再從根結點開始進行一次從上向下的調整。調整時先在左右兒子結點中找最小的,若是父結點比這個最小的子結點還小說明不須要調整了,反之將父結點和它交換後再考慮後面的結點。至關於從根結點將一個數據的「下沉」過程。

     下面給出代碼:

 1 //先進行調整
 2 void MinHeapify(int A[],int i,int heap_size)
 3 {
 4     int l = 2*i;
 5     int r = 2*i+1;
 6     int minimum;
 7     if(l <= heap_size && A[l] < A[i])
 8         minimum = l;
 9     else
10         minimum = i;
11     if(r <= heap_size && A[r] > A[minimum])
12         minimum = r;
13     if(minimum!= i)
14     {
15         swap(A[i],A[minimum]);
16         MinHeapify(minimum,heapsize);
17     }
18 }
19 
20 //而後刪除
21 void Delete(int A[],int heap_size)
22 {
23     Swap(A[1],A[heap_size]);
24     heap_size --;
25     MinHeapify(A,1,heap_size);    
26 }
View Code

2.3 堆化數組(建堆)

     有了堆的插入和刪除後,再考慮下如何對一個數據進行堆化操做。

     核心代碼以下:

1 //N是數組中元素個數
2 void BuildMinHeap(int A[],int N,int heap_size)
3 {
4     int heap_size = N;
5     for(int i = N/2;i > 0;i--)
6         MinHeapify(A,i,heap_size);
7 }
View Code

2.4 堆排序

     核心算法以下:  

 1 void HeapSort(int A[],int heap_size,int N)
 2 {
 3     int heap_size = N;
 4     BuildMinHeap(A,N,heap_size);
 5     for(int i = N;i > 1;i--)
 6     {
 7         Swap(A[1],A[i]);
 8         heap_size --;
 9         MinHeapify(A,1,heap_size);
10     }
11 }
View Code

3 優先隊列

     在用堆實現優先的過程當中,須要注意最大堆只能對應最大優先隊列,最小堆則是對應最小優先隊列,核心代碼以下: 

 1 void INCREASE_KEY(int A[],int i,int key)
 2 {
 3     if (key < A[i])
 4         cout <= "error!";
 5     A[i] = key;
 6     while (i > 1 && A[i/2] < A[i])
 7     {
 8         swap(A[i],A[i/2]);
 9         i = i/2;
10     }
11 }
12 
13 void INSERT(int A[],int key,int heap_size)
14 {
15     heap_size ++;
16     A[heap_size] = MIN; //MIN爲負無窮
17     INCREASE_KEY(A,heap_size,key);
18 }
19 
20 int MAXIMUM(int A[])
21 {
22     return A[1];
23 }
24 
25 int EXTRACT_MAX(int A[],int heap_size)
26 {
27     if (heap_size < 1)
28         cout <= "error!";
29     int max = A[1];
30     A[1] = A[heap_size];
31     heap_size --;
32     MAX_HEAPIFY(A,1,heap_size);  //應該很好根據前面的分析寫出來
33 }
View Code

     以上代碼的寫法有些欠妥,用struct和全局變量寫應該會方便不少,各位多多體諒!

相關文章
相關標籤/搜索