算法:关于快速排序的初步理解,You Know?(小白专用0v0)

125 阅读6分钟

快速排序存在的意义

我们在进行数据处理的时候,要把无序的数据变换成有序的数据,这个时候就需要一些特定的算法来替我们解决问题。比如说大家入门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个数据,那不得墨迹死了.......

630fb225af9cdZFr.gif

哎!所以今天就给大家介绍个比冒泡排序快千百倍的男人快速排序

快速排序的思想

快速排序的核心思想就是四个字:分而治之

简单来说就是在一堆数据里面,找到一个基准点数据(pivot),以这一个基准点为中心,将这一段区域划分为两段不同的区域:在基准点左边的数比基准点小,在右边的比其,划分完毕之后利用递归的方法,再次进入划分,每一次递归都会把一段数据变得有序,最终经过计算机哥哥的重重努力,一段无序的数据就会变得有序啦!

废话不多说直接上例子!

1.png 我们的目的是把这一段数据用快速排序变得有序,我们需要一个基准点数据(pivot)和两个下标(high和low)来做到。基准点是分区的标志。 high和low就是两个下标,用来遍历数组。

2.png 从图中可以看到我们选择的基准点 int pivot=50,我们需要把比50小的数字排在左边,比50大的数字排在右边,那么我们就利用替换的方法,先从a[high]下手,如果a[high]所指向的数字比50小,那么我们就让它赋值给a[low],以达到数值替换的目的。如果a[high]>=50,则我们继续使得high--,直到遇到a[high]所指向的数字<50为止。 (黄色数字是a[high]和a[low]赋值后的数据)

3.png 随后,使得low++,如果a[low]>=50,则让a[high]=a[low],使得数据替换,大的数据在右。如果a[low]<=50,则使得low++,一直找到a[low]>50的数字为止。

!!!在所示的快排算法中当low==high时,初次遍历即结束。(还有更好的快排算法,下次讲0v0)

4.png 分区的逻辑算法:

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; //返回值为基准点的下标
}

就由此一步步反复操作.... 5.png a[high]<50, a[low]=a[high] 6.png low++, a[low]>50, a[high]=a[low] 7.png high--, a[low]=a[high] 8.png 如此循环往复,一直到了low=high的时候,循环结束。 9.png 最后令最初的基准点 pivot覆盖掉a[high](a[low]此时于a[high]相等),就这样第一次分区结束。a[4]左边的数据均比50要小,右边的数据均比50要大,开始火热(有序)了起来呢!hr.jpg 10.png 随后进入递归。

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之后的区域再进行分区排序
	}
}

最后结果如下所示 11.png 恭喜你初步理解了快速排序的思想。离成功人士又进了一步!!!

开心.gif

学习资料来源:【十大排序算法】----冒泡排序(详细图解分析+实现,小白一看就会)-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两姐妹快不少。

新人第一次发作品捏,如有出错欢迎指正,蟹蟹各位大佬智齿!

11.jpg