快速排序存在的意义
我们在进行数据处理的时候,要把无序的数据变换成有序的数据,这个时候就需要一些特定的算法来替我们解决问题。比如说大家入门C语言时都会学的时间复杂度为O(n^2)的冒泡排序:
其通过无序区中相邻关键字的比较与位置交换,使得关键字较小的记录逐渐往上"漂浮",直到"水面"。整个算法从最下面的记录开始,对每两个相邻记录的关键字进行比较,让关键字较小的记录换到关键字较大的记录位置之上,直到数组变成有序为止,具体实现为:
void BubbleSort(int* a, int n)
{
for (int i = 0; i < n; i++) // 决定排序的趟数-->总共n趟
{
for (int j = 1; j < n - i; j++) // 一趟进行比较的次数
{
if (a[j - 1] > a[j]) // 若前一个数比后一个数大,就交换
{
int tem = a[j-1];
a[j-1] = a[j];
a[j] = tem;
}
}
}
}
通过这个办法可以将无序的数据通过从小到大的规律排列起来,使其变得有序。但大家也能看到它循环的次数取决于数字的个数,倘若是1w个数据,10w个数据,100w个数据,那不得墨迹死了.......
哎!所以今天就给大家介绍个比冒泡排序快千百倍的男人:快速排序
快速排序的思想
快速排序的核心思想就是四个字:分而治之
简单来说就是在一堆数据里面,找到一个基准点数据(pivot),以这一个基准点为中心,将这一段区域划分为两段不同的区域:在基准点左边的数比基准点小,在右边的比其大,划分完毕之后利用递归的方法,再次进入划分,每一次递归都会把一段数据变得有序,最终经过计算机哥哥的重重努力,一段无序的数据就会变得有序啦!
废话不多说直接上例子!
我们的目的是把这一段数据用快速排序变得有序,我们需要一个基准点数据(pivot)和两个下标(high和low)来做到。基准点是分区的标志。 high和low就是两个下标,用来遍历数组。
从图中可以看到我们选择的基准点 int pivot=50,我们需要把比50小的数字排在左边,比50大的数字排在右边,那么我们就利用替换的方法,先从a[high]下手,如果a[high]所指向的数字比50小,那么我们就让它赋值给a[low],以达到数值替换的目的。如果a[high]>=50,则我们继续使得high--,直到遇到a[high]所指向的数字<50为止。
(黄色数字是a[high]和a[low]赋值后的数据)
随后,使得low++,如果a[low]>=50,则让a[high]=a[low],使得数据替换,大的数据在右。如果a[low]<=50,则使得low++,一直找到a[low]>50的数字为止。
!!!在所示的快排算法中当low==high时,初次遍历即结束。(还有更好的快排算法,下次讲0v0)
分区的逻辑算法:
int partition(int a[], int low, int high) {
int pivot = a[low];
while (low < high) {
while (a[high] >= pivot && low < high) {
high--;
}
a[low] = a[high];
while (a[low] <= pivot && low < high) {
low++;
}
a[high] = a[low];
}
a[low] = pivot;
return low; //返回值为基准点的下标
}
就由此一步步反复操作....
a[high]<50, a[low]=a[high]
low++, a[low]>50, a[high]=a[low]
high--, a[low]=a[high]
如此循环往复,一直到了low=high的时候,循环结束。
最后令最初的基准点 pivot覆盖掉a[high](a[low]此时于a[high]相等),就这样第一次分区结束。a[4]左边的数据均比50要小,右边的数据均比50要大,开始火热(有序)了起来呢!
随后进入递归。
void Quicksort(int a[], int low, int high) {
if (low < high) {
int pivotpos = partition(a, low, high);//得到基准点下标
Quicksort(a, low, pivotpos - 1);//在50之前的区域再分区排序
Quicksort(a, pivotpos + 1, high);//在50之后的区域再进行分区排序
}
}
最后结果如下所示
恭喜你初步理解了快速排序的思想。离成功人士又进了一步!!!
学习资料来源:【十大排序算法】----冒泡排序(详细图解分析+实现,小白一看就会)-CSDN博客
全网最清晰快速排序,看完快排思想和代码全部通透,不通透你打我!_哔哩哔哩_bilibili
以及Acwing
附上源码:
#include <bits/stdc++.h>
using namespace std;
const int n = 1e6 + 10;
int a[n];
int partition(int a[], int low, int high) {
int pivot = a[low];
while (low < high) {
while (a[high] >= pivot && low < high) {
high--;
}
a[low] = a[high];
while (a[low] <= pivot && low < high) {
low++;
}
a[high] = a[low];
}
a[low] = pivot;
return low;
}
void Quicksort(int a[], int low, int high) {
if (low < high) {
int pivotpos = partition(a, low, high);
Quicksort(a, low, pivotpos - 1);
Quicksort(a, pivotpos + 1, high);
}
}
int main() {
int n ;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d",&a[i]);
}
partition(a, 0, n - 1);//排序,分区
Quicksort(a, 0, n - 1);//递归
for (int i = 0; i < n; i++) {
cout << a[i];
cout << ' ';
}
} //大量数据记得用scanf和printf,这两兄弟比cin和cout两姐妹快不少。
新人第一次发作品捏,如有出错欢迎指正,蟹蟹各位大佬智齿!