最壞情況下做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 ;
}

 

發佈了31 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章