快速排序及分析

快速排序

用于排序的最佳的实用选择,因其平均性能很好,期望运行时间O(nlog2^n),最坏情况运行时间为O(n^2).

1、快速排序

和合并排序一样,采取分治模式:

  (1)分解:数组A[p..r]被划分为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都小于等于A[q],而A[q+1..r]大于A[q],q在此划分过程中进行计算。

  (2)解决:递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]排序

  (3)合并:两个子数组都是原地排序的,因此合并不需要操作,整个数组就已经排好序

 

伪代码:
  QUICKSORT(A,p,r)
      if p<r then
           q<—PARTITION(A,p,r)
           QUICKSORT(A,p,q-1)
           QUICKSORT(A,q+1,r)

 最初调用QUICKSORT(A,1,A.length).

 其中子程序PARTITION(A,p,r)代码如下,实现对子数组A[p..r]进行重排:

 

//对数组A[p,...,r]进行重排,使得A[p..q-1]中的每个元素都小于等于A[q],而A[q+1..r]大于A[q]
int partition(int a[],int p,int r){
    int key=a[r];
	int index=p-1;
	int temp=0;
	for(int i=p;i<=r-1;i++){
		if(a[i]>key){
		  index++;
		  temp=a[i];
		  a[i]=a[index];
		  a[index]=temp;
		}
	}
	temp=a[index+1];
	a[index+1]=a[r];
	a[r]=temp;
	return index+1;
}

 将A[r]=key作为参照数来进行对比,最后的结果是A[p..q-1]中的每个元素都小于等于key,而A[q+1..r]大于key,而A[q]最后和A[r]交换,并返回q。此子程序的运行时间为O(n),其中n=r-p+1.

2、快速排序的性能

快速排序的运行时间和划分是否对称有关,而后者又和选择了哪一个元素来进行划分比较有关。如果划分对称,渐近意义上,与合并算法(nlog2^n)一样快,不对称时,渐近意义上,和插入算法(n^2)一样慢。

  (1)最坏情况

最坏划分是划分过程中产生的两个区域分别包含了n-1个元素和1个0元素。假设每次递归调用都出现了这种划分,划分的时间代价是O(n),递归树有n层,则算法的运行时间为O(n^2).递归表达式T(n)=T(n-1)+O(n).

  (2)最好情况

最平衡的划分,两个子数组的大小都不可能大于n/2,递归式T(n)<=2T(n/2)+O(n),解为O(nlog2^n).由于每一层递归的划分都是两边对称的,因此,从渐进意义上,算法运行就更快了。

  (3)平衡划分

 平均情况和最佳运行时间很接近

  任何一种按常数比例进行的划分都会产生深度为O(log2^n)的递归树,其中每一层的代价为O(n),因而,当按照常数比例划分时,总运行时间是O(nlog2^n).

3、快速排序的随机化版本

加入随机化部分,以便对于所有的输入,它均能获得较好的平均情况性能。随机化算法使得输入数组不相关,使最坏情况发生的可能性变小。

 

伪代码
RANDOMIZED-PARTITION(A,p,r)
   i<—Random(p,r)
   exchange A[r]<->A[i]
   return PARTITION(A,p,r)

 4、Hoare划分

将数组第一个元素作为对比元素,即主元,用两个指针分别从数组的首尾进行遍历,首指针找到第一个比主元大的元素,尾指针找到第一个比主元小(包括等于)的元素,将两个元素交换,循环进行此过程指导首尾指针相遇,最后的尾指针(包括尾指针)之前是比主元小(等于)的元素,尾指针后是比主元素大的元素,将尾指针位置的元素和主元素交换,并返回尾指针位置。

 

伪代码:
 HOARE-PARTITION(A,p,r)
   x<—A[p]
   i<—p-1
   j<—r+1
   while TRUE
       do repeat j<—j-1
              until A[j]<=x
            repeat i<—i+1
              until A[i]>x
            if i<j
              then exchange A[i]<—>A[j]
            else
              A[p]<—>A[j]
              return j
c代码
int hoare_partition(int a[],int p,int r){
	int temp=0;
        int key=a[p];
	int i=p-1;
	int j=r+1;
	while(true){
		do{
		    j--;
		}while(a[j]>key);
		do{
		   i++;
		}while(a[i]<=key);

		if(i<j){
		   temp=a[i];
		   a[i]=a[j];
		   a[j]=temp;
		}
		else{
			temp=a[p];
			a[p]=a[j];
			a[j]=temp;
			return j;
		}

	}
}

 此划分算法的运行时间为O(n),n=r-p+1.

 

你可能感兴趣的:(快速排序)