记录一下两个跟分治比较相关的排序---归并排序和快速排序,两种排序都采用分而治之的思想,将一个问题分为连个子问题,先解决局部有序,然后实现整体有序,两种方法有着比较多的共同之处,平均复杂度都在Onlogn,是比较高效的排序方法。
快速排序 quick_sort()
思路
快速排序会选择一个标准点key(下面都这样称呼),然后将所有比他小的移动到左边,所有比他大的移动到他的右边,那么这时候,只要左边区间实现了有序,右边区间也实现了有序,那么整体就是有序的了。
就用升序排序举个最简单的栗子:
这是第一轮时候的样子,一般情况下我们会就把第一个作为我们的key,这里也就是i所对应的2,然后我们会先从j开始搜索(后面会解释一下为什么一定要从j开始,不能从i开始),我们的目标是需要找到一个比2小的,于是就会变成这样
可以看到1要比2小,于是停下了,这时候i开始向右寻找,找到了4比2大,于是也停下了,
这时候把i和就所对应的数字交换
然后继续第二轮寻找,这时候在j找完之后就会变成这样
发现j和i一样了,这时候就表明探测已经结束了,这时候左边第二个(除去key点)到i一定都是比key小的,后面都是比key大的,然后再把key点2与ij所在的点交换,这一轮探测就结束了,
可以看到序列有序了。
这个其实就是一个问题的比较简单的一个子问题,解决了所有这样的子问题之后,其实整个序列也就有序了。
那么子问题反映在程序中其实就是递归的使用,这里我们把key值换到了ij位置,i和j相同的,左边都比key小,右边都比key大,所以只要key值(ij位置)的左边和右边都有序,那么整体就是有序的,也就是对左边和右边再使用queck_sort()。
下面讨论一下开始为什么要强调一定要从j开始探测,我一定要从i开始不行吗?还真不可以,来看一下下面这个栗子:
就像上面这种情况,这时候你如果从i开始探测,那么找到第一个比3大的,一定是4,这时候ij相同,探测结束了,把3和4交换,
这时候你一看,啥呀这完全没有实现我们预期的目标,4最大反而到了第一个。
那么为什么会这样?主要就是因为要想最后让key点归位,这时候你需要ij位置的数和key换位置,我们选择了最左边的位置为key,那么也就是把一个比key小的换过来(左边的数字都小于key),但是你如果用i先去找,那么不可避免这时候i会找到后面比他大的,这时候撞上j,就结束探测了,这时候i就会停在比key大的位置(上图),也就导致最终把一个比key大的换到了左边,当然也就错了。但是j先找,就不会,因为j一定是找到比key小或者i才会停,不会影响最终的结果。如果是右边为key反一反就好。
贴一个gif
下面推荐一个博文,感觉讲的很不错
快速排序(详细讲解)_梦里Coding的博客-CSDN博客_快速排序
最后快速排序之所以叫做快速排序,不仅因为其复杂度低,同时因为其写法中都是while这样的循环,执行速度也很快,是最常用的排序方法之一(似乎c++的sort函数就是快排?)。
有时间写一下归并排序。
参考代码
#include<stdio.h>
int a[] = { 0,1,5,7,4,2,3,6,6,7,5,3,2,6,0,1,1,1,9,2,1,1,8,9,3,2,1 };
int n = sizeof(a) / sizeof(a[0]) - 1;
void print() {
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
printf("\n");
}
void swap(int i, int j) {
int x = a[i];
a[i] = a[j];
a[j] = x;
}
//quick_sort()
void quick_sort(int l, int r) {
if (l<1 || r>n || l > r)return;//无效
if (l == r)return;//已经有序
//if (r - l == 1) {//两个的情况应该时不需要判断的
// if (a[l] > a[r])swap(l, r);
// return;
//}
int x = a[l];
//左边第一个为基准点,那么必须要j先出发
int i = l, j = r;
while (i < j) {
while (a[j] >= x && i < j)j--;
while (a[i] <= x && j > i)i++;
swap(i, j);
}
swap(i, l);//结束探测,枢轴归位
quick_sort(l, i - 1);
quick_sort(j + 1, r);//继续排序
}
int main()
{
printf("排序前:");
print();
quick_sort(1,n);
printf("排序后:");
print();
return 0;
}