最坏情况下做O(n)选择

看来编程技术还有待提高,尤其是一个思维模式要待提高。

前一个选择,即随机选择一个数作为分割点可能会造成最坏情况也为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 ;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值