随机选择算法
来源:互联网 发布:java金额大写转换 编辑:程序博客网 时间:2024/05/22 03:19
问题描述:
本文主要讨论这样一个问题:如何从一个无序的数组中求出第k大的数。这个问题最直接的想法是对数组排一下序,然后直接取出第k个元素即可,这样做法需要O(nlogn)的时间复杂度。(这个方法比较简单,在运行时间允许的情况下当然选这个方法)下面介绍随机选择算法,它对任何输入都可以达到O(n)的期望时间复杂度。
基本思想:随机选择算法的原理类似于随机快速排序算法。当对A[left,right]执行一次randPartition函数之后,主元左侧的元素个数就是确定的,且它们都小于主元。假设此时主元是A[p],那么A[p]就是A[left,right]中的第一个p-left+1大的数。不妨令M表示p-left+1,那么如果k==M成立,说明第k大的数就是主元A[p];如果k<M成立,就说明第k大的数在主元右侧,即A[(p+1)...right]中的第k-M大,往右侧递归即可。算法以left==right作为递归边界,返回A[left]。由此可以写出随机选择算法代码:
void randSelect(int n[], int left, int right,int k){ if (left == right) return; int p = randPartition(n, left, right); int m = p - left + 1; if (k == m) return; if (k<m) { randSelect(n, left, p - 1, k); } else { randSelect(n, p + 1, right, k - m); }}
可以证明,虽然随机选择算法的最坏时间复杂度是O(n²),但是其对任意输入的期望时间复杂度却是O(n),这意味着不存在一组特定的数据能使这个算法达到最坏情况,是个相当实用和出色的算法。
ps:随机快速排序算法点击打开链接
应用:
给定一个由整数组成的集合,集合中的整数各不相同,现在要将它分为两个子集合,使得这两个子集合的并为原集合,交为空,同时在这两个子集合的元素个数n1和n2之差的绝对值尽可能小的情况下,它们各自的元素之和S1和S2之差的绝对值尽可能大。求|S1-S2|的值。
#include<cstdio>#include<cstdlib>#include<time.h>#include<cmath>#include<algorithm>using namespace std;//选取随机主元,对区间[left,right]进行划分int randPartition(int n[], int left, int right){ //生成[left,right]内的随机数p int p = round(rand() / RAND_MAX*(right - left) + left); swap(n[p], n[left]); //交换n[p],n[left];swap函数在头文件algorithm下 //以下为原先(快速排序)中的Partition函数的划分过程 int temp = n[left]; //将n[left]存放在临时变量temp中 while (left<right) //只要left和right不相遇 { while (left<right&&n[right]>temp) right--; n[left] = n[right]; while (left < right&&n[left] <= temp) left++; n[right] = n[left]; } n[left] = temp; //把temp放在left和right相遇的地方 return left; //返回相遇下标}//随机选择算法,从n[left,right]中找到第k大的数,并进行划分void randSelect(int n[], int left, int right,int k){ if (left == right) return; int p = randPartition(n, left, right); int m = p - left + 1; if (k == m) return; if (k<m) { randSelect(n, left, p - 1, k); } else { randSelect(n, p + 1, right, k - m); }}int main(){ srand((unsigned)time(NULL)); //初始化随机数种子 int n[] = {1,6,33,18,4,0,10,5,12,7,2,9,3}; int sum = 0; for (int i = 0; i < 13; i++) { sum += n[i]; } randSelect(n, 0, 13 - 1, 13 / 2); int sum1 = 0; for (int i = 0; i < 13/2; i++) { printf("%d ", n[i]); sum1 += n[i]; } printf("\n%d\n",n[13/2]); for (int i = 13/2+1; i < 13; i++) { printf("%d ", n[i]); } printf("\n%d\n", (sum - sum1) - sum1); return 0;}
阅读全文
0 0
- 随机算法之随机选择
- 随机选择算法
- 随机选择算法
- C++随机选择算法
- 随机选择算法
- 随机选择算法
- 随机洗牌算法和随机选择算法
- 算法导论之随机选择
- 游戏里随机概率选择算法
- 算法之冒泡、选择、递归、随机、循环
- 随机选择算法---Randomized Selection Algorithm
- [进化算法] 随机Q-竞争选择法
- 基于随机森林的特征选择算法
- uva11300分金币 随机选择算法
- 随机选择
- 随机选择
- 《算法导论》第9章 顺序统计学 (2)随机选择
- 从数据流中随机选择m个数的算法
- 汇编语言32位加减乘除运算题
- 实现宠物跟随移动效果
- ORACLE锁机制深入理解
- hdoj 6047( 2017 Multi-University Training Contest
- ROS动态参数设置dynamic_reconfigure出现“no rules to make”config文件时的方法
- 随机选择算法
- Spring 的核心机制:依赖注入(控制反转)
- 回溯之机器人的运动范围
- 2.class 和 public class的区别
- ES6(babel)环境搭建
- 九度1458:汉诺塔问题Ⅲ
- numpy中的axis=0,axis=1
- log4j 不同模块输出到不同的文件
- Ecilpse快捷键