前往我的主页以获得更好的阅读体验算法基础-顺序统计量 - DearXuan的主页https://blog.dearxuan.com/2022/01/30/%E7%AE%97%E6%B3%95%E5%9F%BA%E7%A1%80-%E9%A1%BA%E5%BA%8F%E7%BB%9F%E8%AE%A1%E9%87%8F/

顺序统计量

将长度为 n 的数组升序排序后,则第 i 个位置的数字是该数组的第 i 小的量,称之为第 i 顺序统计量

数组最小值是第1个顺序统计量,最大值是第n个顺序统计量,中位数(又称下中位数)是第⌊(n+1)/2⌋个顺序统计量

⌊n⌋ 表示对 n 向下取整,⌈n⌉表示对 n 向上取整

最大值和最小值

若想要寻找n个数字里的最大值或最小值,只需要进行(n-1)次比较

int min = a[0];
for(int i=1;i<n;i++){if(a[i] > min)min = a[i];
}

显然这已经是最优的算法了,我们称他为“遍历查找”,因为该算法是简单地遍历了整个数组来寻找最大或最小值,总共需要(n-1)次比较,即S(n)=n-1

现在我们要研究如何以尽可能低的时间复杂度来同时求出数组的最大值和最小值

传统方法

最容易想到的方法就是重复两次“遍历查找”,分别找出最大和最小值,那么就需要S(n)=2(n-1)次比较,但是这显然不是最佳的方案。

设存在数组A=[9,0,1,2,100]

在寻找最小值时,当遍历到第2个元素时,由于0<9,所以最小值被替换成0,同时我们也可以得知0一定不是最大值,因为有个9比它更大。

在寻找最大值时,采用了相同的算法,导致0又被比较了一遍,而现在0不可能是最大值。

优化算法

通过上面的传统方法,我们可以发现减少比较次数的关键是减少不必要的比较,这就给我们一个思路,将一个数组划分为 k 段,找出这 k 个数的最大最小值,然后分别和整个数组的最大最小值比较

设查找长度为 n 的数组中的最大最小值,需要比较至多 f(n) 次,数组被划分为 n/k 段,每段 k 个数字,每段分别需要比较 f(k) 次就可以得到最大最小值,则共比较就可以得到 n/k 个最大值数组和最小值数组,在查找整个数组的最小值时只需要从最小值数组里寻找就行了,而查找整个数组的最大最小值又需要比较次,于是得到 f(n) 的函数

同理对于长度为k的数组,我们又可以将其分为更小的段,一直分下去,直到 k = 2 时,f(2)=1,因为两个数只需要比较一次就能得到最大最小值,我们假设将长度为n的数组划分为长度为k1的数段,将长度为k(i-1)的数段划分为长度为ki的更小的数段,带入 f(n),得

由于 kx 一定是正数,因此 i 为 1 时,右边的连加消失,f(n)取到最小值,即k1=2

得到上述结果的前提是事先定义好了min和max的初值,但是实际应用中我们可以根据数组动态调整初值,如果长度为偶数,则先比较前两项,大的作为max,小的作为min,共比较(3n/2-1)次;如果长度为奇数,则min和max都取第一项,因此实际的比较次数应该是(3n/2-2)次,即最终比较次数应该是

通过理论我们得知了只要把数组中的数两两比较,其中的较小者和最小值比较,而较大者和最大值比较,就可以实现用最少的比较次数同时求出最大最小值

void FindMinAndMax(int* a, int len){int min, max, i;if(len % 2 == 0){//当长度为偶数时,将前两项之间的较大者设为最大值,较小者设为最小值if(a[0] < a[1]){min = a[0];max = a[1];}else{min = a[1];max = a[0];}//从a[2]和a[3]开始比较,i为3i = 3;}else{//当长度为基数时,将最大值和最小值都设为a[0]min = max = a[0];//从a[1]和a[2]开始比较,i为2i = 2;}while (i < len){if(a[i-1] < a[i]){if(a[i-1]<min) min = a[i-1];if(a[i]>max) max = a[i];}else{if(a[i]<min) min = a[i];if(a[i-1]>max) max = a[i-1];}i += 2;}cout << "min:" << min << endl;cout << "max:" << max << endl;
}

第i顺序统计量

如果想要找到数组里的第 i 顺序统计量,也就是第 i 小的数字,通常的办法是把整个数组排序,然后直接取出对应位置的数字。快速排序是一个很好的办法,快速排序将数组划分为两个子数组来排序。实际上,我们只关心其中某一个位置的数字,因此对于快速排序划分出来的两个子数组,我们仅需要排序其中一个就行了

int find(int *a, int left, int right, int k) {if (left >= right) {return a[left];}//key为选定的基准值int i = left, j = right, key = a[left];while (i < j) {//遍历数组找到第一个比key大的数while (a[i] < key) {++i;}//遍历数组找到第一个比key小的数while (a[j] > key) {--j;}//交换,此时比key小的在左边,比key大的在右边if (i < j) {int temp = a[i];a[i] = a[j];a[j] = temp;}}//此时基准值在整个数组的第i个位置//s是基准值在以left开始的数组里的位置,i是基准值的位置int s = i - left + 1;if (s == k) {//如果s==k,说明基准值就是要查找的数,则返回基准值return a[i];} else if (s > k) {//如果s>k,说明基准值在要查找的数的右边,则遍历左边数组return find(a, left, j, k);} else {//如果s<k,说明基准值在要查找的数的左边,则遍历右边数组return find(a, j + 1, right, k - s);}
}

该方法的比较次数受到随机因素的影响,因此是一个随机算法。在平均情况下,它的时间复杂度能够达到O(n)

算法基础-顺序统计量相关推荐

  1. 《算法基础:打开算法之门》一1.5 拓展阅读

    本节书摘来自华章出版社<算法基础:打开算法之门>一书中的第1章,第1.5节,作者 [美]托马斯 H 科尔曼(Thomas H Cormen),更多章节内容可以访问云栖社区"华章 ...

  2. 送书 | 你一定能看懂的算法基础书(代码示例基于Python)

    本文引自图灵教育<算法图解> 你一定能看懂的算法基础书:代码示例基于Python:400多个示意图,生动介绍算法执行过程:展示不同算法在性能方面的优缺点:教会你用常见算法解决每天面临的实际 ...

  3. 2021牛客寒假算法基础集训营1 J 一群小青蛙呱蹦呱蹦呱

    今天的比赛没打( 睡午觉去了,今天太累了 晚上来看看题 2021牛客寒假算法基础集训营1 J 一群小青蛙呱蹦呱蹦呱 题目传送门 板子题( 我们知道由唯一分解定理得,若 n=p1α1×p2α2×p3α3 ...

  4. 《算法基础》——2.3 求幂运算

    本节书摘来自华章计算机<算法基础>一书中的第2章,第2.3节,作者:(美)罗德·斯蒂芬斯(Rod Stephens)著,更多章节内容可以访问云栖社区"华章计算机"公众号 ...

  5. Python3算法基础练习:编程100例( 21~ 25)

    往期练习: Python3算法基础练习:编程100例(1~5) Python3算法基础练习:编程100例(6 ~ 10) Python3算法基础练习:编程100例(11 ~ 15) Python3算法 ...

  6. Python3算法基础练习:编程100例(11 ~ 15)

    往期练习: Python3算法基础练习:编程100例(1~5) Python3算法基础练习:编程100例(6 ~ 10) Python3算法基础练习:编程100例(11 ~ 15) 11.兔子问题 1 ...

  7. Python3算法基础练习:编程100例( 31 ~ 35 )

    上期文章: Python3算法基础练习:编程100例( 26 ~ 30) 目录 31 判断星期几 32 反序输出列表 33 分隔列表 34 函数调用 35 文本加颜色 31 判断星期几 题目:请输入星 ...

  8. Python3算法基础练习:编程100例( 26 ~ 30)

    上期文章: Python3算法基础练习:编程100例( 21~ 25) 目录 26 递归求 20! 的阶乘 27 字符串反转 28 猜岁数 29 整数打印每一位数字 30 回文数 26 递归求 20! ...

  9. Python3算法基础练习:编程100例(6 ~ 10)

    往期练习: Python3算法基础练习:编程100例(1~5) Python3算法基础练习:编程100例(6 ~ 10) 6.斐波那契数列 7.列表复制 8.乘法口诀表 9.暂停输出 10.格式化时间 ...

  10. python小白-day4递归和算法基础

    递归&算法基础 一.递归 递归函数的优点是定义简单,逻辑清晰.理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰. 使用递归函数需要注意防止栈溢出.在计算机中,函数调用是通过 ...

最新文章

  1. 统一沟通-技巧-11-Lync-联盟-1-MSN
  2. 微信小程序开发-IP地址查询-例子
  3. 正则表达式的非捕获性分组
  4. 通过一个例子来理解二维码纠错机制
  5. kong组件_使用Kongzue全家桶组件创建项目全攻略(一、引入和沉浸式的那些事儿)...
  6. Android第三十二期 - 辅助类Android
  7. 阻塞非阻塞、同步异步
  8. 数据传输类型与通信方式
  9. 好用的开源软件_推荐_良心软件
  10. web optimize_image / Jpegoptim / ImageOptim / google webP
  11. W10一键进入安全模式
  12. 区块链火了 市场热度最么高
  13. 全国大学生英语竞赛——题型介绍
  14. oCPC实践录 | oCPC产品设计与出价原理(1)
  15. MySQL备份工具之xtrabackup
  16. Word目录排版,页码格式转换
  17. fdisk分区详解【适用于2T以内的新硬盘分区】
  18. shell的几个重要命令,主要参数,循环语句以及变量处理
  19. 也门亚丁一炼油厂爆炸起火造成数人受伤
  20. OSChina 周四乱弹 ——快速辨别妹子有无男友!

热门文章

  1. 小明左右手分别拿两张纸牌:黑桃10和红心8,现在交换手中的牌。编写并输出互换后的结果,输出结果如图所示。
  2. 【06期】单例模式有几种写法?
  3. 怎样学好python编程-怎样学 Python?
  4. 【知识兔】自学Excel之4:窗口视图控制
  5. python2.7 一个莫名其妙的错误
  6. android动态指示箭头,android – 自定义选项卡指示器(箭头像指示器)
  7. 小心 transmittable-thread-local 的这个坑
  8. 计算机发挥cpu全部,怎样提升CPU性能?怎么让CPU发挥最大的性能
  9. Python3判断字符中英文数字符号
  10. 概率论的学习和整理11:伯努利试验的3种分布:0-1分支,几何分布, 二项分布