编程珠玑: 12章 取样问题 12.1程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复-------解题总结

随机有序选择算法
本文介绍了一个算法,用于从0到n-1范围内随机选择m个不同的整数,并确保这些整数是有序的且每个选择的概率相等。文章详细解释了蓄水池抽样的原理,并给出了具体的实现代码。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>

using namespace std;
/*
问题:程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。从概率的角度说,我们希望得到没有重复的有序选择,其中
    每个选择出现的概率相等。
分析:这个感觉是蓄水池抽样问题。先设置0~m-1为前m个随机整数,然后对于i从m开始,生成随机数k,如果k < m - 1,就将i和k进行调换。
     下面证明该程序的等概率:假设从1~n个数中随机选择m个不同的数,且概率相等。
	 假设当前为第i+1个数,则第i+1个数出现在蓄水池的概率为m/(i+1),现在证明前面i个数中出现在蓄水池的概率也为m(i+1)【先以简单的部分作为论点,论述
	 前面较难的条件成立】
	 证明:前面i个数出现蓄水池的概率=第i+1次选择前出现在蓄水池的概率 * 第i+1次选择不被替换的概率
								    = m/i  * (1 - 第i+1次选择被替换的概率)
									= m/i * (1 - 1/(i+1) = m/(i+1)

关键:
1 证明前面i个数出现在蓄水池的概率和第i+1个数出现在蓄水池的概率相同
2 蓄水池步骤:1 将原数组A[1...m]赋值给新数组B[1...m],对于x属于m+1~n,随机得到一个数k,若k <= m ,就交换B[x]和B[k]


输入:
10(随机选择的数) 100(整数范围n)
输出:
10个不同元素组成的有序列表
*/

int randRange(int min , int max)
{
	if(min > max)
	{
		int temp = min;
		min = max;
		max = temp;
	}
	return ( rand() % (max - min + 1) + min );
}

//生成0~n-1中m个随机选择的不重复的数组成的有序列表
vector<int> getRandomVector(int m , int n)
{
	vector<int> results;
	//前面m个数的直接拷贝
	for(int i = 0 ; i < m ; i++)
	{
		results.push_back(i);
	}

	//后面的随机替换
	for(int i = m ; i < n ; i++)
	{
		int k = randRange(0 , n - 1);
		if(k <= m - 1)
		{
			results.at(k) = i;
		}
	}

	//替换后的结果注意要排序
	sort(results.begin() , results.end());
	return results;
}


void print(vector<int>& results)
{
	if(results.empty())
	{
		cout << "no result" << endl;
		return;
	}
	int size = results.size();
	for(int i = 0 ; i < size; i++)
	{
		cout << results.at(i) << " ";
	}
	cout << endl;
}

void process()
{
	int m , n;
	vector<int> results;
	while(cin >> m >> n)
	{
		results = getRandomVector(m , n);
		print(results);
	}
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值