随机选择算法

  随机选择算法和快速排序原理相似,所以有时候也称作“快速选择算法”,一般选择问题可以证明都能在O(n)时间内完成。随机选择算法的期望运行时间为线性时间,即Θ(n),但其最坏情况运行时间为O(n^2)。最坏情况与快排一样,都是运气不好导致划分不均匀。

  代码:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdlib.h>

class QuicklySelect {
public:
	template<class T>
	void swap(T & a, T & b)
	{
		T tem = a;
		a = b;
		b = tem;
	}

	int Partition(std::vector<int> & nums, int start, int end)
	{
		int tem = nums[end];
		int i = start - 1;
		for (int j = start; j < end; j++)
		{
			if (nums[j] <= tem)
			{
				i += 1;
				swap(nums[i], nums[j]);
			}
		}
		swap(nums[i + 1], nums[end]);
		return i + 1;
	}

	int RandomizedPartition(std::vector<int> & nums, int start, int end)
	{
		int i =  start + rand() % (end - start);
		swap(nums[i], nums[end]);
		return Partition(nums, start, end);
	}

	int RandomizedSelect(std::vector<int> & nums, int start, int end, int i)
	{
		if (nums.empty())	return 0;
		if (start == end)	return nums[start];
		int mid = RandomizedPartition(nums, start, end);
		int k = mid - start + 1;
		if (i == k)
			return nums[mid];
		else if (i < k)
			return RandomizedSelect(nums, start, mid - 1, i);
		else
			return RandomizedSelect(nums, mid + 1, end, i - k);
	}
};

int main()
{
	std::vector<int> nums { 5,3,1,4,2 };//5 3 1 2 4

	std::cout << "结果:" << QuicklySelect().RandomizedSelect(nums, 0, nums.size() - 1, nums.size() + 1 - 2) << std::endl;

	getchar();
	return 0;
}

  运行结果:

  

  即4是数组中第2大,第4小的数。

  算法题:给定一个大小为n的一维无序数组,从数组中找出前k个最大数,最佳时间复杂度是多少?实际应用中我能想到比如网易云的听歌排行榜会列举出听歌次数最多的前100首歌曲。

  这个题我是在刷知乎时看到的,但找不到那个问题了...若不要求对top k 进行排序,则利用随机选择算法可使期望运行时间达到Θ(n),空间复杂度O(k);若排序则运行时间为Θ(n + klogk),当最坏情况为找所有最大数并排序时,就是排序了,利用快排则时间复杂度为Θ(nlgn)

  代码:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <stdlib.h>

class QuicklySelect {
public:
	template<class T>
	void swap(T & a, T & b)
	{
		T tem = a;
		a = b;
		b = tem;
	}

	int Partition(std::vector<int> & nums, int start, int end)
	{
		int tem = nums[end];
		int i = start - 1;
		for (int j = start; j < end; j++)
		{
			if (nums[j] <= tem)
			{
				i += 1;
				swap(nums[i], nums[j]);
			}
		}
		swap(nums[i + 1], nums[end]);
		return i + 1;
	}

	int RandomizedPartition(std::vector<int> & nums, int start, int end)
	{
		int i =  start + rand() % (end - start);
		swap(nums[i], nums[end]);
		return Partition(nums, start, end);
	}

	int RandomizedSelect(std::vector<int> & nums, int start, int end, int i)
	{
		if (nums.empty())	return 0;
		if (start == end)	return nums[start];
		int mid = RandomizedPartition(nums, start, end);
		int k = mid - start + 1;
		if (i == k)
			return nums[mid];
		else if (i < k)
			return RandomizedSelect(nums, start, mid - 1, i);
		else
			return RandomizedSelect(nums, mid + 1, end, i - k);
	}

	std::vector<int> Top(std::vector<int> nums, int k)
	{
		std::vector<int> top;
		top.push_back(RandomizedSelect(nums, 0, nums.size() - 1, nums.size() + 1 - k));
		for (int i = 0; i < nums.size(); i++)
		{
			if (nums[i] > top[0])
				top.push_back(nums[i]);
		}

		return top;
	}

};

int main()
{
	std::vector<int> nums { 5345,332,2341,498,248,89,239,4825,8,43,9892,872,1843 };
	std::vector<int> top = QuicklySelect().Top(nums, 5);

	for (int i = top.size() - 1; i >= 0; i--)
		std::cout << "top" << top.size() - i << ‘:‘ << top[i] << std::endl;

	getchar();
	return 0;
}

  记得知乎大多数同学使用的是建最大堆的方法,时间复杂度为O(nlgk),空间复杂度为O(k),时间复杂度应该还可以优化。

原文地址:https://www.cnblogs.com/darkchii/p/8534836.html

时间: 2024-10-12 13:45:38

随机选择算法的相关文章

算法系列笔记2(静态表顺序统计-随机选择算法)

问题:当给定存在静态表(如数组)中的n个元素,如何快速找到其中位数.最小值.最大值.第i小的数? 首先想到的方法是先对数组元素进行排序,然后找到第i小的元素.这样是可行的,但比较排序最快也需要O(nlgn),能否在线性时间内解决呢.这就是随机的分治法-随机选择. 思想:利用随机划分(在快速排序中介绍过)找到主元r,这样就将小于等于r的元素放在了其左边,大于r的元素放在了其右边.这是可以计算出r的rank为k,如果正好等于i,则就返回该元素:如果k大于i,则在左边中寻找第i小的元素,否则在右边中寻

Randomize select algorithm 随机选择算法

从一个序列里面选择第k大的数在没有学习算法导论之前我想最通用的想法是给这个数组排序,然后按照排序结果返回第k大的数值.如果使用排序方法来做的话时间复杂度肯定至少为O(nlgn). 问题是从序列中选择第k大的数完全没有必要来排序,可以采用分治法的思想解决这个问题.Randomize select 算法的期望时间复杂度可以达到O(n),这正是这个算法的迷人之处.具体的算法分析可以在<算法导论>这本书里查看. 贴出伪代码: RANDOMIZED-SELECT(A, p, r, i) 1 if p =

线性选择算法(未完成)

#include "stdafx.h" #include<iostream> #include <stdlib.h> #include <time.h> using namespace std; #define SB -1 int RANDOM(int p, int r) { srand((unsigned)time(NULL)); return (rand() % (r - p + 1)) + p; } int partition(int a[],

Bagging与随机森林算法原理小结

在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合.本文就对集成学习中Bagging与随机森林算法做一个总结. 随机森林是集成学习中可以和梯度提升树GBDT分庭抗礼的算法,尤其是它可以很方便的并行训练,在如今大数据大样本的的时代很有诱惑力. 1.  bagging的原理 在集成学习原理小结中,我们给Bagging画了下面一张原理图. 从上图可以看出,

R语言︱决策树族——随机森林算法

笔者寄语:有一篇<有监督学习选择深度学习还是随机森林或支持向量机?>(作者Bio:SebastianRaschka)中提到,在日常机器学习工作或学习中,当我们遇到有监督学习相关问题时,不妨考虑下先用简单的假设空间(简单模型集合),例如线性模型逻辑回归.若效果不好,也即并没达到你的预期或评判效果基准时,再进行下换其他更复杂模型来实验. ---------------------------------------------- 一.随机森林理论介绍 1.1 优缺点 优点. (1)不必担心过度拟合

带权随机数问题--根据权重随机选择一条路径

最近工作中遇到了一个根据权重随机选择一条路径的问题,一时没有啥好方案,参考借鉴了网上的经验,得出了如下解决方案: 思路:1.求权重的和,对(0,权重之歌和]区间进行划分,每个权重占用长度为权重的区间: 2.产生一个在(0,权重之和]区间的等概率随机数: 3.该随机数落在哪个区间,则该区间对应的权重的映射为本次产生的带权随机数. 1 import java.util.ArrayList; 2 import java.util.HashMap; 3 import java.util.List; 4

随机森林 算法过程及分析

简单来说,随机森林就是Bagging+决策树的组合(此处一般使用CART树).即由很多独立的决策树组成的一个森林,因为每棵树之间相互独立,故而在最终模型组合时,每棵树的权重相等,即通过投票的方式决定最终的分类结果. 随机森林算法主要过程: 1.样本集的选择. 假设原始样本集总共有N个样例,则每轮从原始样本集中通过Bootstraping(有放回抽样)的方式抽取N个样例,得到一个大小为N的训练集.在原始样本集的抽取过程中,可能有被重复抽取的样例,也可能有一次都没有被抽到的样例. 共进行k轮的抽取,

第九章 中位数和顺序统计量 9.2 期望为线性时间的选择算法

package chap09_Medians_and_Order_Statistics; import static org.junit.Assert.*; import java.util.Random; import org.junit.Test; public class SearchAlorithms { /** * 分割(快速排序中对数组的分割) * * @param n * @param start * @param end * @return */ protected static

我的游戏服务器类库 -- 按权重随机选择1个或n个对象

按权重选择 在编写游戏服务器的时候,经常会遇到类似的需求:从列表中随机选出1个或多个条目,且条目是有权重的(权重越大,选中它的可能性就越大).比如说,砍死一个怪物可以从一个装备列表里掉一个装备.这种需求,和现实生活中的幸运大转盘很类似: 算法实现 因为这种需求很常见,所以我想把它写的通用一点.首先,接口Weighted表示有权重值的对象,getWeight()方法返回权重值: public interface Weighted { public int getWeight(); } Weight