快速找出数组中前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]<<" ";
}

猜你喜欢

转载自blog.csdn.net/qq_35503380/article/details/82528241