1. 程式人生 > >最小的k個數、第k小的數(利用快排,堆排序)

最小的k個數、第k小的數(利用快排,堆排序)

快排:(若求top M個元素,則只需把下面的程式裡的k換乘n-M即可)

//利用快排求最小的k個數,第k小的數
void GetLeastKNum(int *input,int n,int *output,int k)
{
    if(input==NULL || n<=0 || k<=0) return;
    int start=0;
    int end=n-1;
    int index=partition(input,start,end);
    while(index!=k-1)
    {
        if(index<k-1)
        {
            start=index
+1; index=partition(input,start,end); } else { end=index-1; index=partition(input,start,end); } } for(int i=0;i<k;i++) output[i]=input[i]; //其中,output[k-1]就是第k小的數 } //partition函式,時間複雜度是o(n) int partition(int *a,int
low,int high) { int pivot=a[low];//樞軸 while(low<high) { while(low<high && a[high]>pivot) high--; swap(a[low],a[high]); while(low<high && a[low]<pivot) low++; swap(a[low],a[high]); } return low; } //改進的partition函式,o(n)
int partition2(int *a,int low,int high) { int pivot=a[low]; while(low<high) { while(low<high && a[high]>pivot) high--; a[low]=a[high]; while(low<high && a[low]<pivot) low++; a[high]=a[low]; } a[low]=pivot; return low; }

利用堆排序:

/****************大根堆排序********************/
void AdjustDown(int *a,int s,int n)
{
    a[0]=a[s];//a[0]暫時存放
    for(int i=2*s;i<=n;i*=2)//沿著k較大的位元組點向下篩選
    {
        if(i<n && a[i]<a[i+1])
            i++;//取K較大的子節點的下標
        if(a[0]>=a[i]) break;//篩選結束
        else
        {
            a[s]=a[i];//將a[i]調整到雙親節點上
            s=i;//修改k值,以便繼續向下篩選
        }
    }
    a[s]=a[0];//被篩選節點的值放在最終位置
}
void BuildMaxHeap(int *a,int n)
{
    for(int i=n/2;i>0;i--)
        AdjustDown(a,i,n);//向下調整
}
void HeapSort(int *a,int n)//n是指待排序列 的元素個數,陣列a的長度是n+1,a[0]不使用
{
    BuildMaxHeap(a,n);//建立大根堆,時間複雜度是o(n)
    //調整大根堆,時間複雜度是o(nlgn)
    for(int i=n;i>1;i--)
    {
        swap(a[1],a[i]);
        AdjustDown(a,1,i-1);//向下調整
    }
}
//求最小的k個數
int a[n];//陣列a中存放輸入的N個數
int b[k+1];//從a中以此讀入k個數a[0]...a[k-1],第一個數存在b[1]中,以此類推
BuildMaxHeap(b,k);//調整b為大根堆
for(int i=k;i<n;i++)
{
    if(a[i]>b[1])
        continue;
    else
    {
        b[1]=a[i];
        AdjustDown(b,1,k);
    }
}