【图文并茂的算法】-快速排序算法

450 阅读4分钟

快速排序算法是分治算法技术的一个实例,也称为分区交换排序。快速排序采用递归调用对元素进行排序,是基于比较的排序算法中的一个著名算法,也是面试常考的一个算法。

本文主要思想借鉴于这篇文章:

白话经典算法系列之六 快速排序 快速搞定 blog.csdn.net/morewindows…

时间复杂度:

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1) 性能:

假设快速排序的复杂度为T(n) 且所有元素都不相同。T(n) 取决于两个子问题的规模,而规模又取决于中枢点。

  • 最好情况:每个划分把数组分成相等的两部分。时间复杂度为(nlogn);
  • 最坏情况:每个划分把数组分成不相等的两部分。时间复杂度为(n^2),最坏情况发生在序列已经排序且选择最后一个元素作为中枢点。若初始序列有序则会退化为选择排序。
  • 平均情况下的时间复杂度与最好情况一样也为(nlogn);

基本思想:

书上说该算法主要由以下四步组成:

  1. 如果数组中仅有一个元素或者没有元素需要排序,则返回。
  2. 选择数组中的一个元素作为中枢点(通常选择数组最左边的元素)。
  3. 把数组分成两部分,一部分元素大于中枢点,一部分元素小于中枢点。
  4. 对两部分数组递归调用该算法。

借鉴参考文章,在这里我们巧妙的把它翻译为这样一种思想:

挖坑填数、分而治之。

操作过程如下:

假设有如下数组,且拟定有一个数组 A[4,6,2,9,1,17] ,下标为index,和两个指针 left 和 right,和一个保存中枢点的变量 temp。

初始时,取第一个元素为中枢点,此时:left = 0; right = 5; temp = A[left] = 4; 这里写图片描述

由于已经将A[0]中的数保存到temp中,可以理解成在数组A[0]上挖了个坑,可以将其它数据填充到这来。

1、首先从右向左,寻找第一个比temp小的数,准备填充到A[0]的位置上。 当right=4时满足情况,于是将A[4] 挖走,填充到上一个坑A[0]处,并且left++;此时:left=1;right=4;temp=4;形成新坑A[4]。 这里写图片描述

2、开始从左往右,寻找第一个比temp大的数,准备填充到A[4]的位置上。当left=1时,便满足条件,于是将A[1]挖走,填到上一个坑A[4]处,并且right--;此时:left=1;right=3;temp=4;形成新坑A[1]; 这里写图片描述

3、开始从右往左,寻找第二个比temp小的数,准备填充到A[1]的位置上。 当right=2时满足情况,于是将A[2] 挖走,填充到上一个坑A[1]处,并且left++;此时:left=2;right=2;temp=4;形成新坑A[2]。 这里写图片描述

4、此时left=right,则第一趟排序结束,将temp填充到中枢点index=2的位置上,可以看到,4的左边都比4小,右边都比4大。 这里写图片描述

5、得到新的中枢点后,递归对左边和右边重复上述过程即可完成整个排序。

对挖坑填数进行总结(引用自上述参考文章):

1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。 2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。 3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。 4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。

算法实现(java):

	public static void sort(int[] A,int l,int r){
		int left=l;
		int right=r;
		// index为下标,temp用来保存中枢位置的值,无关数组A,只是一个临时变量而已
		int index,temp;
		
		if(A.length==0 || A.length==1){return;}
		if(left>right){return;}
		//选取中枢,通常选择最左边的元素
		temp=A[left];	
		while(left < right){
		//先从右向左找不大于temp的元素
		 while(left < right && A[right] > temp){  
			 right--;
		 }	
		 if(left < right){
			//挖right,填left
			A[left]=A[right];  
			//填完之后,left右移一位        
			left++;                   
		 }
		 //再从左向右找不小于temp的元素来填上一个坑
		 while(left < right && A[left] <= temp){  
			 left++;
		 }
		 if(left < right){
			 //挖left,填上一次的right
			 A[right]=A[left];   
			 //填完之后,right左移一位        
			 right--;					
		 }
		}
		//走到这一步,必然left==right,得到中枢位置,将temp插入中枢位置
		A[left]=temp; 	
		//下标index						
		index=left;					
		//执行完一次排序操作,再对左边和右边分别递归
		sort(A,l,index-1);
		sort(A,index+1,r);
	}

测试程序:

public static void  main(String[] arg){
		// TODO Auto-generated method stub
		int[] A=new int[]{1,4,2,8,5,9,477,25,1};
		
		long time=System.nanoTime();
		sort(A, 0, A.length-1);
		System.out.println("耗时:"System.nanoTime()-time);
		for (int i : A) {
			System.out.println(i);	
		}
	}

打印内容如下:

1
1
2
4
5
8
9
25
477


QQ(裙):985600592