快速切分法寻找中位数的递归与非递归实现
2015-11-01 21:31
344 查看
中位数
对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,则中位数不唯一,通常取最中间的两个数值的平均数作为中位数。
中位数寻找的快速算法
一般寻找中位数可以先将数组排序,按照次序将中间的数据作为中位数即可,其时间复杂度主要取决于排序算法的时间复杂度,利用快速排序可以将其控制为线性对数量级。
但是能否打破线性对数的限制呢?其中最关键的问题是,寻找中位数并不需要整个数组完全有序,如果把多余的元素排序省略掉,那么就可以超越线性对数的限制实现最快的算法。
启发来源于快速排序算法中的切分法,比如我们需要找到数组中第
经过数学推导,这种快速切分法寻找中位数仅仅为线性量级,是寻找中位数最为快速的算法。
算法实现
对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,则中位数不唯一,通常取最中间的两个数值的平均数作为中位数。
中位数寻找的快速算法
一般寻找中位数可以先将数组排序,按照次序将中间的数据作为中位数即可,其时间复杂度主要取决于排序算法的时间复杂度,利用快速排序可以将其控制为线性对数量级。
但是能否打破线性对数的限制呢?其中最关键的问题是,寻找中位数并不需要整个数组完全有序,如果把多余的元素排序省略掉,那么就可以超越线性对数的限制实现最快的算法。
启发来源于快速排序算法中的切分法,比如我们需要找到数组中第
k小的元素,首先将数组
a[lo,hi]切分返回整数
j,使得
a[lo,j-1]都小于等于
a[j],而
a[j+1,hi]都大于等于
a[j],如果
j==k,那么
j位置的元素就是我们要找的第
k小的元素,而如果
j>k,就要切分左子数组,如果
j<k,就要切分右子数组,不断缩小选定的子数组的规模直到只剩下一个元素,则它就是最终我们要找的第
k小的元素。
经过数学推导,这种快速切分法寻找中位数仅仅为线性量级,是寻找中位数最为快速的算法。
算法实现
public class Select { // 寻找中位数 public static <T> Comparable<T> findMedium(Comparable<T>[] a) { return select1(a, a.length / 2); } // 找出数组中第k小的元素,非递归实现 public static <T> Comparable<T> select1(Comparable<T>[] a, int k) { int lo = 0, hi = a.length - 1; while (hi > lo) { int j = partition(a, lo, hi); if (j == k) { return a[k]; } else if (j > k) { hi = j - 1; } else if (j < k) { lo = j + 1; } } return a[k]; } // 找出数组中第k小的元素,递归实现 public static <T> Comparable<T> select2(Comparable<T>[] a, int k, int lo, int hi) { int j = partition(a, lo, hi); if (j == k) { return a[k]; } else if (j > k) { return select2(a, k, lo, j - 1); } else { return select2(a, k, j + 1, hi); } } public static <T> int partition(Comparable<T>[] a, int lo, int hi) { int i = lo, j = hi + 1; Comparable<T> v = a[lo];// 切分元素选为首元素 while (true) { while (less(a[++i], v)) {// 向右扫描 if (i == hi) { break; } } while (less(v, a[--j])) {// 向左扫描 if (j == lo) { break; } } if (i >= j) {// 指针相遇,切分位置确定 break; } exch(a, i, j);// 交换左右逆序元素 } exch(a, lo, j);// 将切分元素放在切分位置 return j; } @SuppressWarnings("unchecked") public static <T> boolean less(Comparable<T> v, Comparable<T> w) { return v.compareTo((T) w) < 0; } private static <T> void exch(Comparable<T>[] a, int i, int j) { Comparable<T> t = a[i]; a[i] = a[j]; a[j] = t; } public static void main(String[] args) { String[] a = "qwertyuiopasdfghjklzxcvbnm".split(""); System.out.println("Max: "+select1(a, 0)); System.out.println("Min: "+select2(a, 25, 0, a.length - 1)); System.out.println("Medium: "+findMedium(a)); } }
相关文章推荐
- 在EA中将代码导入模型的时候,查看源码出现中文乱码的解决方案
- 第八周项目1—建立顺序串的算法库
- Android动画进阶—使用开源动画库nineoldandroids
- C语言中求字符串长度
- 【线性代数公开课MIT Linear Algebra】 实际应用——python中的线性代数(1)
- 乔迁
- YJQ Arranges Sequences
- HTML--【DRP】
- Java记录 -53- LinkedList实现队列
- elasticsearch 笔记-安装
- AE二次开发异常报错:异常来自 HRESULT:0x80040228
- 在Android Studio中创建项目和模拟器
- 闲聊
- linux 命令
- hdu 1495 非常可乐
- Nmap-服务探测
- 经典SQL语句大全【提升一】
- linux 解压缩命令
- BP算法C++实现
- 模块化编程