Select 算法

I 编程珠玑(续)介绍的 Quickselect 算法

选择 N 个元素中的第 K 小(大)值,是日常场景中常见的问题,也是经典的算法问题.

选取 N 个元素的数组的中的第 K 小(大)值,最简单的想法是将数组排序后直接选取. 那么这种方法的时间复杂度是O(N log N).

C.A.R.Hoare 提出的 Quickelect 算法的平均时间复杂度达到了 O(N) . 在去递归之后, 是原地算法. 这个算法因为其简洁,高效而被广泛使用.

算法思路的C++实现如下.

int select(vector<int>& X, int k) {
int l = 0, u = X.size() - 1;
while(l < u){
swap(X[l], X[rand()%(u-l+1)+l]);
int m = l;
for(int i = l + 1; i <= u; i++)
if(X[i] < X[l])
swap(X[++m], X[i]); //m在i遍历的过程中,是遍历过的元素中, 小于X[l]的元素的最大下标
swap(X[l], X[m]);
if(k <= m) u = m - 1;
if(k >= m) l = m + 1;
}
return X[k];
}
  • k 选定为数组的中位数时,平均所耗的时间最多.
  • 当数组中有大量重复元素,或者是逆序排序的数组时,会增加运行时间. 遇到大量重复的元素时不能很快地缩小 l - u 的范围. 逆序数组会产生很多的 swap 操作.
  • Worst-case peformance O(N ^ 2)

II 序列输入时使用的 Heap-Select 算法

考虑一个输入序列,要求在序列输入完毕的时候得出这个序列的第 k 大(小)的元素.

要选择第 k 小的元素时, 我们考虑用一个 k 大小的大顶堆. 对数组从头开始遍历(等价于数组线性输入), 头 k 个元素用于建立 k 大小的大顶堆. 对于从 k + 1N 的元素. 当该元素小于堆顶元素的时候,将该元素插入到堆中,将堆顶元素出堆. 遍历(输入)结束后, 堆顶元素即为我们要找的元素.

相应的选择第 k 大的元素时, 我们考虑用一个 k 大小的小顶堆.对数组从头开始遍历. 头 k 个元素用于建立 k 大小的小顶堆. 对于从 k + 1N 的元素. 当该元素大于堆顶元素的时候,将该元素插入到堆中,将堆顶元素出堆. 遍历(输入)结束后, 堆顶元素即为我们要找的元素.

这样可得这个算法的时间复杂度为 O(k) + O(N * log k) ==> O(N * log k)

由于要调用空间构造堆,空间复杂度为 O(k)

关于这个算法的正确性,用归纳法, 从已经输入k的数组中挑选头k个最大(小)的元素。 然后继续下去即可。

III 三个元素的中间值

杀鸡不用牛刀,三个元素的中间值用简单的三次比较就可以搞定.

if(X[1] > X[2])
swap(X[1], X[2]);
if(X[2] > X[3])
swap(X[2], X[3]);
if(X[1] > X[2])
swap(X[1], X[2]); //自此 X[1], X[2], X[3] 从小到大有序.

IV 其他的Select算法

Median of medians 又名 BFPRT算法. 基于Blum, Floyd, Pratt, Rivest and Tarjan 1973年的论文 Time Bounds for Selection. 拥有O(N)worst case performance.

Introselect 则是BFPRT算法和 Quickselect 算法的结合. 默认使用 Quickselect ,在 Quickselect 表现出比较差的运行情况时转向Median of medians. 从而也能提供O(N)worst case performance.

Select 选择算法 - 编程珠玑(续) 笔记的更多相关文章

  1. 算法线性编程珠玑读书笔记之----->使用线性算法求解连续子序列的最大和

    这段时间笔者几篇文章介绍了改算法线性的文章. 关联文章的地址 这个算法我在我的博客里应用动态规划做过,详细实现请参阅我的dp板块,下面给出书上最快的算法,时间复杂度为O(n),称之为线性算法. #in ...

  2. 学习笔记之编程珠玑 Programming Pearls

    Programming Pearls (2nd Edition): Jon Bentley: 0785342657883: Amazon.com: Books https://www.amazon.c ...

  3. 《编程珠玑,字字珠玑》读书笔记完结篇——AVL树

    写在最前面的 手贱翻开了<珠玑>的最后几章,所以这一篇更多是关于13.14.15章的内容.这篇文章的主要内容是“AVL树”,即平衡树,比红黑树低一个等次.捣乱真惹不起红黑树,情况很复杂:而 ...

  4. 读书笔记--编程珠玑II

    学化学的应该都知道chemdraw,这是一款专门绘制化学结构的软件,什么苯环.双键各种word难以搞定的分子式,你可以轻松的用chemdraw完成,可以称得上化学工作者居家旅行必备的良药.其实早在19 ...

  5. 编程珠玑I算法总结

    主要是根据编程珠玑后面的Algorithm附录总结了一下这本书里面的经典算法. 1 辗转相减求最大公约数 思想:最大公约数能整除i和j,则其一定也能整除i-j(if i>j) int gcd(i ...

  6. 一种最坏情况线性运行时间的选择算法 - The missing worst-case linear-time Select algorithm in CLRS.

    一种最坏情况线性运行时间的选择算法 - The missing worst-case linear-time Select algorithm in CLRS. 选择算法也就是求一个无序数组中第K大( ...

  7. python核心编程第二版笔记

    python核心编程第二版笔记由网友提供:open168 python核心编程--笔记(很详细,建议收藏) 解释器options:1.1 –d   提供调试输出1.2 –O   生成优化的字节码(生成 ...

  8. 《[MySQL技术内幕:SQL编程》读书笔记

    <[MySQL技术内幕:SQL编程>读书笔记 2019年3月31日23:12:11 严禁转载!!! <MySQL技术内幕:SQL编程>这本书是我比较喜欢的一位国内作者姜承尧, ...

  9. 《C#高级编程》读书笔记

    <C#高级编程>读书笔记 C#类型的取值范围 名称 CTS类型 说明 范围 sbyte System.SByte 8位有符号的整数 -128~127(−27−27~27−127−1) sh ...

随机推荐

  1. shell 特殊字符

    shell 基础 # 当做注释的比较多 : 命令分隔符,在同一行上写两个或两个以上的命令 :: 是case 代码块的结束符 . 点作为文件名的一部分 隐藏文件 目录名 点是正则表达式中的匹配字符 '' ...

  2. [转] 经典排序算法 - 基数排序Radix sort

    原理类似桶排序,这里总是需要10个桶,多次使用 首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,暂时忽视十位数 例如 待排序数组[62,14,59,88,16]简单点五个数字 分 ...

  3. readb(), readw(), readl(),writeb(), writew(), writel() 宏函数

    参见: http://blog.csdn.net/hustyangju/article/details/20448339

  4. js时间格式化函数,支持Unix时间戳

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  5. USACO Ski Course Design解析和C语言实现

    题目大意: John农场有N(1=<N<=1000)小丘陵(山),它们高度的范围从0 到 100 但仅仅有当最大的高度差不大于17时.才干够避税.John对它们进行改造,从高的丘陵上取土放 ...

  6. [poj 2480] Longge's problem 解题报告 (欧拉函数)

    题目链接:http://poj.org/problem?id=2480 题目大意: 题解: 我一直很欣赏数学题完美的复杂度 #include<cstring> #include<al ...

  7. 怎么去除innerHTML获得内容中的标签?

    去掉innerHTML获得内容里面的标签: <body> <div id="d1"><p id="p1">hello wor ...

  8. ios下微信浏览器如何唤醒app?app已上架应用宝

    android下可以通过在应用宝微下载地址后面加参数&android_schema='应用schema'来实现,ios下如何实现? ios下微信浏览器如何唤醒app?app已上架应用宝 > ...

  9. 《剑指offer》调整数组顺序使奇数位于偶数前面

    一.题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 二.输入描述 ...

  10. 使用sysbench 对mysql进行性能测试

    使用sysbench 对mysql进行性能测试 sysbench是一个开源的.模块化的.跨平台的多线程性能测试工具,可以用来进行CPU.内存.磁盘I/O.线程.数据库的性能测试.目前支持的数据库有My ...