经典快排代码-C语言-参考菜鸟教程
void quick_sort(int s[], int l, int r)
{
if (l < r)
{
//Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j] >= x) // 从右向左找第一个小于x的数-(后续改变的查找条件)
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;//填坑
quick_sort(s, l, i - 1); // 递归调用
quick_sort(s, i + 1, r);
}
}
关于排序算法的稳定性解释
简单讲就是待排数组中存在相同值的元素在排序后相对位置保持不变就是稳定的
例如 待排数组 [2,1A,1B,3] 其中1A和1B值为1,为了区分所以后缀字母
排序后为[1A,1B,2,3] 就是稳定的排序,反之[1B,1A,2,3]为不稳定排序
在快速排序中,关键之一就是“填坑操作”,其是不稳定排序算法。
最开始时,我的理解方向是,我们可以自己操作代码中的“查找条件”来控制其稳定性,即控制“等于状态”的不同操作方式(跳过或者置换)以试图控制其稳定性。这是错误的,下面简述验证过程。
依然以数组 [2,1A,1B,3]为例,讨论两种情况
①改变查找条件,在两个值相等时执行跳过操作
2 1A 1B 3 待排数组
1B 1A 1B 3 (2为基准,在第一次从右向左扫描后,1B小于2,将1B填入2的位置)
1B 1A 2 3 填坑,第一次排序完成
可以看到 此时已经不稳定了 之后对 [1B,1A] 和 [3] 进行排序
1B 1A (1B为基准,1A等于1B,执行跳过操作,j-- ,i==j,于是排序完成)
最后排序结果为[1B,1A,2,3],为不稳定
②在两个值相等时执行置换操作
第一次排序结果相同
第二次排序
1B 1A (1B为基准,1A等于1B,即将执行置换操作)
1A 1B
最后排序结果为[1A,1B,2,3],为稳定排序
那在②情况下设置待排序数组为【1,2A,2B,3】,验证其稳定性
排序过程
1 2A 2B 3 (1为基准,第一次排序完成)
2B 2B 3 (2A为基准,2A等于2B,已经置换,2B已经填入2A,排序完成的1不写出)
2B 2A 3 (在原来2B位置填入2A)
1 2B 2A 3 (最后结果)
显然此时是不稳定排序
上诉的两种策略对应代码中的操作条件即“>=”和“>”的区别
综上,不论哪种代码逻辑,快速排序都不能保证对任意数组的排序稳定性,时而稳定时而不稳定,不同数组呈现的稳定性不同,所以是不稳定的
仅供参考