快速排序:
基本原理:快速排序也是基于分治模式的。
分治过程的三个步骤:
分解:数组A[p...r]被划分成两个(可能空)子数组A[p..q-1]和A[q+1...r],使得A[p..q-1]中的每个元素都小于等于A(q),而且,小于等于A[q+1..r]中的元素。下标q也在这个划分过程中进行计算。
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1...r]排序。
合并:因为两个子数组是就地排序的,将它们的合并不需要操作:整个数组A[p...r]已排序。
平均运行时间:O(nlgn),最坏情况运行时间为O(n^2)。
以上摘自《算法导论》
一个版本代码实现:
#include<stdio.h>
#define N 50
int A[N] ;
int Partition(/*int *A*/int p,int r) ;
void QuickSort(/*int *A*/int p,int r) ;
int main(void)
{
int i,n ;
freopen("in.txt","r",stdin) ;
while(scanf("%d",&n) != EOF)
{
for(i = 0 ; i < n ; ++i)
{
scanf("%d",&A[i]) ;
}
printf("You had input the List:\n") ;
for(i = 0 ; i < n ; ++i)
{
printf("%-3d",A[i]) ;
}
printf("\n") ;
QuickSort(/*A*/0,n-1) ;
printf("After Sort:\n") ;
for(i = 0 ; i < n ; ++i)
{
printf("%-3d",A[i]) ;
}
printf("\n\n") ;
}
return 0 ;
}
int Partition(/*int *A*/int p,int r)
{
int x = A[r] ;
int i,j,nTemp ;
i = p - 1 ;
for(j = p ; j < r ; ++j)
{
if(A[j] <= x)
{
i++ ;
nTemp = A[i] ;
A[i] = A[j] ;
A[j] = nTemp ;
}
}
nTemp = A[i+1] ;
A[i+1] = A[r] ;
A[r] = nTemp ;
return i+1 ;
}
void QuickSort(/*int *A*/int p,int r)
{
int q = 0 ;
if(p < r)
{
q = Partition(p,r) ;
QuickSort(p,q-1) ;
QuickSort(q+1,r) ;
}
}
这个版本对于我来说比较好理解,特别是Partition这个函数。它将数组分为4个区间,一个是元素比主元小的区间,一个是元素比主元大的区间,一个是元素未进行与主元比较的区间,一个是主元区间。(《算法导论》有图解,更清晰)
Partition这个函数其实很好用,今天在其它地方看到两个面试题,其中一个大概就是:对一个包含正负数的数组进行处理,处理完毕之后要求全部负数在全部正数左边。时间复杂度要求O(n),空间复杂度O(1)。
思路:其实就是对0的Partition。不过,也有其它方法,之前写过,就不再提了。
另外一个面试题就是包含奇偶数的,也是要进行分开。其实也是一样的道理。
下面附上另外一个快速排序的版本,自己压根没理解:
void qsort(int lt,int rt)
{
int i,j,mid,t;
i = lt;
j = rt;
mid = a[ (lt + rt) / 2 ];
do
{
while (a[i] < mid && i<rt) ++i;
while (a[j] > mid && j>lt) --j;
if (i<=j)
{
t = a[i];a[i] = a[j];a[j] = t;
++i;--j;
}
}while (i<=j);
if (i<rt) qsort(i,rt);
if (j>lt) qsort(lt,j);
}