算法初步——快速排序
上一节中我们讲到冒泡排序的算法时间复杂度为O(N^2),这是一个比较大的时间复杂度,在算法执行上效率很低。于是我们就想一想有没有既不浪费空间又能提高效率的算法呢,当然,我们找到了一个更为常用的排序算法——快速排序。“快速排序”光听这个名字是不是就很高端呢,接下来我们来看一看该算法如何实现。
假设我们对“6 1 2 7 9 3 4 5 10 8”这10个数进行排序。我们首先要选定一个数作为基准数。我们一般可以选这串数字的第一个数为基准数,紧接着我们要把比6小的数全部移动到6的左边,而比6大的数我们全部移动到6的右边,结果为“3 1 2 5 4 6 9 7 10 8;这时候你一定会好奇我们如何将原来的那串数字变成现在这个样子的,接下来看清楚:我们需要两个变量我们可以称这两个变量为“哨兵i”和“哨兵j”,两个哨兵从两端进行探测,但我们有个原则:哨兵j的级别比哨兵i的级别高,所以它永远先走。我们将哨兵j向前遍历找到第一个比基准数(也就是6)小的数,接下来我们就要让哨兵i向后找到第一个比基准数大的数,将他俩交换;接着哨兵j继续行动探测下一个比基准数小的数,随后哨兵i出击进行探测……当我们发现两个哨兵要接头时,我们将接头位置的数和基准数进行交换(当我们要排序的数串里数字的个数为奇数时,我们则把哨兵i和基准数交换,实际无论是奇数还是偶数,我们只需要将哨兵i和基准数交换即可),这样我们的基准数6就到达了它应该在的位置,接下来进行第二轮的探测。每一轮探测我们将会确定一个基准数的位置,当所有基准数的位置我们都确定之后,我们的排序工作也就完成了。
快速排序之所以比冒泡排序的效率高,是因为冒泡排序处理数据是连续的,而快速排序处理数据是跳跃式的。总的比较和交换次数变少我们的速度自然就变快了。经过我们分析可以知道,快速排序的算法时间复杂度为O(NlogN)。快速排序的原理其实是二分法的应用,我们有机会再详谈。
#include<iostream> using namespace std; int a[101], n; void quicksort(int left, int right) { int t, temp, i, j; if (left > right) return; temp = a[left];//用temp储存下我们的基准数 i = left; j = right;//定义两个哨兵 while (i != j)//开始探测 { //顺序很重要,我们先从后往前探测 while (a[j] >= temp && i < j) j--; //再从前往后探测 while (a[i] <= temp && i < j) i++; //交换过程 if (i < j) { t = a[j]; a[j] = a[i]; a[i] = t; } } //将基准数归位 a[left] = a[i]; a[i] = temp; quicksort(left, i - 1);//接着处理基准数左侧的数据 quicksort(i + 1, right);//处理基准数右侧的数据 return; } int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; } quicksort(1, n); for (int i = 1; i <= n; i++) { cout << a[i] << " "; } cout << endl; return 0; }