《算法导论》学习笔记之Chapter9中位数和顺序统计量

2024-05-16 00:18

本文主要是介绍《算法导论》学习笔记之Chapter9中位数和顺序统计量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第9章 中位数和顺序统计量

先定义:在一个由n个元素组成的集合中,第i个顺序统计量是该集合中第i小的元素。一个中位数是它所属集合的“中点元素”。当n是奇数时,中位数是唯一的,位于i=n/2处。当n为偶数时,中位数有两个,分别位于i = n/2和i=n/2+1处。不考虑n的奇偶性,中位数总是出现在i=(n+1)/2向下取整处,也叫下中位数,和i=(n+2)/2向上取整处,也叫上中位数。本书默认下中位数。

本章讨论的是:从n个互异的元素构成的集合中选择第i个顺序统计量的问题。

如果不学习其他方法,仅使用前面介绍的算法,可以考虑使用归并排序或堆排序的算法,在O(nlogn)时间内完成查找。下面会介绍一个更快的方法。


求最大值最小值问题:

单词求最大值或最小值,会进行θ(n)次的比较,如果同时求出最大值最小值,简单来说可能需要2n-2次比较。但是,稍微改变一下:提前记录已知的最大值和最小值,每次选择一对数据进行比较,较大的与最大值比较,较小的与最小值比较,这样每次进行3次比较,总体会进行3(n/2)向下取整次比较,效率提升不少。

该问题中:如何设定已知的最大值和最小值取决n的奇偶性:n为奇数时,取第一个元素作为最大值最小值,后面元素成对比较;n为偶数时,对前两个元素进行比较,大的作为最大值,小的作为最小值,之后与n为奇数时相同的比较过程。若n为奇数,总比较次数为3(n/2)向下取整次;n为偶数,总比较次数为3(n-2)/2+1,共3n/2-2次比较。所以,不管哪一种情况,总的比较次数最多是3(n/2)向下取整次。


基于快速排序算法的线性时间选择算法

相同点是:均采用递归划分数据;

区别是:快速排序处理划分的两边,期望运行时间是θ(nlogn)

               选择算法只处理划分的一边,期望运行时间是线性时间θ(n)


下面介绍一个期望运行时间(注意:是期望,不是最坏运行时间)是线性时间的选择算法,代码实现如下:

// 基于快排的线性时间选择算法,选择数组中第i小的元素public static int RandomizedSelect(int[] a, int p, int r, int i) {if (p == r) {return a[p];}// q的左侧是比q小的,右侧是比q大的int q = RandomPartition(a, p, r);// k坐标表示的该元素是在数组中排行第k的数据;int k = q - p + 1;if (i == k) {return a[q];} else if (i < k) {return RandomizedSelect(a, p, q - 1, i);} else {return RandomizedSelect(a, q + 1, r, i - k);}}


上述算法最坏情况运行时间是θ(n.^2),但是因为是随机化的,所以不存在一个特定的情况导致最坏情况发生,该算法有线性的期望运行时间θ(n)。


下面是一个最坏情况是线性时间的选择算法

该算法的原理图如下:

左侧算法原理代码实现如下:

private static int select(int[] a, int l, int r, int k) {if (r - l < 75) {insertSort(a, l, r); // 当数组个数较小时,用快速排序进行排序return a[l + k - 1];}int group = (r - l + 5) / 5;//对数组进行分组,每组5个元素。其中加5操类似于向上取整for (int i = 0; i < group; i++) {//该循环结束之后会导致数组中的前group个数被所有子数组的中位数替代int left = l + 5 * i;int right = (l + i * 5 + 4) > r ? r : l + i * 5 + 4; // 如果超出右边界就用右边界赋值insertSort(a, left, right);//对每组进行插入排序int mid = (left + right) / 2;//找到中间坐标swap(a, l + i, mid); // 将各组中位数与前i个交换}int pivot = select(a, l, l + group - 1, (group + 1) / 2); // 找出中位数的中位数int p = partition(a, l, r, pivot); // 用中位数的中位数作为主元的位置int leftNum = p - l; // leftNum用来记录主元位置的前边的元素个数if (k == leftNum + 1)return a[p];else if (k <= leftNum)return select(a, l, p - 1, k);else // 若k在主元位子的后边,则要从主元位置的后边数起,即第(k - leftNum - 1)个return select(a, p + 1, r, k - leftNum - 1);}// 适用于线性时间选择的partition方法private static int partition(int[] a, int l, int r, int pivot) { int i = l;int j = r;while (true) {while (a[i] <= pivot && i < r)++i; // i一直向后移动,直到出现a[i]>pivotwhile (a[j] > pivot)--j; // j一直向前移动,直到出现a[j]<pivotif (i >= j)break;swap(a, i, j);}a[l] = a[j];a[j] = pivot;return j;}private static void insertSort(int[] a, int low, int high) { // 插入排序for (int i = low + 1; i <= high; i++) {int key = a[i];int j = i - 1;while (j >= low && a[j] > key) {a[j + 1] = a[j];j--;}a[j + 1] = key;}}

与比较排序一样,上述选择算法也是通过元素之间的比较来确定彼此之间的次序的,但是不同的是,上述选择算法在没有排序的情况下就已经解决了选择问题,所以运行时间并不受Ω(nlogn)的限制,而是线性运行时间。且与第8章介绍的线性运行时间不同的是,对输入并没有任何限制。

备注:后面的代码参考别人的博客内容,链接如下:http://blog.csdn.net/notfamous/article/details/23261341


这篇关于《算法导论》学习笔记之Chapter9中位数和顺序统计量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/993331

相关文章

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

在Linux终端中统计非二进制文件行数的实现方法

《在Linux终端中统计非二进制文件行数的实现方法》在Linux系统中,有时需要统计非二进制文件(如CSV、TXT文件)的行数,而不希望手动打开文件进行查看,例如,在处理大型日志文件、数据文件时,了解... 目录在linux终端中统计非二进制文件的行数技术背景实现步骤1. 使用wc命令2. 使用grep命令

Spring如何使用注解@DependsOn控制Bean加载顺序

《Spring如何使用注解@DependsOn控制Bean加载顺序》:本文主要介绍Spring如何使用注解@DependsOn控制Bean加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录1.javascript 前言2. 代码实现总结1. 前言默认情况下,Spring加载Bean的顺

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

Java中JSON格式反序列化为Map且保证存取顺序一致的问题

《Java中JSON格式反序列化为Map且保证存取顺序一致的问题》:本文主要介绍Java中JSON格式反序列化为Map且保证存取顺序一致的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录背景问题解决方法总结背景做项目涉及两个微服务之间传数据时,需要提供方将Map类型的数据序列化为co

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

MySQL中SQL的执行顺序详解

《MySQL中SQL的执行顺序详解》:本文主要介绍MySQL中SQL的执行顺序,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql中SQL的执行顺序SQL执行顺序MySQL的执行顺序SELECT语句定义SELECT语句执行顺序总结MySQL中SQL的执行顺序

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示