1. 程式人生 > >重讀資料結構之優先順序佇列

重讀資料結構之優先順序佇列

佇列是一種先進先出的結構,但優先順序佇列需要對後擠進去的資料進行排序,如果足夠大的話會排至隊首。它可以用來維護一堆資料中最大(最小)的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;
}

通過堆排序,可以在消耗較少記憶體的情況下找到大量資料中最大(小)的若干資料。