看来编程技术还有待提高,尤其是一个思维模式要待提高。
前一个选择,即随机选择一个数作为分割点可能会造成最坏情况也为O(n*n),当时的分析是在期望情况下以线性时间做选择。本算法是在最坏情况下都是线性时间做选择。主要的思想为:
1.将长度为n的数组按每5个元素做一组,当然最后可能有一组数据是没有5个元素的。
2.将1得到的每组数据进行插入排序,从而找到每组中的中位数。
3.在2得到的每组中位数中也以这种将数组分成每组5个元素的形式找出这中位数的中位数x。
4.以x为点划分数组。
5.判断划分点是否为我们所要的找的点,若是,算法结束,若在x以前的数目大于我们要寻找的k,则在x前面数据中找,否则在x的后面数据中找。
算法代码实现如下:
//在最坏情况下以O(n)时间做选择
#include<iostream>
using namespace std ;
bool failed = false ;
//这里只考虑整型数
int selectMid(int *array, int start ,int end)
{
if(array == NULL || start > end )
{
failed = true ;
return 0 ;
}
failed = false ;
if(start == end )
{
return array[start] ;
}
if( start+1 == end )
{
return array[start] < array[end] ? array[start]:array[end];
}
//将数组分割成n/5个数组
int len = end - start + 1 ;
int partion = len / 5 ;
if(len % 5 != 0 )
{
partion ++ ;
}
int *mids = new int[partion];
for(int i = 0 ; i < partion ; i ++ )
{
//执行插入排序
int s = i*5 + start;
int e = (i+1)*5+start < end ? (i+1)*5+start:end+1 ;
int mid = (e-s)%2 == 1 ? (e-s)/2+1:(e-s)/2 ;
e-- ;
int temp = 0 ;
int p = s ;
for(int j = s+1; j <= e; j ++ )
{
// insert
int k = j ;
while(k > s )
{
if(array[k] < array[k-1])
{
temp = array[k] ;
array[k] = array[k-1] ;
array[k-1] = temp ;
k -- ;
}else
break ;
}
}
mids[i] = array[s+mid-1] ;
}
int x = selectMid(mids,0,partion-1);
delete []mids ;
return x ;
}
int select(int *array,int start, int end,int i )
{
if(array == NULL || start > end || i <= 0 || i > (end - start+1))
{
failed = true ;
return -1 ;
}
failed = false ;
int x = selectMid(array,start,end);
//对数组进行分组
int len = end - start + 1 ;
int tmp = 0 ;
int f = start ;
int tk = i ;
int samenum = 0 ;
for(int k = start ; k <= end ; k ++ )
{
if(array[k] < x)
{
tmp = array[k] ;
array[k] = array[f] ;
array[f] = tmp ;
f ++ ;
}else if(array[k] == x )//如果是有相等
{
tmp = array[k] ;
array[k] = array[f] ;
array[f] = tmp ;
f ++ ;
samenum ++ ;
}
}
if( (f-start) == i)
{
return array[f-1] ;
}
if( (f-start) > i )
{
end = f-2 ; //要将x去掉。
}else
{
i = i + start ;//这个地方出现过错误,就是边界很难考虑周全了。
start = f ;
tk = i - start ;
}
x = select(array,start,end,tk);
return x ;
}
int main()
{
int array[10] = {1,2,3,9,5,6,7,8,9,9};
for(int i = 1 ; i<=10 ; i ++ )
cout<<select(array,0,9,i)<<endl;
system("pause");
return 0 ;
}