线性时间查找第k大元素

来源:互联网 发布:msdn win7 优化 编辑:程序博客网 时间:2024/05/01 15:04

/* 找出第k大的元素可以使用:堆排序,桶排序等方法,这里介绍一种O(n)的分治算法:先对数组划分,然后判断第k小的元素应该在哪个分组,再对相应的分组递归 */int partion(int *a, int start, int end) {int rnd = start + rand() % (end - start + 1);int tmp = a[rnd];a[rnd] = a[start];//随机获取参考值while (start < end) {for (; start < end && a[end] > tmp; end--);if (start < end) {a[start++] = a[end];}//从右边选取第一个小于tmp的值复制到a[start]for (; start < end && a[start] < tmp; start++);if (start < end) {a[end--] = a[start];}//从左边选取第一个大于tmp的值复制到a[end]}a[start] = tmp; //将保存在tmp里面的a[start]存到最终的位置return start;}/* n为数组的个数,要找出第k大的值,k从1开始计数 */int findk(int *a, int start, int end, int k) {assert(k > 0 && k <= end - start + 1);int tmp = partion(a, start, end);//随机拆分成左小右大的2部分int nlower = tmp - start + 1;//左边小元素的个数if (k == nlower) {//若左边小元素个数恰好为k,则返回return a[tmp];} else if (nlower < k) {//左边元素个数比k少,则在右边继续寻找剩下的k-nlowerreturn findk(a, tmp + 1, end, k - nlower);} else {return findk(a, start, tmp - 1, k);//继续在左边部分寻找第k大}}