快速选择算法--无序数组中寻找中位数 O(n)的算法及证明

news/2024/12/22 20:07:41/

一、排序算法

排序的算法是最容易想到的,但是即使是快排,平均复杂度也只有 O ( n log ⁡ n ) O(n \log n) O(nlogn)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;double findMid(vector<int>& nums) {int n = nums.size();sort(nums.begin(), nums.end());if (n % 2) {return nums[n/2];}else {return (nums[n/2] + nums[n/2-1]) / 2.0;}
}int main() {vector<int> nums = {9, 8, 7, 6, 1, 2, 3, 4};cout << findMid(nums) << endl;return 0;
}

这就很简单,没什么说的了,只需要注意如果数组为偶数需要求两个数的平均值

二、快速选择算法

1、随机选择一个元素作为基准

2、将数组分为三个部分,小于基准,等于基准,大于基准

3、确定位置:

  • 如果基准的位置恰好是中位数位置,那么返回基准
  • 如果中位数在小于基准位置,那么递归处理小于部分
  • 如果中位数在大于基准位置,那么递归处理大于部分
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;int quickselect(vector<int> nums, int l, int r, int k) {if (l == r) return nums[l];// 元素选择为最右边元素int pivot_value = nums[r];int j = l;for (int i=l; i<r; i++) {if (nums[i] < pivot_value) {swap(nums[i], nums[j]);++j;}}// 基准元素放回数组中间swap(nums[r], nums[j]);if (k == j) {return nums[k];}else if (k < j) {return quickselect(nums, l, j-1, k);} else {return quickselect(nums, j+1, r, k);}}double findMid(vector<int>& nums) {int n = nums.size();if (n % 2) {// cout << '$' << endl;return quickselect(nums, 0, n-1, n/2);}else {int a = quickselect(nums, 0, n-1, n/2);int b = quickselect(nums, 0, n-1, n/2-1);// cout << a << ' ' << b << endl;return (a + b) / 2.0;}
}int main() {vector<int> nums = {9, 8, 7, 6, 1, 2, 3, 4};cout << findMid(nums) << endl;return 0;
}

快速选择算法有点类似于快速排序,可以帮助我们快速找到数组中的第k个元素。但是快速排序的时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)为什么快速选择算法就是 O ( n ) O(n) O(n) 呢?

2.1、期望时间复杂度

期望分析

  • 假设基准将数组分为 a n an an ( 1 − a ) n (1−a)n (1a)n 两部分,其中 a a a 是一个介于 0 和 1 之间的常数。
  • 每次递归调用后的时间复杂度可以表示为: T ( n ) = T ( α n ) + O ( n ) T(n)=T(αn)+O(n) T(n)=T(αn)+O(n)
  • 这里, O ( n ) O(n) O(n) 是当前分区所需的时间。

递归展开

  • 我们可以展开这个递归公式:

T ( n ) = O ( n ) + T ( a n ) = O ( n ) + O ( n 2 ) + T ( a 2 n ) = . . . = O ( n ) + O ( n 2 ) + . . . + O ( a k n ) T(n)=O(n)+T(an)=O(n) + O(n^2) + T(a^2n) = ... = O(n) + O(n^2) + ...+O(a^k n) T(n)=O(n)+T(an)=O(n)+O(n2)+T(a2n)=...=O(n)+O(n2)+...+O(akn)

其中k是递归深度,直到n变为1。

求和公式

  • 求和部分是一个几何级数:

O ( n ) + O ( n 2 ) + . . . + O ( a k n ) = O ( n ) ( 1 + a + a 2 + . . . + a k ) = 1 − a k 1 − a O ( n ) O(n) + O(n^2) + ...+O(a^k n) = O(n)(1+a+a^2+...+a^k) = \frac{1-a^k}{1-a} O(n) O(n)+O(n2)+...+O(akn)=O(n)(1+a+a2+...+ak)=1a1akO(n)

最终结果

  • 因此,整体的时间复杂度可以表示为: O ( n ) O(n) O(n)

2.2、最差时间复杂度

最差时间复杂度就可以看做每一层选择的值都很差,都需要和剩下的n-1个值比较
T ( n ) = T ( n − 1 ) O ( n ) = T ( n − 2 ) O ( n − 1 ) O ( n ) = . . . = O ( n ( n − 1 ) 2 ) = O ( n 2 ) T(n) = T(n-1)O(n) = T(n-2)O(n-1)O(n)=...=O(\frac{n(n-1)}{2}) = O(n^2) T(n)=T(n1)O(n)=T(n2)O(n1)O(n)=...=O(2n(n1))=O(n2)


http://www.ppmy.cn/news/1533119.html

相关文章

【吊打面试官系列-MySQL面试题】为表中得字段选择合适得数据类型

大家好&#xff0c;我是锋哥。今天分享关于【为表中得字段选择合适得数据类型】面试题&#xff0c;希望对大家有帮助&#xff1b; 为表中得字段选择合适得数据类型 字段类型优先级: 整形>date,time>enum,char>varchar>blob,text 优先考虑数字类型&#xff0c;其次是…

DevExpress WinForms中文教程:Data Grid - 如何添加或删除行?

本教程介绍DevExpress WinForm的Data Grid控件UI元素和API&#xff0c;它们使您和最终用户能够添加或删除数据行。您将首选学习如何启用内置的数据导航器&#xff0c;然后学习如何使用Microsoft Outlook启发的New Item行添加新记录。最后教程将向您展示基本的API&#xff0c;它…

k8s 部署 prometheus

创建namespace prometheus-namespace.yaml apiVersion: v1 kind: Namespace metadata:name: ns-prometheus拉取镜像 docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/quay.io/prometheus/prometheus:v2.54.0prometheus配置文件configmap prometheus-configmap.yaml …

PHP 中,将 JSON 数据与二进制数据之间进行相互转化主要涉及两个步骤:

在 PHP 中&#xff0c;将 JSON 数据与二进制数据之间进行相互转化主要涉及两个步骤&#xff1a; 将 JSON 数据转换为二进制数据将二进制数据转换为 JSON 数据 1. 将 JSON 数据转换为二进制数据 要将 JSON 数据转换为二进制数据&#xff0c;首先需要将 JSON 数据解析成 PHP 数…

爬虫逆向学习(九):记录一个集cookie、请求参数、请求体、响应文本加密的站点反爬

此分享只用于学习用途&#xff0c;不作商业用途&#xff0c;若有冒犯&#xff0c;请联系处理 反爬前置信息 站点&#xff1a;aHR0cHM6Ly96d2Z3LmNxLmdvdi5jbi9pY2l0eS9pY2l0eS9lbmdpbmVlcmluZy9uYXZpZ2F0aW9u 接口&#xff1a;/icity/api-v2/cq.app.icity.engineering.Engine…

滚雪球学MySQL[11.2讲]:MySQL未来学习方向:大数据、云计算与迁移路径

全文目录&#xff1a; 前言11.2 未来学习方向1. MySQL与大数据1.1 MySQL与大数据生态的结合1.2 MySQL在大数据场景中的应用 2. MySQL与云计算2.1 云数据库服务2.2 容器化与MySQL2.3 云计算与MySQL的结合优势 3. MySQL的替代与迁移3.1 迁移到NoSQL数据库3.2 迁移到分布式SQL数据…

65.【C语言】联合体

目录 目录 1.定义 2.格式 3.例题 答案速查 分析 4.练习 答案速查 分析 5.相同成员的联合体和结构体的对比 6.联合体的大小计算 2条规则 答案速查 分析 练习 答案速查 分析 7.联合体的优点 8.匿名联合体 1.定义 和结构体有所不同,顾名思义:所有成员联合使用同…

RabbitMQ基本原理

一、基本结构 所有中间件技术都是基于 TCP/IP 协议基础之上进行构建新的协议规范&#xff0c;RabbitMQ遵循的是AMQP协议&#xff08;Advanced Message Queuing Protocol - 高级消息队列协议&#xff09;。 生产者发送消息流程&#xff1a; 1、生产者和Broker建立TCP连接&#…