優先隊列【堆】的應用:ios
選擇問題:輸入時N 個元素以及一個整數k ,這N 個元素的集能夠是全序的。該選擇問題是要找出第 k 個最大的元素。。。算法
有多種解決方案:數組
1A算法:把這些元素讀入數組,並對其進行排序,返回適當的元素。假設使用的是簡單排序算法,時間複雜度是O(N^2)。ui
1B算法:將k 個元素讀入一個數組,並對其進行排序。這些元素的最小者在第k 個位置上,一個一個的處理其他的元素。當一個元素開始被處理時,它先與第k 個元素進行比較,若是該元素大,則將第k 個元素出去,該元素放在其他k - 1 個排好序的元素中的正確位置。當算法結束時,第k 個位置上的元素就是該問題的解答。該算法的運行時間爲O(N*k),若是k = N / 2(上取整),則運行時間爲O(N^2)【此時的 k 爲中位數】。spa
2A算法:將N個元素讀入一個數組,而後對該數組創建一個大頂堆。最後,執行k 次刪除最大值的操做。從該堆最後提取的元素就是咱們的答案。若是使用 BuildHeap 算法構造堆的最壞狀況是 O(N) 【具體分析參見文章(BuildHeap 構建堆的運行時間的界)】,而每次刪除操做用時O(logN),因爲k 次刪除,所以,獲得總的運行時間是O(N + k * logN), 若k = N / 2(上取整),那麼運行時間爲O(NlogN) 【堆排序】。.net
2A-改進:在任意時刻都維持k 個最大元素結合S, 在前 k 個元素讀入之後,當再讀入一個新的元素時,該元素將與第 k 個最大的元素進行比較,記這第k 大的元素爲 Sk,注意 Sk 是 S 中的最小元素。若是新元素更大,則用新元素替代這個 Sk 。此時 S 中將有一個新的最小元。這裏,咱們使用一個堆來實現 S 。前 k 個元素經過堆的創建過程,創建一個堆,總時間爲 O(k),處理其他的每一個元素的時間爲 O(1) (檢測元素是否進入堆),在加上時間O(log k)(在必要時刪除 Sk, 並插入新元素)。所以,總的時間是O(k + (N - k) * log K) = O(N log k)。若 k 爲中位數,則時間爲 O(NlogN)。【代碼以下:】blog
//利用堆尋找某一序列中第k大的元素(從小到大)即第k大的元素
#include<iostream>
#define MINHEAPSIZE 1
#define MINVALUE 0.0001
using namespace std;排序
typedef int ElemType;
typedef struct HeapStruct
{
ElemType *elem;
int Size;
int Capasity;
}Heap, *PriorityQueue;隊列
PriorityQueue InitializeHeap(int MaxSize) //堆的初始化
{
if(MaxSize < MINHEAPSIZE)
throw exception("The priority queue is too small!");
PriorityQueue H;
H = new HeapStruct();
H->Size = 0;
H->Capasity = MaxSize;
H->elem = new ElemType[MaxSize + 1];
H->elem[0] = MINVALUE;
return H;
}ci
void InsertHeap(PriorityQueue H, ElemType key) //上濾過程
{
if(H->Size == H->Capasity)
throw exception("The priority queue is full!");
int i;
for(i = ++H->Size; H->elem[i / 2] > key; i /= 2)
{
H->elem[i] = H->elem[i / 2];
}
H->elem[i] = key;
}
int DeleteMin(PriorityQueue H) //下濾過程
{
int i, child;
ElemType MinElem, LastElem;
if(H->Size == 0)
{
cout << "The priority queue is empty!" << endl;
return H->elem[0];
}
MinElem = H->elem[1]; //此時根節點能夠看作是一個空穴
LastElem = H->elem[H->Size--];
for(i = 1; i * 2 <= H->Size; i = child) //比較空穴i的兩個孩子,child指向最小的孩子
{
child = i * 2;
if(child != H->Size && H->elem[child] > H->elem[child + 1])
child++;
if(LastElem > H->elem[child]) //最小的孩子與最後一個元素比較,若最後一個元素小於該節點的最小孩子,
//則將最後的元素填入空穴中
H->elem[i] = H->elem[child];
else
break;
}
H->elem[i] = LastElem; //填補空穴
return MinElem;
}
int SearchKElem(ElemType arr[], int length, int k)
{
if(length < k || length <MINHEAPSIZE)
throw exception("Invalidate input!");
PriorityQueue H;
H = InitializeHeap(k);
for(int i = 0; i < k; i++)
InsertHeap(H, arr[i]);
for(int j = k; j < length; j++)
{
if(arr[j] > H->elem[1])
{
DeleteMin(H);
InsertHeap(H, arr[j]);
}
}
ElemType kMax = H->elem[1];
return kMax;
}
int main()
{
int arr[10] = {5, 2, 8, 1, 3, 9, 7, 4, 6,10};
int k;
cout << "請輸入k值:" ;
cin >> k;
int result = SearchKElem(arr, 10, k);
cout <<"倒數第k大的元素爲:" << result << endl;
system("pause"); return 0;}