首先,中位数问题可以归结为求 K=n/2的 第K小元素,并无明显区别。

第一种方法,用MaxHeap,大小为K的大顶堆,能够求出最小的K的元素,复杂度为O(n*logK). 当K较大时,复杂度会较高。其实只需要求出第K小,而不是全部前K的序列,可以有更优化的方式。(大顶堆的方法就不贴代码了)

第二种方法,采用partition能够进行一定程度的改进,开始我认为这种方式已经是O(n),实际上如果partition选取的pivot导致每次partition都偏向一边,那么最坏情况是O(n^2). 先贴代码如下:

#include <iostream>
#include <stdio.h>
#include <unistd.h> using namespace std; int array[] = {, , , , , , };
const int size = sizeof(array) / sizeof (*array); int partition(int *array, int left, int right) {
if (array == NULL) {
return -;
} int pos = right;
right--; while (left <= right) {
while (left <= right && array[left] <= array[pos]) {
left++;
}
while (right > left && array[right] > array[pos]) {
right--;
}
if (left >= right) {
break;
}
swap(array[left], array[right]);
}
swap(array[left], array[pos]);
return left; } int getMinKth(int *array, int size, int k) {
if (array == NULL) {
return -;
}
int left = ;
int right = size - ;
int index = -; while (index != k) {
index = partition(array, left, right);
if (index < k) {
left = index + ;
}
else if (index > k) {
right = index - ;
}
else {
break;
}
} cout << "Value of k " << k << ":" << array[index] << endl;
return array[index];
} int main(int argc, char** argv) { if (argc < ) {
printf("Run cmd %s kth\n", basename(argv[]));
return ;
} int k = atoi(argv[]);
int value = getMinKth(array, size, k);
return ;
}

运行结果:

[getMinKth]$ ./getMinKth
Value of k :
[getMinKth]$ ./getMinKth
Value of k :
[getMinKth]$ ./getMinKth
Value of k :
[getMinKth]$ ./getMinKth
Value of k :
[getMinKth]$ ./getMinKth
Value of k :
[getMinKth]$ ./getMinKth
Value of k :
[getMinKth]$ ./getMinKth
Value of k :

第三种方法,是真的O(n),方法是采用5个一组的数列,取出中间一个,然后再从中取出中间一个,使用这个数作为pivot。

这样,至少有1/2 * 3/5个数比pivot小,也有1/2 * 3/5个数比pivot大。所以,每次最坏情况是划分成3:7或者7:3.

时间复杂度的证明方法:

T(n)<=T(n/)+T(/*n)+O(n)<=c*n*(+/+(/)^....)
所以T(n)=O(n)

写代码如下:

review时注:我觉得可以用上面的end比较的方式,先把pivot交换到最后,这样虽然多了一个swap,但是代码简洁很多,也不容易出错。

#include <algorithm>
#include <iostream> using namespace std; void printArr(int *arr, int first, int end) {
cout << "Array first " << first << "end " << end << ":";
for (int i=first; i<=end; ++i) {
cout << arr[i] << " ";
}
cout << endl;
}
int getMinKth(int *arr, int first, int end, int k); int partition(int *arr, int first, int end, int pivot) { int ret = -;
int tmp = -;
while (first <= end) {
while (arr[first] <= pivot) {
if (arr[first] == pivot) {
ret = first;
}
first++;
}
while (arr[end] > pivot) {
end--;
}
if (first < end) {
tmp = arr[first];
arr[first] = arr[end];
arr[end] = tmp;
if (arr[first] == pivot) {
ret = first;
}
first++;
end--;
}
}
tmp = arr[end];
arr[end] = arr[ret];
arr[ret] = tmp;
return end; } int getPivot(int *arr, int first, int end) {
if (end - first + <= ) {
sort(arr+first, arr+end+);
return arr[(first+end)/];
} int grp = (end - first + ) / ;
int *tmpArr = new int[grp]; for (int i=; i<grp; i++) {
int tmpFirst = first + * i;
int tmpEnd = first + * i + ;
if (tmpEnd > end) {
tmpEnd = end;
}
tmpArr[i] = getPivot(arr, tmpFirst, tmpEnd);
}
int ret = getMinKth(tmpArr, , grp-, (grp-)/);
delete []tmpArr;
return ret;
} int getMinKth(int *arr, int first, int end, int k) { if (first == end) {
return arr[first];
}
if (k < first || k > end) {
return -;
} int index = -;
int pivot = -;
while (index != k) {
pivot = getPivot(arr, first, end);
index = partition(arr, first, end, pivot);
if (index < k) {
first = index + ;
}
else if (index > k) {
end = index - ;
}
else {
break;
}
}
return arr[k];
} int main(int argc, char **argv) {
int array[] = {, , , , , , , };
if (argc <= ) {
printf("%s kth\n", argv[]);
return ;
} printArr(array, , );
int k = atoi(argv[]);
int ret = getMinKth(array, , , k);
printf("The %dth val is %d\n", k, ret);
return ;
}

编译命令:

g++ -o getMinKthOn getMinKthOn.cpp 

执行命令:

[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 0th val is
[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 1th val is
[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 2th val is
[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 3th val is
[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 4th val is
[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 5th val is
[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 6th val is
[getMinKthOn]$ ./getMinKthOn
Array first 0end :
The 7th val is

代码写的有点罗嗦,中间也调试了好几次。

后面有时间的时候,可以慢慢改进。

O(n)获得中位数及获得第K小(大)的数的更多相关文章

  1. 快速排序及查找第K个大的数。

    本文提供了一种基于分治法思想的,查找第K个大的数,可以使得时间复杂地低于nlogn. 因为快排的平均时间复杂度为nlogn,但是快排是全部序列的排序, 本文查找第k大的数,则不必对整个序列进行排序.请 ...

  2. 认真对待每一道算法题 之 两个排序好的数组寻找的第k个大的数

    转载博客:http://www.cnblogs.com/buptLizer/archive/2012/03/31/2427579.html 题目意思:给出两个排好序的数组 ,不妨设为a,b都按升序排列 ...

  3. 求数组前K个大的数

    我们举例,假若从10000万个数里选出前100个最大的数据. 首先我们先分析:既然要选出前100个最大的数据,我们就建立一个大小为100的堆(建堆时就按找最大堆的规则建立,即每一个根节点都大于它的子女 ...

  4. 有关最短路上的第k小/大值的总结

    1.USACO08JAN  Telephone Lines 题面 由于问的是最大值最小,所以二分加验证就好了 比较显然的,题干问的是第k+1长的路最短: 那么二分答案是正确的方向: 但是怎么验证? 我 ...

  5. luogu P3834 【模板】可持久化线段树 1(主席树) 查询区间 [l, r] 内的第 k 小/大值

    ————————————————版权声明:本文为CSDN博主「ModestCoder_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https:// ...

  6. 求第 k 小:大元素

    #include<bits/stdc++.h> using namespace std; void swap_t(int a[],int i,int j) { int t=a[i]; a[ ...

  7. 无序数组求第k大/第k小的数

    根据http://www.cnblogs.com/zhjp11/archive/2010/02/26/1674227.html 博客中所总结的7种解法,我挑了其中的解法3和解法6进行了实现. 解法3: ...

  8. (算法)两个有序数组的第k大的数

    题目: 有两个数组A和B,假设A和B已经有序(从大到小),求A和B数组中所有数的第K大. 思路: 1.如果k为2的次幂,且A,B 的大小都大于k,那么 考虑A的前k/2个数和B的前k/2个数, 如果A ...

  9. 动态数组第k小,Poj(1442)

    题目链接:http://poj.org/problem?id=1442 本来想复制一下,然后直接sort,结果T了. 在网上看了一下,有用两个队列做的,想了半天,没看懂什么意思.后来模拟一边,总算是懂 ...

随机推荐

  1. PRINCE2七大原则(2)

    PRINCE2七大原则(2) 我们先来回顾一下,PRINCE2七大原则分别是持续的业务验证,经验学习,角色与责任,按阶段管理,例外管理,关注产品,剪裁. 第二个原则:吸取经验教训. PRINCE2要求 ...

  2. ACM题目————又见拦截导弹

    描述 大家对拦截导弹那个题目应该比较熟悉了,我再叙述一下题意:某国为了防御敌国的导弹袭击,新研制出来一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:它的第一发炮弹能够到达任意的高度,但是以后每一发炮 ...

  3. 移动端web出现的一系列问题

    今天做移动端的web,在做后期处理的时候,发现了非常多的问题.下面我分别列举一下吧~~ 1.移动端浏览器众多,各种浏览器之间的显示等都有差异,很多需要单独处理,于是我需要判断分别是什么浏览器.js代码 ...

  4. 基于clahe的图像去雾

    基于clahe的图像去雾     通过阅读一些资料,我了解到clahe算法对图像去雾有所价值,正好opencv中有了实现,拿过来看一看.   但是现在实现的效果还是有所差异 #);    clahe] ...

  5. qbxt十一系列二

    PA[题目描述]汉诺塔升级了:现在我们有N个圆盘和N个柱子,每个圆盘大小都不一样,大的圆盘不能放在小的圆盘上面,N个柱子从左到右排成一排.每次你可以将一个柱子上的最上面的圆盘移动到右边或者左边的柱子上 ...

  6. shell脚本之lnmp的搭建

    !/bin/bash #this script is source packages installed lnmp .xmal yum -y install wget #"========= ...

  7. git版本控制器

    Git 是一个开源的分布式版本控制系统 Google用于android 源代码的管理就是Git,  它支持离线工作, 本地提交可以稍后提交到服务器上. 众多的开源项目都使用 Git  作为版本控制系统 ...

  8. 在centos6.3用yum安装redis

    一.centos默认的安装源在官方centos.org上,而redis在第三方的yum源里,所以无法安装,非官方的yum推荐用fedora的epel仓库.当然也可通过配置 /etc/yum.repos ...

  9. V-rep学习笔记:转动关节1

    V-REP(Virtual Robot Experimentation Platform),是全球领先的机器人及模拟自动化软件平台.V-REP让使用者可以模拟整个机器人系统或其子系统(如感测器或机械结 ...

  10. PCB表面处理工艺

    PCB表面处理最基本的目的是保证良好的可焊性或电性能.由于自然界的铜在空气中倾向于以氧化物的形式存在,不大可能长期保持为原铜,因此需要对铜进行其他处理. 1.热风整平(喷锡) 热风整平又名热风焊料整平 ...