快速排序
一、概念
基础概念:快速排序,听这个名字就能想到它排序速度比较快方法,是一种分治思想。
所谓分治,就是指以一个数为基准,将序列中的其他数往它两边“扔”。以从小到大排序为例,比它小的都“扔”到它的左边,比它大的都“扔”到它的右边,然后左右两边再分别重复这个操作,不停地分,直至分到每一个分区的基准数的左边或者右边都只剩一个数为止。这时排序也就完成了。
例子:35,22,17,-20,48,99,46
通俗理解:
-
选定一个数作为比较数key(基数),比key小的放左边,比key大的放右边。
选定第一个数:35。 第一趟排序后:-20,22,17,35,48,99,46 -
这个时候key的左边都比key小,但还不是有序。就再次对key的左半部分执行1操作
(下标是:0~3的元素,也就是 -20,22,17 这三个元素,再这三个数中选定一个key,比key小的放左边,比key大的放右边)
排序后:-20,17,22,35,48,99,46 -
对 35 右边的(48,99,46)三个数,执行相同操作
完成排序:-20,17,22,35,46,48,99
二、代码及过程
/**
*
*快速排序
*Date: 2019/4/12
*
***/
#include <stdio.h>
// 快速排序
void quickSort(int *a, int low, int high){ // low是头指针,high是尾指针
int i = low;
int j = high;
int key = a[low]; // 选定基数
if(low >= high){ //说明已经排序完成
return ;
}
while(low < high){ //这层循环每结束一次,就代表完成了一轮排序
// 注意:这里的a[high]必须是“大于等于>=”key,否则遇到与基数相等的数将陷入死循环
while(low < high && a[high] >= key){ // 从最右端开始,找出比key小的值
--high;
}
if(a[high] < key){ // 直接覆盖,不用交换位置
a[low] = a[high];
++low;
}
while(low < high && a[low] <= key){ // 从最左端开始,找出比key大的值
++low;
}
if(a[low] > key){ // 直接覆盖,不用交换位置
a[high] = a[low];
--high;
}
}
a[low] = key; // 第一轮排序完毕,当前位置就是key的位置(左边都是小于key,右边都是大于key)
quickSort(a,i,low-1); //递归调用(排序key左边的子序列)
quickSort(a,low+1,j);
}
// 遍历数组
void show(int *a,int n){
for(int i = 0; i < n; i++){
printf("%5d",a[i]);
}
}
void main(){
int a[] = {35,22,17,-20,48,99,46};
int n = sizeof(a) / sizeof(a[0]); // 数组长度
printf("原数组:\n");
show(a,n);
quickSort(a,0,n-1);
printf("\n排序后的数组:\n");
show(a,n);
printf("\n");
}
三、复杂度
平均时间复杂度: O(nlogn)
空间复杂度: O(nlogn)
四、分析总结
最优情况:
如果待排序列是“升序有序”,如:1,2,3,4,5,6,7
那么,快速排序为最优情况
最糟糕情况:
如果待排序列是“降序有序”,如:7,6,5,4,3,2,1
那么,快速排序为退化为冒泡排序。