TopK---返回第K小(大)的數字

TopK—返回第K小(大)的數字

給定一個數組,返回數組中第K小(或者第K大)的數字,比較經典的TopK問題。

快排選擇

基於快排的思想,partition函數每次將切分元素放置到正確位置pos:當我們需要的K>pos時,代表我們需要再從(pos,right]中查找;當K

最小(大)堆

基於堆排序的思想,當我們需要查找第K小(大)的數字時,我們將數組前K個元素構建成最大(小)堆,則堆頂元素是前K個數字中最大的(也就是第K小的),再從數組第K+1個元素開始遍歷,如果元素小(大)於當前堆頂元素,則交換到堆頂,再調整堆,維護最大堆,當遍歷完數組後,堆頂元素就是整個數組中第K小的元素。

代碼:

#include<iostream>

using namespace std;

void exchange(int a[],int i,int j);
int partition(int a[],int lo,int hi);
int quick_selector(int a[],int k,int size)
{
  k--;                     //第k小的數索引爲k-1
  int lo = 0,hi = size-1;
  int pos = partition(a, lo, hi);
  while(pos!=k) {
    if(pos<k) lo = pos+1;  //如果當前位置小於k,則在該位置右側繼續
    if(pos>k) hi = pos-1;  //如果當前位置大於k,則在該位置左側繼續
    pos = partition(a, lo, hi);
  }
  return a[k];
}
int partition(int a[],int lo,int hi)
{
  if(lo>hi) return NULL;
  int i = lo-1,j = hi;
  int pivot = (lo+hi)/2;      //將首、中、尾三處值的中間大小值作爲pivot
  if(a[pivot]<a[lo]) exchange(a,pivot,lo);
  if(a[pivot]<a[hi]) exchange(a,pivot,hi);
  if(a[lo]>a[hi]) exchange(a,lo,hi);
  while(true) {
    while(a[++i]<a[hi]) if(i==hi) break;
    while(a[--j]>a[hi]) if(j==lo) break;
    if(i>=j) break;
    exchange(a,i,j);
  }
  exchange(a,i,hi);          //尾處作爲pivot,則應該跟指向大值的指針i交換;如果首處作爲pivot,則應該跟指向小值的j交換
  return i;
}
void sink(int a[],int i,int k);
int heap_selector(int a[],int k,int size)
{
  if(k<=0) return 0;
  for(int i=k/2-1;i>=0;--i) {  //構建k個元素的最大堆
    sink(a,i,k-1);
  }
  for(int i=k;i<size;++i) {    //從第k+1個元素開始替換堆中元素
    if(a[i]<a[0])
      exchange(a,i,0);
    sink(a,0,k-1);            //調整堆,保持最大堆
  }
  return a[0];
}
void sink(int a[],int i,int k) //向下調整
{
  while(2*i+1<=k) {
    int j = 2*i+1;
    if(j<k && a[j]<a[j+1]) j++;
    if(a[i]>a[j]) break;
    exchange(a,i,j);
    i = j;
  }
}
void exchange(int a[],int i,int j)
{
  int temp = a[i];
  a[i] = a[j];
  a[j] = temp;
}
int main()
{
    int a[] = {7, 8, 9, 54, 6, 4, 11, 1, 2, 33};
    cout<<quick_selector(a, 10, sizeof(a)/sizeof(int))<<endl;
    cout<<heap_selector(a, 10, sizeof(a)/sizeof(int))<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章