本博文源于浙江大学《数据结构》,快速排序的设计体现了分而治之的思想,如何分而治之在程序中用处比较大。如果粗暴选择,那就会造成O(N^2)的时间复杂度,经过多年来学者的探究,选主元无非这几种情况:
选主元
第一种 随机取
利用rand()函数取,rand函数是c语言产生随机数的一个函数,如果大家对随机数不是非常了解,需要看这篇博主写的文章,较清晰的阐述rand函数使用
(c语言)qsort及rand使用指南(附测试用例)
这里的随机取,无非是用rand取下标,这种因为调用浪费时间,所以很快被淘汰
第二种 三者的中位数
这种取法就是比较,将中位数甩出去,保证分而治之两个都是有序列,不然就出现这种情况,
快速排序算法特点
- 快速排序的趟数取决于递归树的深度。
在这里插入代码片
时间复杂度:nlogn
空间复杂度:log2n 最坏 O(n)
总的关键字比较次数KCN O(n^2/2)
算法特点:
- 记录非顺次的移动导致排序是不稳定的。
- 排序过程中需定位的下界和上界,所以适合用于顺序结构,很难用于链式结构。
- 当n较大,平均情况下快速排序是所有内部排序方法中速度最快的一种,所以其适合初始记录无序,n较大时的情况。
快速排序的缺失
因为采用递归,小规模数据不适宜采用快速排序,利用选择排序就差不多行了,随着要排序的数量不断增大,大规模数据考虑用快速排序
测试用例
int a[MAXN];
srand(time(NULL));
for (int i = 0; i < MAXN; i++)
a[i] = rand()%(1000)+1;
博主是用随机数产生[1,1000]范围之间的随机数,最后将其排序,效果比较显著
效果图
源码(严蔚敏版本)
int Partition(int r[],int low,int high){
r[0] = r[low];
int pivotkey = r[low];
while(low < high){
while(low < high && r[high]>=pivotkey) --high;
r[low] = r[high];
while(low<high && r[low]<=pivotkey) ++low;
r[high] = r[low];
}
r[low] = r[0];
return low;
}
void Qsort(int r[],int low,int high){
if(low<high){
int pivotloc = Partition(r,low,high);
Qsort(r,low,pivotloc-1);
Qsort(r,pivotloc+1,high);
}
}
void QuickSort(int r[]){
Qsort(r,1,4);
}
源码附上(浙大版)
//qsort-1-2.c
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#define MAXN 100
typedef int ElementType;
void Swap(int *X,int *Y)
{
int tmp = *X;
*X = *Y;
*Y = tmp;
}
void InsertionSort(ElementType A[], int N)
{
int i = 0;
for(int P=1;P<N;P++) {
int Tmp = A[P];
for(i = P;i>0 && A[i-1] > Tmp;i--)
A[i] = A[i-1];
A[i] = Tmp;
}
}
ElementType Median3( ElementType A[], int Left, int Right )
{
int Center = (Left+Right) / 2;
if ( A[Left] > A[Center] )
Swap( &A[Left], &A[Center] );
if ( A[Left] > A[Right] )
Swap( &A[Left], &A[Right] );
if ( A[Center] > A[Right] )
Swap( &A[Center], &A[Right] );
/* 此时A[Left] <= A[Center] <= A[Right] */
Swap( &A[Center], &A[Right-1] ); /* 将基准Pivot藏到右边*/
/* 只需要考虑A[Left+1] … A[Right-2] */
return A[Right-1]; /* 返回基准Pivot */
}
void Qsort( ElementType A[], int Left, int Right )
{ /* 核心递归函数 */
int Pivot, Cutoff, Low, High;
if ( Cutoff <= Right-Left ) { /* 如果序列元素充分多,进入快排 */
Pivot = Median3( A, Left, Right ); /* 选基准 */
Low = Left; High = Right-1;
while (1) { /*将序列中比基准小的移到基准左边,大的移到右边*/
while ( A[++Low] < Pivot ) ;
while ( A[--High] > Pivot ) ;
if ( Low < High ) Swap( &A[Low], &A[High] );
else break;
}
Swap( &A[Low], &A[Right-1] ); /* 将基准换到正确的位置 */
Qsort( A, Left, Low-1 ); /* 递归解决左边 */
Qsort( A, Low+1, Right ); /* 递归解决右边 */
}
else InsertionSort( A+Left, Right-Left+1 ); /* 元素太少,用简单排序 */
}
void QuickSort( ElementType A[], int N )
{ /* 统一接口 */
Qsort( A, 0, N-1 );
}
void Print_Array(ElementType A[],int N)
{
for(int i=0;i<N;i++){
printf("%d ",A[i]);
if((i+1)%5==0) printf("\n");
}
}
int main()
{
int a[MAXN];
srand(time(NULL));
for (int i = 0; i < MAXN; i++)
a[i] = rand()%(1000)+1;
QuickSort(a,MAXN);
Print_Array(a,MAXN);
return 0;
}