/*
本文是选择问题:
选择一组N个数当中的第k小的数(第k大的数类似)
集中方法的实现代码
*/
#include "sorting.h"
#include "fatal.h"
#define SORTING_BUBBLE 1
#define SORTING_INSERTION 2
#define SORTING_SELECTION 3
#define SORTING_SHELL 4
#define SORTING_QUICK 5
#define SORTING_HEAP 6
#define SORTING_MERGE 7
/*
解法1: 我们可以对这个乱序数组按照从小到大先行排序,然后
取出前k大,总的时间复杂度为O(n*logn + k)。
*/
int select_by_sorting(int A[], int N, int k, int SortingMethod)
{
if(k <1 || k > N )
{
fprintf (stderr, "error, k ??????
");
exit (EXIT_FAILURE);
}
switch(SortingMethod)
{
case SORTING_BUBBLE :
bubble_sort (A, N,IntComp);
return A[ k-1];
case SORTING_INSERTION :
insertion_sort (A, N,IntComp);
return A[ k-1];
case SORTING_SELECTION :
selection_sort (A, N,IntComp);
return A[ k-1];
case SORTING_SHELL :
shell_sort (A, N,IntComp);
return A[ k-1];
case SORTING_QUICK :
quick_sort (A, N,IntComp);
return A[ k-1];
case SORTING_HEAP :
heap_sort (A, N,IntComp);
return A[ k-1];
case SORTING_MERGE :
merge_sort (A, N,IntComp);
return A[ k-1];
default:
Error ("not a known sorting method!");
}
return 0;
}
/*
解法2: 先把前k个元素读进数组并排序(递增顺序),接着,将剩下
的元素逐个读入。当新元素大于数组中的第k个元素是则忽略,否则将
其放入正确的位置,旧的第k个元素将被挤掉!
*/
int select2(int A[], int N, int k)
{
// 可改进为前面k个数原地排序。
int *Ak = malloc(sizeof(int )*k);
Ak[0 ] = A[0];
int i,j ;
for(i = 1; i < k; i++)
{
for(j = i- 1; j >= 0 ; j--)
{
if(A [i]< Ak[j])
Ak [j+ 1] = Ak[ j];
else
break;
}
Ak [j+ 1] = A[ i];
}
for(i = k ; i < N; ++i )
{
if(Ak [k- 1]<= A [i]) continue;
for(j = k- 2; j >=0; --j)
{
if(A [i] < Ak[j ])
Ak [j+ 1] = Ak[ j];
else
break;
}
Ak [j+ 1] = A[ i];
}
int ret = Ak [k- 1];
free(Ak );
return ret ;
}
/*
解法3:利用选择排序或交互排序,K次选择后
即可得到第k大的数。总的时间复杂度为O(n*k)
*/
int select3(int A[], int N, int k)
{
int minIndex ;
int tmp;
int i,j ;
for(i = 0; i <k; ++i)
{
minIndex = i;
for(j = i+ 1; j <N; ++j)
if(A [minIndex] > A [j])
minIndex = j;
tmp = A[ minIndex];
A [minIndex] = A [i];
A [i] = tmp;
}
return A [k- 1];
}
/*
解法4:利用快速排序的思想,从数组S中随机找出一个元素X,
把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素
小于X。这时有两种情况:
1. Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数;
2. Sa中元素的个数大于等于k,则返回Sa中的第k大数。时间复杂度近似为O(n)
*/
int partition(int A[], int p, int q)
{
// select a pivot
// for simplicity select p as pivot
int i,j ;
i = p ;
int tmp;
for(j = p +1; j <= q ; j++)
{
if(A [j] < A[p ])
{
++i;
if(i == j)
continue;
tmp = A[ i];
A [i] = A[j ];
A [j] = tmp;
}
}
tmp = A [i];
A[i ] = A[p];
A[p ] = tmp;
return i ;
}
int findk( int A[], int p, int q, int k)
{
int r = partition (A, p,q);
if(k-1 == r)
return A[ r];
else if(r > k - 1)
{
return findk( A,p,r -1, k);
}else
return findk( A,r+1 ,q, k);
}
int select4(int A[], int N, int k)
{
return findk (A, 0,N -1, k);
}
#define ITEMNUM 5000
#define METHODNUM 10
int main()
{
int A[METHODNUM ][ITEMNUM];
int k = 564;
int temp;
for(int i = 0 ; i < ITEMNUM; ++i)
{
temp = rand();
for(int j = 0; j < METHODNUM; j++)
A [j][ i] = temp ;
}
int r1,r2 ,r3, r4,r5,r6 ,r7, r8;
r1 = select_by_sorting (A[ 0],ITEMNUM ,k, SORTING_BUBBLE);
r2 = select_by_sorting (A[ 1],ITEMNUM ,k, SORTING_INSERTION);
r3 = select_by_sorting (A[ 2],ITEMNUM ,k, SORTING_SELECTION);
r4 = select_by_sorting (A[ 3],ITEMNUM ,k, 4);
r5 = select_by_sorting (A[ 4],ITEMNUM ,k, 5);
r6 = select_by_sorting (A[ 5],ITEMNUM ,k, 6);
r7= select_by_sorting (A[ 6],ITEMNUM ,k, 7);
r8 = select2 (A[ 7],ITEMNUM ,k);
int r9 = select3 (A[ 8],ITEMNUM ,k);
printf("%d
%d
%d
%d
%d
%d
%d
%d
" ,r1, r2,r3,r4 ,r5, r6,r7,r8 );
printf("%d
" ,r9);
int r10 = select4 (A[ 9],ITEMNUM ,k);
printf("%d
" ,r10);
return 0;
}