1. 快速排序也采用了分治思想,下面是对子数组A[p..r]进行快速排序的三步分治过程:
分解:数组A[p..r]被划分为两个子数组(可能为空)A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每
一个元素都小于等于A[q],而A[q]也小于等于A[q+1..r]中的每一个元素。其中,计算
下标q也是划分过程的一部分。
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序。
合并:因为子数组都是通过原址排序的,因此不需要合并操作
伪代码实现快速排序:
QUICK-SORT(A,p,r)
ifp < r
q= PARTITION(A,p,r)
QUICK-SORT(A,p,q-1)
QUICK-SORT(A,q+1,r)
PARTITION过程实现了对子数组A[p..r]的原址重排:
PARTITION(A,p,r)
x= A[r]
i= p – 1
forj = p to r – 1
ifA[j] <= x
i= i + 1
exchangeA[i] and A[j]
exchangeA[i + 1] and A[r]
returni + 1
分析:该过程选择A[r]作为主元,并围绕它来划分子数组A[p..r]。for循环中的每一区域均满足循环不变量,即对于任意的下标k,存在:
(1) 若p <= k <= i,则A[k] <=A[r]
(2) 若i + 1 <= k <= j – 1,则A[k] > A[r]
(3) 若k = r,则A[k] = x
在最后两行中,通过将主元与最左的大于x的元素进行交换,就可以将主元移到它在数组中的正确位置上,并返回主元的新下标。
2. 快速排序的性能
快速排序的运行时间依赖于划分是否平衡,如果是平衡的,则快速算法性能与归并排序一样,如果不平衡,则性能接近于插入排序。
3. 快速排序的程序代码:
#include<stdio.h>
//对R[i..j]做划分,并返回基准记录的位置
intPartition(int *R,int i,int j)
{
int pivot=R[i]; //用区间的第一个记录作为基准
while (i<j) //从区间两端交替向中间扫描,直至i=j为止
{
while (i<j &&R[j]>=pivot) //pivot相当于在位置i上
{
j--; //从右至左扫描,查找第一个关键字小于pivot的记录R[j]
}
if (i<j)
{
R[i++]=R[j];
}
while (i<j &&R[i]<=pivot)
{
i++;
}
if (i<j)
{
R[j--]=R[i];
}
}
R[i]=pivot;
return i;
}
voidQuickSort(int *R,int low ,int high)
{
int pivotpos;
if (low<high)
{
pivotpos=Partition(R,low,high);
QuickSort(R,low,pivotpos-1);
QuickSort(R,pivotpos+1,high);
}
}
intmain()
{
int S[10]={23,12,4,8,11,3,34,15,2,1};
QuickSort(S,0,9);
for (int i=0;i<10;i++)
{
printf("%d ",S[i]);
}
printf("\n");
}
4. 快速排序的随机化版本
/************************************************************************/
/*
快速排序算法:
分解:数组A[p..r]被划分为两个子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]
中的每一个元素都小于等于A[q],而A[q]也小于等于A[q+1..r]中的每个数。
其中,计算下边q也是划分过程的一部分
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序
合并:因为子数组都是原址排序的,所以不需要合并操作,数组A[p..r]已经有序
QUICKSORT(A,p,r)
if p<r
q=PARTITION(A,p,r)
QUICKSORT(A,p,q-1)
QUICKSORT(A,q+1,r)
PARTITION过程实现了对子数组A[p..r]的原址重排
PARTITION(A,p,r)
x=A[r]
i=p-1
for j=p to r-1
if A[j]<=x
i=i+1
exchange A[i] withA[j]
exchange A[i+1] with A[r]
return i+1
快速排序:最坏运行时间是O(n^2),期望的运行时间为θ(nlgn)
*/
/************************************************************************/
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
intnum=10;
voidswap(int *a,int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
voidPrintArray(int arr[])
{
for (int i=0;i<10;i++)
{
printf("%d",arr[i]);
}
}
intPartition(int *arr,int beg,int end)
{
int j;
int sentline1=arr[end];
int i=beg-1;
for (j=beg;j<=end-1;j++)
{
if (arr[j]<=sentline1)
{
i++;
swap(&arr[i],&arr[j]);
}
}
swap(&arr[i+1],&arr[end]);
printf("\n排序过程:\n");
PrintArray(arr);
return i+1;
}
intRadomPartition(int *arr,int beg,int end)
{
int i=beg+rand()%(end-beg+1);
swap(&arr[i],&arr[end]);
return Partition(arr,beg,end);
}
voidRandomQuickSort(int *arr,int beg,int end)
{
if (beg<end)
{
intpivot=RadomPartition(arr,beg,end);
printf("\n随机选择 arr[%d](%d)",pivot,arr[pivot]);
RandomQuickSort(arr,beg,pivot-1);
printf("\n随机选择 arr[%d](%d)",pivot,arr[pivot]);
RandomQuickSort(arr,pivot+1,end);
}
}
intmain()
{
int i;
int arr[10];
srand(time(0));
for (i=0;i<10;i++)
{
arr[i]=rand()%100+1;
}
printf("初始数组:");
PrintArray(arr);
RandomQuickSort(arr,0,9);
printf("\n最后结果:");
PrintArray(arr);
return 0;
}