二路归并排序

交换排序:冒泡排序、快速排序(改进的)

1、基本思想:确定一个基准值,将所有元素划分为两个序列,前一序列元素比基准值小,后一序列元素比基准值大,再对两个子序列进行相同操作,每次划分都将确定一个基准值的最终位置。

2、标准快排(挖坑法)实现步骤:

  • 假设数组为array,将每个序列的 第一个值作为基准值pivot;
  • 初始化i,j:i为第一个元素所在位置,j为最后一个元素所在位置,当前坑为array[i];
  • 如果array[j]>=pivot,那么j--, 否则array[i] = array[j],i++,当前坑为array[j];
  • 如果array[i]<=pivot,那么i++,否则array[j] = array[i],j--,当前坑为array[i];
  • 对于其余子序列也做相同操作,先j变化再i变化,直到i==j为止。

3、代码实现


  
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public  void  quickSort( int[]  array){
     sort( 0, array. length -1, array);
}
private  void  sort( int  left, int  right, int[]  array){
     if( left < right){
         int  pivotPos  =  partion( left, right, array);
         sort( left, pivotPos -1, array);
         sort( pivotPos +1, right, array);
    }
}
private  int  partion(( int  left, int  right, int[]  array){
     int  pivotPos  =  left;   //
     int  pivot  =  array[ left];  //
     int  i  =  left, i  =  right;
     while( i < j){
         while( i < j  &&  array[ j] >= pivot)
          j --;
         if( i < j){
             array[ i=  array[ j];   ji
             i ++;
        }
         while( i < j  &&  array[ i] <= pivot
             i ++;
         if( i < j){
             array[ j=  array[ i];  ij
             j --;
        }
    }
     pivotPos  =  i//i,j
     array[ pivotPos=  pivot;
     return  pivotPos
}

 

4、时间复杂度

(1)最好情况:每次划分都从中间分成相等的两个子序列。每次定位基准值的位置需要的时间为O(n),那么

   T(n) <= cn + 2T(n/2) = cn + 2(cn/2 + 2T(n/4)) = 2cn+4T(n/4)=2cn+4(cn/4+2T(n/8))=3cn+8T(n/8)=cnlogn+nT(1)=O(nlogn)

   从另一个角度来看,快速排序的过程实际就是一棵递归树,树的深度logn就是递归的次数,每次对O(n)个元素排序,所以时间复杂度为O(nlogn);

(2)最坏情况:元素按照正序排列,每次划分后都只排序好基准值左边的序列,需要对右边的序列继续划分,则划分次数总共为n-1次,每次划分需要比较n-k次(1<k<n-1),那么

   T(n) = n-1+n-2+n-3+...+1 = n(n-1)/2 = O(n^2)

(3)平均情况:T(n) = O(nlogn)

5、空间复杂度

每次递归都要是用一个栈,所以空间复杂度为O(logn)

6、稳定性:不稳定

7、改进快排

  改进快排的着手点主要在基准值的选取上,基准值要选取的尽量能将序列划分均匀。

(1)对于每个序列,比较第一个元素、中间元素和最后一个元素的值,取值居中的一个数作为基准值,将第一个数与值居中的这个数交换位置。

代码实现:


  
  
private  int  partion ( int  leftint  rightint[]  array){
     //
     int  mid  = ( left + right)/ 2;
     int  a  =  array[ left];
     int  b  =  array[ right];
     int  c  =  array[ mid];
     int  pivot  =  a > b?( a > c?(( b > c)? b: c): a):( a > c? a:( b > c: c: b));
     int  pivotPos  =  left;
     if( pivot == b)
     pivotPos  =  right;
     else  if( pivot == c)
     pivotPos  =  mid;
     //
     if( pivotPos != left){
         int  temp  =  array[ pivotPos];
         array[ pivotPos=  array[ left];
         array[ left=  temp;
         pivotPos  =  left;
    }
     int  i = left, j = right;
     while( i < j){
         while( i < j  &&  array[ j] >= pivot)
         j --;
         if( i < j  &){
             array[ i=  array[ j];
             i ++;
        }
         while( i < j  &&  array[ i] <= pivot)
         i ++;
         if( i < j){
             array[ j=  array[ i];
             j --;
        }
    }
     pivotPos  =  i;
     array[ pivotPos=  pivot;
     return  pivotPos;
}

(2)对于每个序列,随机选取从头到尾的一个随机数作为基准值,这种排序叫做随机快速排序。

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值