1. 程式人生 > >快速找出陣列中前k小的元素

快速找出陣列中前k小的元素

方法一:利用快排的思想,迴圈找到第k個位置安放正確的元素,此時k的左邊是小於k位置元素的元素,右邊是大於k位置元素的元素,即前k個元素就是問題答案。時間複雜度O(n)。

int Partition(vector<int> &res,int s,int e)
{
    int tp=res[s];
    while(s<e)
    {
        while(s<e&&res[e]>=tp)e--;
        res[s]=res[e];
        while(s<e&&res[s]<=tp)s++;
        res[e]=res[s];
    }
    res[s]=tp;
    return s;
}

void GetKNumbers(vector<int> res,int k)
{
    int s=0,e=res.size()-1;
    int index=Partition(res,s,e);
    while(index!=k-1) //當k位置安放正確的時候,前k個元素就是最終結果
    {
        if(index>k-1)e=index-1;
        else s=index+1;
        index=Partition(res,s,e);
    }
    for(int i=0;i<k;i++)
        cout<<res[i]<<" ";
}

方法二:利用堆排序的思想,若找前k小的元素,則構建大頂堆,先將前k個元素構建成大頂堆,然後判斷堆頂元素和第k+i元素,若堆頂元素大則將第k+i位置的元素交換,然後重新調整大頂堆,最後得到的大頂堆就是結果。時間複雜度O(nlogk);

void HeapAdjust(vector<int>&heap,int index)
{
    int tp=heap[index];
    for(int i=2*index+1;i<heap.size();i*=2)
    {
        if(i<heap.size()-1&&heap[i]<heap[i+1])
            i++;
        if(tp>heap[i])break;
        heap[index]=heap[i];
        index=i;
    }
    heap[index]=tp;
}

void GetKNumbers(vector<int> res,int k)
{
    if(res.size()==0||res.size()<=k||k<=0)return;
    vector<int> heap(k);//初始化k大小的堆
    for(int i=0;i<k;i++)
        heap[i]=res[i];//首先放入k個元素
    for(int i=(k-1)/2;i>=0;--i)
        HeapAdjust(heap,i);//初始化堆
    for(int i=k;i<res.size();i++)
    {//每次從原陣列中拿出一個元素和當前堆頂值比較,
       //然後判斷是否可以放入,放入後繼續調整堆結構
        if(heap[0]>res[i]){
            heap[0]=res[i];
            HeapAdjust(heap,0);
        }
    }
    for(int i=0;i<k;i++)
        cout<<heap[i]<<" ";
}