基本思想
1、先从序列中选取一个数作为基准元素,然后以此基准元素为标准,将待排序序列分割成两个子序列,其中一个序列的数据都比另一个序列的数据小(以基准元素为界限)
2、分别对已经分好的两个子序列再做快速排序 ----> 递归实现
3、当所有的子序列都有序的时候,整个序列也就有序了 ----> 原地排序,无需辅助空间数组
基准元素的选取方法
1、取第一个元素
2、取最后一个元素
3、取中间位置元素
4、取第一个、最后一个、中间位置元素三者之中位数
5、取第一个和最后一个之间位置的随机数k(low ≤ k ≤ high)作为基准元素的下标 ----> 多用几次rand()函数,然后取平均值
注:如果基准元素选取不当,快速排序有可能退化成冒泡排序
复杂度
最好时间复杂度是O(nlogn),其对应的空间复杂度为O(logn) ----> 选取的基准元素每次均将问题分解为两个规模为n/2的子问题(T(n) = 2T(n/2) + O(n),n > 1 )
最坏时间复杂度是O(n2),其对应的空间复杂度为O(n) ----> 每次选取的基准元素有一侧没有元素(T(n) = T(n - 1) + O(n),n > 1)
平均时间复杂度是O(nlogn),其对应的空间复杂度为O(logn)
图解
[注]:本处没有在序列中采用三杯水交换的方法是因为用一个变量保存基准元素后,在排完序之后只需把基准元素放入自己应在的位置中即可(即 low == high 处),可以减少数据的赋值次数,从而减少时间的开销
C语言代码
#include <stdio.h>
#include <stdlib.h>
//函数声明
int partition_function(int *, int, int);
int quick_sort(int *, int, int);
int main(int argc, const char *argv[])
{
printf("请输入你要排序的数据个数:");
int data_number = 0;
while(1){
//判断输入的数据类型是否合理
if( 0 == scanf("%d",&data_number) ){
printf("%s(%d):数据类型输入错误,请检查!\n",__FILE__, __LINE__);
return -1;
}
//判断输入的数据大小是否合理
if( data_number < 1 ){
printf("输入的数据大小不合理,请重新输入:");
}else{
break;
}
}
//动态申请内存空间
int *int_data_array = (int *)malloc(sizeof(int) * data_number);
if( NULL == int_data_array ){
printf("内存空间不足,申请失败!\n");
return -1;
}
//内存空间申请成功后输入数据
int i = 0;
printf("请依次输入数据:");
for(i = 0; i < data_number; i++){
scanf("%d",int_data_array + i);
}
if( 0 == quick_sort(int_data_array, 0, data_number - 1) ){
printf("排序完成!\n");
printf("排序后数据如下:");
for(i = 0; i < data_number; i++){
printf("%-5d",*(int_data_array + i));
}
printf("\n");
}else if( 1 == quick_sort(int_data_array, 0, data_number - 1) ){
printf("仅有一个数据[ %d ],无需排序!\n",*(int_data_array));
}else{
return -1;
}
//释放刚申请的内存空间
free(int_data_array);
int_data_array = NULL;
return 0;
}
//定义划分函数
int partition_function(int *p_array, int low, int high){
if( NULL == p_array ){
printf("%s(%d):入参为空,请检查!\n",__FILE__, __LINE__);
return -1;
}
//设定基准元素
int pivot = *(p_array + low);
while( low < high ){
//从右向左扫描
while( low < high && pivot <= *(p_array + high) ){
high--;
}
//判断出while循环时是否因为条件 pivot <= *(p_array + high) 不满足
if( low < high ){
*(p_array + low) = *(p_array + high);
low++;
}
//从左向右扫描
while( low < high && pivot >= *(p_array + low) ){
low++;
}
//判断出while循环时是否因为条件 pivot >= *(p_array + low) 不满足
if( low < high ){
*(p_array + high) = *(p_array + low);
high--;
}
}
//出while循环时 low == high
*(p_array + low) = pivot;
return low;
}
//快速排序递归函数
int quick_sort(int *p_array, int low, int high){
if( NULL == p_array ){
printf("%s(%d):入参为空,请检查!\n", __FILE__, __LINE__);
return -1;
}
if( low == high ){
return 1;
}else if( low < high ){
int ret = 0;
ret = partition_function(p_array, low, high);
//递归处理
quick_sort(p_array, low, ret - 1);
quick_sort(p_array, ret + 1, high);
return 0;
}else{
return -1;
}
}
程序运行结果
快速排序和归并排序(合并排序)的区别
快速排序是原地排序,无需辅助空间(辅助数组),但分解困难,合并容易 ----> “先苦后甜”行
归并排序(合并排序)是异地排序,需要额外的辅助空间(辅助数组),但分解容易,合并困难 ----> “先易后难”型
[注]:参考文献:《趣学算法》陈小玉著