重讀資料結構之優先順序佇列
阿新 • • 發佈:2018-12-20
佇列是一種先進先出的結構,但優先順序佇列需要對後擠進去的資料進行排序,如果足夠大的話會排至隊首。它可以用來維護一堆資料中最大(最小)的N個數據,在這裡用大頂堆(完全二叉樹)來實現不停輸入整數時找出K個最小的數,通過與堆頂的比較,決定是否頂替堆頂並再次排序。這也是為了給KD樹求K近鄰做個鋪墊~
大頂堆在陣列中的表現是陣列下標n是下標2n與2n+1的父節點,同時2n的節點大於它的兄弟節點,因此在有資料頂替堆頂之後,再依次與其子節點比較,若有需要則替換。這樣每一次維護的平均時間複雜度是nlog(n)。
開心寫程式碼:
#include <iostream> using namespace std; int *a;//初始化陣列 //交換位置 void swapData(int a[],int i,int j) { int temp; temp = a[i]; a[i] = a[j]; a[j] = temp; } //維護大頂堆 void reorderQueue(int a[],int n) { int q; //檢查從堆頂沉下來的資料是否需要與子節點交換 for(int i = 1;i < n/2+1;i++) { q=2*i; if(q+1 > n) break; if(a[q] < a[q+1]) swapData(a,q,q+1); if(a[i] < a[q]) swapData(a,i,q); } } void insertData(int a[],int insertInt,int n,int K) { if(n <= K) { a[n]=insertInt; reorderQueue(a,n); } else if(n > K && insertInt < a[1]) { a[1]=insertInt; reorderQueue(a,K); } else { cout<<"a too big integer"<<endl; } } int main() { int K;//從資料中找最小的K個數 cout<<"Please input K"<<endl; cin >> K; int *a = new int[K+1]; a[0]=-1; cout<<"Please input data"<<endl; int n = 1; int insertInt; while(cin>>insertInt) { insertData(a,insertInt,n,K); ++n; for(int i = 1;i < K+1;i++) { cout<<a[i]<<" "; } cout<<endl; } delete a; return 0; }
通過堆排序,可以在消耗較少記憶體的情況下找到大量資料中最大(小)的若干資料。