最小的k個數、第k小的數(利用快排,堆排序)
阿新 • • 發佈:2019-01-10
快排:(若求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);
}
}