算法:线性时间选择(C/C++)
Description
给定线性序集中n个元素和一个整数k,n<=2000000,1<=k<=n,要求找出这n个元素中第k小的数。
Input
第一行有两个正整数n,k. 接下来是n个整数(0<=ai<=1e9)。
Output
输出第k小的数
Sample Input
6 3
1 3 5 2 4 6
Sample Output
3
利用快速排序可以找出第k小的,加上随机函数改进一下:
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
int num[2000001];
void quictSort(int, int, int);
int partition(int, int);
int main()
{
int n, m, i;
srand(unsigned(time(NULL))); // 随机函数种子
while (~scanf("%d%d", &n, &m))
{
for (i = 0; i < n; i++)
scanf("%d", &num[i]);
quictSort(0, n - 1, m - 1);
printf("%d\n", num[m - 1]);
}
return 0;
}
// 快速排序
void quictSort(int left, int right, int mTop)
{
if (left < right)
{
int p = partition(left, right); // 分为两段
if (p == mTop) // 如果随机找到第mTop小就直接返回
return;
if (p < mTop)
quictSort(p + 1, right, mTop); // 找到的位置比mTop小就在[p + 1, right]区间找
if (p > mTop)
quictSort(left, p - 1, mTop); // 找到的位置比mTop大就在[left, p - 1]区间找
}
}
// 从小到大排
int partition(int left, int right)
{
int r = rand() % (right - left + 1) + left; // 随机选择一个数
int key = num[r];
std::swap(num[r], num[left]); // 交换到数组首位
while (left < right)
{// 从数组后面开始, 找比随机选择的数小的, 然后从前找比随机选择的数大的
while (left < right && num[right] >= key)
right--;
if (left < right)
num[left] = num[right];
while (left < right && num[left] <= key)
left++;
if (left < right)
num[right] = num[left];
}
num[left] = key; // 将随机选择的数存回
return left; // 返回随机选择的数分割数组的下标, 左边都是比它小的, 右边都是比它大的
}
中位数法线性时间选择划分:
AC代码:
#include <cstdio>
#include <cstdlib>
int num[2000001];
int select(int low, int high, int top);
int partition(int low, int high, int median);
void selectSort(int low, int high);
void swap(int &a, int &b);
int main()
{
int n, m, i;
while (~scanf("%d%d", &n, &m))
{
for (i = 0; i < n; i++)
scanf("%d", &num[i]);
printf("%d\n", select(0, n - 1, m - 1));
/*
for (i = 0; i < n; i++)
printf("%d%c", num[i], i < n - 1 ? ' ' : '\n');
*/
}
return 0;
}
// 中位数法线性时间选择
int select(int low, int high, int top)
{
// 小于75个数据随便用一个排序方法
if (high - low < 74)
{
selectSort(low, high); // 选择排序
return num[low + top]; // 排完序直接返回第low + top的数
}
int groupNum = (high - low - 4) / 5; // 每组5个数, 计算多少个组, 从0开始计数
for (int i = 0; i <= groupNum; i++)
{
int start = low + 5 * i; // 每组的起始位置
int end = start + 4; // 每组的结束位置
for (int j = 0; j < 3; j++) // 从小到大冒3个泡
for (int k = start; k < end - j; k++)
if (num[k] > num[k + 1])
swap(num[k], num[k+1]);
swap(num[low + i], num[start + 2]); // 每组的中位数交换到前面第low + i的位置
}
// 上面排完后, 数组low + 0 到 low + groupNum都是每一组的中位数
int median = select(low, low + groupNum, (groupNum + 1) / 2); // 找中位数的中位数
int p = partition(low, high, median); // 将数组分为两段, 左边的小于中位数的中位数, 右边的大于中位数的中位数
int n = p - low; // 计算p到low之间有多少个数, 后面得减掉
if (n == top)
return num[p]; // 如果运气好, 刚好要找的就是中位数
if (n > top)
return select(low, p - 1, top); // n比top大就在左边找
if (n < top)
return select(p + 1, high, top - n - 1); // n比top小就在右边找, 并且top要减去已经大的个数
}
// 以中位数进行分割, 分成两半
int partition(int low, int high, int median)
{
int p;
for (int i = low; i <= high; i++)
if (num[i] == median)
{
p = i;
break;
}
// 将中位数交换到最前面
swap(num[p], num[low]);
// 记下最前面的数
int key = num[low];
// 把小于key的放前面, 大于key的放后面
while (low < high)
{
while (num[high] >= key && low < high)
high--;
if (low < high)
num[low] = num[high];
while (num[low] <= key && low < high)
low++;
if (low < high)
num[high] = num[low];
}
// 分别从两头开始, 找到中间时, 把key存回
num[low] = key;
return low;
}
// 选择排序
void selectSort(int low, int high)
{
for (int i = low; i <= high; i++)
{
int MIN = i;
for (int j = i + 1; j <= high; j++)
if (num[MIN] > num[j])
MIN = j;
swap(num[i], num[MIN]);
}
}
// 交换两个元素
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
算法:线性时间选择(C/C++)的更多相关文章
- [图解算法]线性时间选择Linear Select——<递归与分治策略>
#include <ctime> #include <iostream> using namespace std; template <class Type> vo ...
- 【Unsolved】线性时间选择算法的复杂度证明
线性时间选择算法中,最坏情况仍然可以保持O(n). 原因是通过对中位数的中位数的寻找,保证每次分组后,任意一组包含元素的数量不会大于某个值. 普通的Partition最坏情况下,每次只能排除一个元素, ...
- 算法线性编程珠玑读书笔记之----->使用线性算法求解连续子序列的最大和
这段时间笔者几篇文章介绍了改算法线性的文章. 关联文章的地址 这个算法我在我的博客里应用动态规划做过,详细实现请参阅我的dp板块,下面给出书上最快的算法,时间复杂度为O(n),称之为线性算法. #in ...
- Top k问题(线性时间选择算法)
问题描述:给定n个整数,求其中第k小的数. 分析:显然,对所有的数据进行排序,即很容易找到第k小的数.但是排序的时间复杂度较高,很难达到线性时间,哈希排序可以实现,但是需要另外的辅助空间. 这里我提供 ...
- C++分治策略实现线性时间选择
问题描述: 给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素,即如果将这n个元素依其线性序排列时,排在第k个的元素即为要找到元素. 细节须知:(与之前的随笔相比) (1 ...
- 关于曲线 规划 算法 线性 S曲线 贝塞尔曲线
工控领域经常会涉及速度加减速的算法:线性加减速,S曲线加减速(sin函数,拓展其他三角函数曲线), 贝塞尔曲线,等等. 线性加减速: 设定起始速度V0,目标速度V1,加速时间Ta(s,或加速度) ...
- 查找第K小的元素(利用中位数线性时间选择)(C)
找任意第k个小的元素 #include <stdio.h> #include <stdlib.h> #include <ctime> #include <io ...
- 剑指Offer——分治算法
剑指Offer--分治算法 基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更 ...
- K:找寻数组中第n大的数组元素的三个算法
相关介绍: 给定一个数组,找出该数组中第n大的元素的值.其中,1<=n<=length.例如,给定一个数组A={2,3,6,5,7,9,8,1,4},当n=1时,返回9.解决该问题的算法 ...
随机推荐
- spring boot:用redis+lua限制短信验证码的发送频率(spring boot 2.3.2)
一,为什么要限制短信验证码的发送频率? 1,短信验证码每条短信都有成本制约, 肯定不能被刷接口的乱发 而且接口被刷会影响到用户的体验, 影响服务端的正常访问, 所以既使有图形验证码等的保护, 我们仍然 ...
- python 保存登录状态 cookie
import requests from lxml import etree import faker url = "https://www.yeves.cn/admin/Articles& ...
- python图片验证码识别最新模块muggle_ocr
一.官方文档 https://pypi.org/project/muggle-ocr/ 二模块安装 pip install muggle-ocr # 因模块过新,阿里/清华等第三方源可能尚未更新镜像, ...
- 服务器免密码登录 deployer
在本地(或者开发机)执行部署任务时我们不想每次输入密码,所以我们需要将 deployer 用户设置 SSH 免密码登录: 在本机生成 deployer 专用密钥,然后拷贝公钥: $ ssh-keyge ...
- 《Head First 设计模式》:剩下的模式
正文 一.桥接模式 1.定义 桥接模式通过将实现和抽象分离开来,放在两个不同的类层次中,从而使得它们可以独立改变. 要点: 当一个类存在两个独立变化的维度,而且都需要进行扩展时,可以将其中一个维度抽象 ...
- JUC---11单例模式
一.什么是单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.这种模式涉及到一个单一的类,该 ...
- vue-cli3使用jq
第一步安装 npm install jquery --save 第二部配置vue.config.js, 没有这个文件就创建 主要是框框出来的那些: 忽略我配置的另一个uglifyjs-webpack- ...
- 【转】Setting up SDL 2 on MinGW
FROM: http://lazyfoo.net/tutorials/SDL/01_hello_SDL/windows/mingw/index.php Setting up SDL 2 on MinG ...
- 框架-SPI四种模式+通用设备驱动实现
目录 前言 笔录草稿 SPI介绍 SPI四种模式 ** SPI 驱动框架 ** 框架 前言 SPI 介绍为搜集百度资料+个人理解 其余为原创(有误请指正) 集四种模式于一身 笔录草稿 SPI介绍 SP ...
- 工业级4G路由器有哪些优势
在金融.电力.邮政以及气象等各大行业中有着更为广泛的应用,并受到人们的高度推崇与青睐,那么工业级4G路由器有哪些优势深受用户的喜欢呢? 1.高稳定性 工业级4G路由器在传输和接收数据时具有较高的稳定性 ...