查找无序数组的中位数,要想时间复杂度为O(n)其实用计数排序就能很方便地实现,在此讨论使用快速排序进行定位的方法。

1、中位数定义

2、算法思想

3、Java代码实现

4、时间复杂度分析

5、附录

中位数一般两种定义:

第一种:

排序后数组的中间位置的值,如果数组的个数是偶数个,则返回排序后数组的第N/2个数。

第一种(官方):

排序后数组的中间位置的值,如果数组的个数是偶数个,则返回最中间两个数的平均数。

例如:{ 7, 9, 4, 5}   第一种输出5;第二种输出6.0

算法思想:大家应该都知道,快速排序每一躺都能定位一个数在这个数组的最终位置,所以可以利用此特性对数组中任意一个位置进行二分法定位。

    方法就是:一趟快排的partition结束之后,将此时定位的位置与欲定位位置进行比较,如果不等于,则将partition的区间折半,直到等于为止,返回这个位置的值

Java代码实现

因为第二种中位数定义需要定位两个位置,在第一种上扩展即可,所以先讨论第一种:

  1. public static int getMedian(int[] nums) {
  2. return partition(nums, 0, nums.length - 1);
  3. }
  4.  
  5. private static int partition(int[] nums, int start, int end) {
  6. /***快排partition函数原代码——start***/
  7. int left = start;
  8. int right = end + 1;
  9.  
  10. int point = nums[start];
  11. while (true) {
  12. while (left < right && nums[--right] >= point)
  13. ;
  14. while (left < right && nums[++left] <= point)
  15. ;
  16. if (left == right) {
  17. break;
  18. } else {
  19. int tmp = nums[left];
  20. nums[left] = nums[right];
  21. nums[right] = tmp;
  22. }
  23. }
  24. nums[start] = nums[left];
  25. nums[left] = point;
  26. /***快排partition函数原代码——end***/
  27.  
  28. /***定位判断***/
  29. if (left == (nums.length - 1) / 2) {
  30. return nums[left];
  31. } else if (left > (nums.length - 1) / 2) {
  32. return partition(nums, start, left - 1);
  33. } else {
  34. return partition(nums, left + 1, end);
  35. }
  36. }

其实就是在原来的partition结束后加了一个定位判断,此时left指向的就是已经本趟定位的那一个数,如果没有定位成功则将上下界调整折半。

【注意】:“如果数组的个数是偶数个,则返回排序后数组的第N/2个数”这句话需要用 (nums.length - 1) / 2 来实现这句描述的下标,并满足奇数时取最中间下标的效果。

时间复杂度分析:

由于此方法采用的也是递归,那么必定符合递归的复杂度通项表达式: T(n) = aT(n/b) + f(n)

其中a为每次递归会分成几个需要计算的下一层,(n/b)为下一层计算的元素个数,f(n)为本层的计算复杂度

由于是折半查找,所以有:a=1、b=2(平均)、f(n)=n(每次的遍历比较交换)

所以有

  1. T(n) = T(n/2) +n
  2. = T(n/4) + n/2 +n
  3. ……
  4. = T(1) + 2 + …… + n/2 +n // T(1)≈1 等比数列求和
  5. = 1 - n * 2)/(1 - 2)
  6. = 2n - 1

所以最后平均时间复杂度为O(n)

【最优情况下b=n复杂度O(n);

 最坏情况下b=n-1/n,也就是(n/b)=(n-1),此时复杂度为O(n²),请自行计算哈】

附录——第二种求中位数的实现

思路:第一种已经解决了定位一个数字,而第二种就是定位两个数字,由于定位一个数字的时候不能保证另一个数字已经排序好,所以还需重新调用方法

  那么就把方法中定位判断的部分单独移出来做一个getByQuickSort(int[] nums,int stop)

java代码实现:

  1. public static double getByQuickSort(int[] nums, int stop) {
  2. if (stop < 0 || stop >= nums.length) {
  3. throw new IndexOutOfBoundsException();
  4. }
  5.  
  6. int start = 0;
  7. int end = nums.length -1;
  8. int par = 0;
  9.  
  10. while (start <= end) {
  11. par = partition(nums, start, end);
  12. if (par == stop) {
  13. break;
  14. } else if (par > stop) {
  15. end = par - 1;
  16. } else {
  17. start = par + 1;
  18. }
  19. }
  20. return nums[par];
  21. }

此处的partition(...)方法就是上一段代码中的partition方法中把 /***定位判断***/ 以下都去掉,然后加一个 return left; 即可。

而找中位数就再写一个方法getMedian2(...)判断一下奇偶,再调用getByQuickSort(....)就可以了:

  1. public static double getMedian2(int[] nums) {
  2. if (nums.length % 2 == 1) {
  3. return getByQuickSort(nums, nums.length / 2);
  4. } else {
  5. return (getByQuickSort(nums, nums.length / 2 - 1) +
  6. getByQuickSort(nums, nums.length / 2)) / 2.0;
  7. }
  8. }

求中位数,O(n)的java实现【利用快速排序折半查找中位数】的更多相关文章

  1. java基础-数组的折半查找原理

    java基础-数组的折半查找原理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 如果让你写一个数组的查找功能,需求如下:在一个数组中,找一个元素,是否存在于数组中, 如果存在就返回 ...

  2. Java实现冒泡排序、折半查找

    1.冒泡排序 public class BubbleSort{ public static void main(String[] args){ int score[] = {67, 69, 75, 8 ...

  3. Java经典算法之折半查找(二分法)

    采用二分法时,数据应是有序并且不重复的 与小时候玩的猜数游戏是一样的,会让你猜一个他所想的1~100之间的数,当你猜了一个数后,他会告诉你三种选择中的一个,比他想的大,或小,或猜中了,为了能用最少的次 ...

  4. Java下利用Jackson进行JSON解析和序列化

    Java下利用Jackson进行JSON解析和序列化   Java下常见的Json类库有Gson.JSON-lib和Jackson等,Jackson相对来说比较高效,在项目中主要使用Jackson进行 ...

  5. (转)Java程序利用main函数中args参数实现参数的传递

    Java程序利用main函数中args参数实现参数的传递 1.运行Java程序的同时,可以通过输入参数给main函数中的接收参数数组args[],供程序内部使用!即当你在Java命令行后面带上参数,J ...

  6. java实现利用httpclient访问接口

    HTTP协议时Internet上使用的很多也很重要的一个协议,越来越多的java应用程序需要通过HTTP协议来访问网络资源. HTTPClient提供的主要功能: 1.实现了所有HTTP的方法(GET ...

  7. 在JAVA中利用public static final的组合方式对常量进行标识

    在JAVA中利用public static final的组合方式对常量进行标识(固定格式). 对于在构造方法中利用final进行赋值的时候,此时在构造之前系统设置的默认值相对于构造方法失效. 常量(这 ...

  8. Java中利用随机数的猜拳游戏

    Java中利用随机数的猜拳游戏,实现非常简单,重难点在于随机数的产生. 首先GameJude类是用于判断输赢的一个类: package testGame; public class GameJudge ...

  9. java 中利用反射机制获取和设置实体类的属性值

    摘要: 在java编程中,我们经常不知道传入自己方法中的实体类中到底有哪些方法,或者,我们需要根据用户传入的不同的属性来给对象设置不同的属性值,那么,java自带的反射机制可以很方便的达到这种目的,同 ...

随机推荐

  1. libprotobuf 编译错误处理

    1. 编译完链接的时候报错undefined reference to well_known_types_js' 出现这个错误的原因是升级gcc导致的,是程序依赖的include文件和实际链接的文件不 ...

  2. QQ视频直播架构及原理 流畅与低延迟之间做平衡 音画如何做同步?

    QQ视频直播架构及原理 - tianyu的专栏 - CSDN博客 https://blog.csdn.net/wishfly/article/details/53035342 作者:王宇(腾讯音视频高 ...

  3. https://blog.newrelic.com/2014/05/02/25-php-developers-follow-online/

    w https://blog.newrelic.com/2014/05/02/25-php-developers-follow-online/ 1. Rob Allen. Zend Framework ...

  4. SSD(Single Shot MultiBox Detector)二读paper

    SSD KeyWords:Real-time Object Detection; Convolutional Neural Network Introduction 目前最尖端(State-of-ar ...

  5. eslasticsearch操作集锦

    索引-index:一个索引就是一个拥有几分相似特征的文档的集合.比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引.一个索引由一个名字来标识(必须全部是小写字母的),并且 ...

  6. corethink功能模块探索开发(十七)opencmf.php 配置文件

    图样: opencmf.php存在于每个模块的根目录,是模块配置文件. 能进行持久化配置参数保存,一开始我以为是写文件或者做缓存,后来在数据库中发现admin_module表,存储了每个模块的配置参数 ...

  7. window下安装php的imagick和imagemagick扩展教程

    最近的PHP项目中,需要用到切图和缩图的效果,在linux测试服务器上很轻松的就安装好php imagick扩展.但是在本地windows开发环境,安装过程遇到好多问题,在此与大家分享. 1. 下载 ...

  8. C/C++中浮点数输出格式问题

    在C语言中,浮点数的输出格式有三种:%g, %f, %e 首先要说的是%e是采用科学计数法来显示. %g与后两者有一个重要的差别,就是设置输出精度的时候,(C中默认浮点输出精度是6),%g认为,包括整 ...

  9. 使用反射实现 webdriver page 类

    这个类的目的是为了简化page类的实例化,只需要定义public page成员变量 然后再 启动driver后 通过反射实例化page 后面可以直接点出page实例 package crazy.sel ...

  10. 关于myeclipse+tomcat+struct2的热部署问题

    今天满心欢喜的打开电脑来写程序,却不曾想到它竟然给我搞事情,前几天刚学的struct2热部署竟然不好用了.每次改java文件都要重新部署好麻烦,最后花了了好长时间才解决,必须在这里总结一下: (1)s ...