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. BZOJ 3689 异或之 (可持久化01Trie+堆)

    题目大意:给你一个序列,求出第$K$大的两两异或值 先建出来可持久化$01Trie$ 用一个$set$/堆存结构体,存某个异或对$<i,j>$的第二关键字$j$,以及$ai\;xor\;a ...

  2. Kneser猜想与相关推广

    本文本来是想放在Borsuk-Ulam定理的应用这篇文章当中.但是这个文章实在是太长,导致有喧宾夺主之嫌,从而独立出为一篇文章,仅供参考.$\newcommand{\di}{\mathrm{dist} ...

  3. 处理Oracle 11g在用EXP导出时,空表不能导出

    一.问题原因:     11G中有个新特性,当表无数据时,不分配segment,以节省空间 想要给空表也分配segmant,有以下两个办法: 1.insert一行,再rollback就产生segmen ...

  4. Qt之QPushButton

    简述 前面章节我们分享过Qt之QAbstractButton,讲解了QAbstractButton的基本用法,本节着重讲解QPushButton. 简述 常用状态 效果 源码 QSS 更多参考 关于Q ...

  5. C语言之文件操作04——输入矩阵a,b,求乘积c,并打印a,b,c到文件

    //文件与数组结合 /* ================================================================= 题目:输入矩阵a,b,求乘积c,并打印a, ...

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

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

  7. linux程序设计——个人总结

    linux程序设计--个人总结 到今天为止,<linux程序设计>学习基本完毕了.从五月下旬開始接触linux,学习安装Ubuntu14.04,六月份開始学习<linux程序设计&g ...

  8. Android笔记——Activity中的数据传递案例(用户注冊)

    1.创建程序activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/andro ...

  9. jsp页面中自定义标签的小演示

    在实习期遇到公司的pg自定义标签了,同事要我自己自学一下 自定义标签是用户定义的JSP语言元素.当JSP页面包含一个自定义标签时将被转化为servlet.JSP标签扩展可以让你创建新的标签并且可以直接 ...

  10. python-网络-tcp

    python-网络-tcp 标签(空格分隔): python TCP[client]-发送数据 from socket import * s = socket(AF_INET, SOCK_STREAM ...