目录
一,介绍
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
二,原理
采用分治法的基本思想:
- 1.先从数列中取出一个数作为基准数。
- 2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 3.再对左右区间重复第二步,直到各区间只有一个数。
三,解析
快速排序并不是将小的数插入到基准数前,大的数插入到基准数后,而是通过交换元素位置的方式来实现排序,所以也称之为“舞动排序🔍”。
快速排序简单来说就是确定一组数据中每个数据该去的位置,操作过程分为两步。
第一步,把一组数据以其中的某个数字为基准数,分成大小两部分,然后基准数不动(它的位置已经确定);
第二步,重复第一步的操作,直到整个数据排好为止。
也就是通过把数据中每个数字都做一次基准数,然后确定位置。通过控制基准数左右数字相对于基准数的大小就可以给整组数据按照升序或降序排序。
四,代码实现
1、递归理解版
#include <stdio.h>
//以升序为例
//第一趟排序
//right为数组最高位
//left为数组最低位
int first_sort(int *s,int left,int right){
int flag = s[left];//每次选定传入数据中最左边位置的数为基准数
while (left != right)//当左边和右边都走到一个位置时,基准数位置确定,循环结束
{
//由于基准数为最左边第一位
//所以基准数与数据最右边的数开始比较
while (left < right && s[right] >= flag)//若为降序,改为s[right] <= flag
{
right --;//向左走
}
if (s[right] < flag)//从右往左比时 遇到比基准数小的数
{
s[left] = s[right];//将该位置元素的值赋值给left位置的元素(也就是基准数的位置)
left ++;//最左边的位置的元素已确定,不再参与比较
}
while (left <right && s[left] <= flag)//若为降序,改为s[right] >= flag
{
left++;//向右走
}
if (s[left] > flag)//从左往右比时 遇到比基准数大的数
{
s[right] = s[left];//将该位置元素的值赋值给right位置的元素
right--;//最右边的位置的元素已确定,不再参与比较
}
}
s[left] = flag;//由于在此过程中,采用赋值的方式改变每个位置元素的值
//所以基准数位置的数在第一次赋值时被覆盖
//所以需要在确定好的位置上放入基准数
//由于此时left == right 也可使用s[right] = flag;
return left;
}
//第二趟排序
//递归调用第一趟排序的函数
int quickly_sort(int *s,int left, int right){
if (right >left)
{
int ret = first_sort(s,left,right); //获得第一次排序基准数的位置
quickly_sort(s,left,ret-1);//递归调用,排左边
quickly_sort(s,ret+1,right);//递归调用,排右边
}
}
//打印数组
int print_s(int *s,int n){
int i = 0;
for ( i = 0; i < n; i++)
{
printf("%d ",s[i]);
}
printf("\n");
return 0;
}
int main(int argc, char const *argv[])
{
int s[10] = {50, 34, 5, 32, 16, 67, 99, 45 ,20, 88};
//排序前
printf("排序前>\n");
print_s(s, 10);
quickly_sort(s, 0, 9);
//排序后
printf("排序后>\n");
print_s(s, 10);
return 0;
}
2、简化版
// 快速排序算法
void quick_sort(int arr[], int left, int right) {
if (left < right) {
int i = left, j = right;
int pivot = arr[left]; // 以数组的第一个元素作为枢轴
while (i < j) {
// 将右侧大于枢轴的元素移动到左侧
while (i < j && arr[j] >= pivot) {
j--;
}
arr[i] = arr[j];
// 将左侧小于枢轴的元素移动到右侧
while (i < j && arr[i] <= pivot) {
i++;
}
arr[j] = arr[i];
}
// 将枢轴值放回正确的位置
arr[i] = pivot;
// 递归排序左半部分和右半部分
quick_sort(arr, left, i - 1);
quick_sort(arr, i + 1, right);
}
}
运行结果:
五,快速排序的特点
快速排序是在冒泡排序的基础上改进得到的,冒泡排序每次只能交换相邻的两个元素,而快速排序采用的是跳跃性的交换,减少了没必要的交换过程,因此比较和交换次数相对于冒泡排序减少了很多,提高了时间利用率。因此快速排序的时间复杂度是。
但是快速排序在最坏的情况下的时间复杂度和冒泡排序是一样的,是,也就是每次的比较都需要交换,但是这种情况不常见。
快速排序只是使用数组原本的空间进行排序,所以占用的空间是常量级的,但是由于每次划分后需要递归调用,所以在运行过程中会消耗一定的空间。所以我们一般认为快速排序的空间复杂度为。在最差的情况下,如果每次只是完成了一个元素,则空间复杂度为。
快速排序是一个不稳定的算法,因为在排序之后,可能会对相同值的元素的相对位置造成改变,但快速排序基本上被认为是相同数量级的所有排序算法中,平均性能最好的。