快速排序(快排)的一些细节和k-th问题
来源:互联网 发布:成都广电网络 编辑:程序博客网 时间:2024/06/05 09:29
对算法竞赛而言,轴点的选取不是关键,算法的细节和程序才是重点,而在应用快排的副产品k-th元素问题中,这个细节尤为重要。网络上鲜有这些细节描述,谨以记之。
快排的不同写法
主要用两种写法:标准快排和“两头”交换写法,竞赛中以后者居多。
标准写法
void quick_sort(int l, int r){ int i = l, j = r, x = s[l]; while (i < j) { while(i < j && s[j] > x) j--; if(i < j) s[i++] = s[j]; while(i < j && s[i] < x) i++; if(i < j) s[j--] = s[i]; } s[i] = x; if (l<i) quick_sort(l, i - 1); if (r>i) quick_sort(i + 1, r);}
第6行内层循环中的while测试是用“严格大于/小于”还是”大于等于/小于等于”。
一般的想法是用大于等于/小于等于,忽略与枢纽元相同的元素,这样可以减少不必要的交换,因为这些元素无论放在哪一边都是一样的。但是如果遇到所有元素都一样的情况,这种方法每次都会产生最坏的划分,也就是一边1个元素,令一边n-1个元素,使得时间复杂度变成
另一个因素是,如果将枢纽元放在数组两端,用严格大于/小于就可以将枢纽元作为一个哨兵元素,从而减少内层循环的一个测试。
由以上两点,内层循环中的while测试一般用“严格大于/小于”。
这个算法的妙处在于第14行放置
“两头”交换(这应该是Hoare提出的最早的快排划分法,算导说的)
void sort(int left, int right) { int i = left, j = right, x = a[(i+j)>>1], tmp; while (i<=j) { while (a[i] < x) i++; while (a[j] > x) j--; if (i<=j){ tmp = a[i]; a[i] = a[j]; a[j] = tmp; i++; j--; } } if (left<j) sort(left, j); if (right>i) sort(i, right);}
- 对于两头交换法,每次可以交换两个数到正确区段,似乎效率更高,但是实际上,效率并不比标准算法高
- 第3行循环的条件一般要取“=”,即指向同一元素时再比一次,以便分成两段
- 第6行交换的条件必须取“=”,以便分成两段
- 倘若第3行取了“=”,而第6行没有取“=”,此时while将会造成死循环
- 对于第4、5行的
i,j 的移动来说,条件中不能取“=”。若轴点刚好是序列的最大值,那么i,j 的值将会下标越界
k-th问题
这里的k-th问题,简单的指将所有元素非降排序后,位于第
标准写法的演化版
由标准写法的第14行可知,若此时
int findKth(int left, int right){ int i = left, j = right, x = s[left]; while (i < j) { while(i < j && s[j] > x) j--; if(i < j) s[i++] = s[j]; while(i < j && s[i] < x) i++; if(i < j) s[j--] = s[i]; } s[i] = x; if (k==i) return s[i]; if (left<i && k<i) return findKth(left, i - 1); if (right>i && k>i) return findKth(i + 1, right);}
两头交换的演化版
这个版本的轴点元素可能并不一定在原先位置,因此要循环到区间内只有一个元素为止。
int findKth(int left, int right) { if (left == right) return a[left]; int i = left, j = right, x = a[(i+j)>>1], tmp; while (i<=j) { while (a[i] < x) i++; while (a[j] > x) j--; if (i<=j){ tmp = a[i]; a[i] = a[j]; a[j] = tmp; i++; j--; } } if (left<=j && k<=j) return findKth(left, j); if (right>=i && k>=i) return findKth(i, right); return x;}
参考:
http://blog.csdn.net/shuangshuang37278752/article/details/8992119
- 快速排序(快排)的一些细节和k-th问题
- TOP-K问题-堆排序和快排实现
- 快排 和 堆排序算法的细节代码分析
- 快排 快速排序
- Erlang的算法-(一)递归快速排序和MapReduce分布式的快排
- 快速排序的实现(快排)
- 快速排序 改进快排的方法
- 快速排序 改进快排的方法
- 快速排序 改进快排的方法
- 快速排序的一些实现技巧(曾经被手写快排打倒过n+1次。。。)
- HDUOJ 1234开门人和关门人问题(快排及快排的二级排序)
- QuickSort/快速排序/快排
- 快速排序算法(快排)
- [算法]快排-快速排序
- Java 快速排序 快排
- [模板]快速排序(快排)
- 单链表的排序(归并和快排)
- 快排和归并排序的比较
- 旅行 纪中1281 vijos 1661
- yii2项目实战-访问控制过滤器ACF讲解
- BroadcastReceiverPractive
- filter 过滤器实现自动登录功能
- 关于程序自动安装软件的一些问题1
- 快速排序(快排)的一些细节和k-th问题
- 剑指offer:判断二叉树是不是平衡二叉树(java)
- 习题8.9
- 1006
- 漫谈四种神经网络序列解码模型
- 谷歌插件postman的安装
- Codeforces 219C C. Color Stripe【dp+输出路径】
- JAVA笔记:double四舍五入并保留两位小数的方法
- setw()与setfill()