快速排序算法——以数组最后一个元素为主元

关于快速排序的认识及其基本特征,请参寻我的另外一篇博文快速排序——以数组第一个元素为主元

以具体的例子,参照July大神博客里给的思路,飞起来——July大神的快排思路


大神博客里给的是伪代码的形式来表述思路,这里我用大白话来解释一下,让大家看起来更放松一些

首先,我们能够确定排序所用的参照系,也就是数组最后一个元素(这里我用temp来表示,程序中同样如此),比较特别的是,我们定义的i和j两个参数都是从要排序的数组段的第一个元素位置开始,以此往右移动。

我们暂且定义i是用来寻找大于temp的参数,j是用来找到小于等于temp的。

从图示中可以看出j总是在i的右侧,因为在左侧的话就没必要执行交换操作了,我们是要把小数交换到左侧,留下大数不动来实现的

下面看程序

package 快速排序2;

public class QuickSort2 {
	
      static int[] arr={2,8,7,1,3,5,6,4};
      static int num=1;
      public static void main(String[] args) {
		quickSort(arr,0,7);
		
	}
      public static void quickSort(int[] arr,int low,int high){
    	  int temp=arr[high];
    	  int i=low,j=low;
    	  int ex;
    	  
    	  while(j<high){
    	  //找到大于temp的数
          while(arr[i]<=temp){
                i++;
                /*
                 * 实在找不到,说明low到high之间没有比arr[high]更大的数了
                 * 也就是说此时temp左边的数都小于等于temp
                 * 此时,本次排序结束,退出循环
                 */
                if(i>=high)break;
          }
    	  //找到小于或等于temp的数
          while(arr[j]>temp||j<i){
        		j++;
        		/*
        		 * 为了防止i=high时,根据j<i就可以继续循环这一条件,j可能大于high,导致溢出
        		 * 所以必须加上下面的条件
        		 */
        		if(j>=high)break;
        		  
          }
          //执行数值交换
          ex=arr[i];
    	  arr[i]=arr[j];
    	  arr[j]=ex;
          }
    	 
    	  System.out.println("第"+num+++"次排序,i在"+arr[i]+"的位置,可见"+arr[i]+"左边的数(有数的情况下)全部小于"+arr[i]+",而其右边的数(有数的情况下)全部大于"+arr[i]);
    	  //遍历输出
    	  each(arr);
    	  //根据条件执行递归调用
    	  if(i-1>low){
    		  quickSort(arr,low,i-1);
    	  }
          if(i+1<high){
        	  quickSort(arr, i+1, high);
          }
    	  
      }
      public static void each(int[] arr){
    	  for(int i=0;i<arr.length;i++){
    		  System.out.print(arr[i]+"    ");
    	  }
    	  System.out.println();
      }
}

大神给出了时间复杂度和空间复杂度的推导方法,不说话,直接拿过来

快速排序的最坏情况和最快情况。

最坏情况发生在划分过程产生的俩个区域分别包含n-1个元素和一个0元素的时候,
即假设算法每一次递归调用过程中都出现了,这种划分不对称。那么划分的代价为O(n),
因为对一个大小为0的数组递归调用后,返回T(0)=O(1)。
估算法的运行时间可以递归的表示为:

    T(n)=T(n-1)+T(0)+O(n)=T(n-1)+O(n). 
可以证明为T(n)=O(n^2)。

因此,如果在算法的每一层递归上,划分都是最大程度不对称的,那么算法的运行时间就是O(n^2)。
亦即,快速排序算法的最坏情况并不比插入排序的更好。

此外,当数组完全排好序之后,快速排序的运行时间为O(n^2)。
而在同样情况下,插入排序的运行时间为O(n)。

//注,请注意理解这句话。我们说一个排序的时间复杂度,是仅仅针对一个元素的。
//意思是,把一个元素进行插入排序,即把它插入到有序的序列里,花的时间为n。

 
再来证明,最快情况下,即PARTITION可能做的最平衡的划分中,得到的每个子问题都不能大于n/2.
因为其中一个子问题的大小为|_n/2_|。另一个子问题的大小为|-n/2-|-1.
在这种情况下,快速排序的速度要快得多。为,
      T(n)<=2T(n/2)+O(n).可以证得,T(n)=O(nlgn)。

直观上,看,快速排序就是一颗递归数,其中,PARTITION总是产生9:1的划分,
总的运行时间为O(nlgn)。各结点中示出了子问题的规模。每一层的代价在右边显示。
每一层包含一个常数c。




  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值