众所周知,选择、冒泡排序的时间复杂度是O(n^2),而所谓的快速排序,时间复杂度只有O(n*logn),那什么是快速排序呢,下面就跟着小编一起来探究吧!(点赞更新非递归方法哦😬)
封面选的好,绅士少不了😏
目录
一.排序原理
假设有一串无规律的数字,现在需要我们把它从小到大依次排好,根据快速排序的原则,我们可以这样进行:
1.随便找出一个数a,比它小的在它左边,大的在它右边,不管是左边还是右边都不需要有序排好。
2.在a的左边再找一个数b,a的右边找一个数c,b和c重复1.的步骤(分治、递归)
上图一眼懂:
二.代码实现
快速排序的代码可以分为两个大部分,一是找出一个数把大的放左边小的放右边,二是把一步骤进行递归直到只剩一个数。
一步骤我们可以用挖坑法来解决,选择数组中最左边的值做坑位(你定义的那个中间值)。定义两个变量,一个指向数组中坑位的下一个下标left,一个指向数组尾部下标right。先进行right与坑位的对比,如果right小的话就与坑位交换,坑位指向right,right再减1;之后进行left与坑位的比较,left大的话就与坑位交换,坑位指向left,left加1。之后再进行right的比较,left的比较,直到left>=right为止。
二步骤就是在一步骤结束后进行分治递归,但数组要被拆分成两部分,一部分是数组开头到坑位(你定义的数字最终在的下标),即坑位左边;另一部分是坑位的右边。递归的结束条件就是数组只剩下一个数为止。
上代码:
void quickSort(int* a, int left,int right)//快速排序
{
if (left >= right) return;//递归返回条件,只剩下一个数值
int pivot=left,begin=left,end=right, key = a[pivot];//pivot:坑 , key:所选择的数值
while (begin < end)//选择一个数值key,左边放小于其的,右边放大于其的
{
while (begin < end && a[end]>=key)//两个条件要同时满足,若只有后者则会出现end 小于begin了,却把小数放在右边的情况
{
end--;
}
a[pivot] = a[end];//把小的数放入坑内
pivot = end;//坑的位置变成了key数值右边的
while (begin < end && a[begin] <= key)
{
begin++;
}
a[pivot] = a[begin];
pivot = begin;
}
a[pivot] = key;//把key放入最终的坑中
quickSort(a, left, pivot - 1);//递归最终key左边的
quickSort(a, pivot + 1, right);//递归最终key右边的
}
三.拓展
(一)我们在实现每一次排序时除了用挖坑法还可以用前后指针法,实现方法如下:
1.选择左边的数做中间数key,定义两个变量(front,back)同时指向最左边的下一位,进行front与key的比较,如果小就进行front与back的交换,然后都加一;如果大的话就front加一,直到front走到数尾为止。
代码献上:
void quickSort_fnb(int* a, int left, int right)//前后法快排
{
if (left >= right) return;
int front = left + 1, back = left + 1;
while (front <= right)
{
while (front <= right && a[front] > a[left]) front++;
if (front <= right)
{
swap(&a[back], &a[front]);
back++;
front++;
}
}
swap(&a[left], &a[back - 1]);
quickSort_fnb(a, left, back - 2);
quickSort_fnb(a, back, right);
}
(二).细节优化,三数取中,确保复杂度O(n*logn)
细心的朋友已经发现了,我们每一次选择数字的时候都只能选择最左边的数,那这样就有可能造成选择数字过大或过小举个例子:987654321。我们每次选择的时候最坏一次只能排序一个数字,这样时间复杂度是O(n^2)了!。那么我们该怎么优化呢,通用的做法是选择这个数组中的中间下标数,让它与最左边和最右边的数进行比较,找出三个数中的中间值,与最左边的数交换即可。
代码来了:
int midnum(int* a, int left, int right)//三数取中
int mid = (left + right) >> 1;
if (a[left] < a[mid])
{
if (a[right] > a[mid]) return mid;
else if (a[right] < a[left]) return left;
else return right;
}
else // a[left]>a[mid]
{
if (a[mid] > a[right]) return mid;
else if (a[right] > a[left]) return left;
else return right;
}
return mid;
}
创作不易 多多点赞支持😆, 如有错误,敬请斧正