Bootstrap

从1到100随机20个不重复的数字出来c++

//从1到100随机20个不重复的数字出来
//已有下面函数,随机生成一个[min, max]的数
int myRand(int min, int max);

一开始想的是使用set和vector来保存已经随机生成的数,每次要生成新的数的时候,就要通过set来判断是否已经重复。

void Get20RandomNum()
{
	//集合,用来判断数字是否存在,加快查询
	set<int> mySet;

	//vector,用来存储随机数
	vector<int> arr(20);

	//myRand调用次数,防止出现未知bug导致while无法终止
	int count = 0;

	//目前已经获得的不重复的随机数
	int num = 0;

	std::set<int> vals;

	while (count <= 10000 && num < 20)
	{
		int randVal = myRand(0, 100);
		if (mySet.find(randVal) == mySet.end())
		{
			mySet.insert(randVal);
			arr[num] = randVal;
			num++;
		}
		count++;
	}
	assert(mySet.size() == 20 && arr.size() == 20, "error");

	for (auto val : arr)
	{
		cout << val << " ";
	}

}

但是这有一个问题,就是具备一个极小的概率,每次新生成的数都是原来的,这样就永远不会得到全部的随机数,因此上面判断count次数是否超过10000,防止while循环永远不会结束,但是这样也没有真正解决问题。

下面使用了另外一种方法进行补充。

codes保存已经生成的随机数,然后myRand生成的范围是剔除了生成的随机数数量后的,例如codes里面有[2]一个数,那么范围应该是100- 1 = 99。每次生成的是偏移量。例如myRand(1, 99)返回2,那么就应该从1开始偏移2,由于2已经生成了,则跳过,为3

在这里插入图片描述

int Get1RandowmNum(std::set<int> codes)
{

	//产生从1到剩余区间的偏移
	int randVal = myRand(0, 100 - codes.size());

	int count = 0;
	for (int i = 1; i <= 100; i++)
	{
		if (codes.count(i) > 0)
		{
			continue;
		}

		count++;
		if(randVal == count)
		{
			return i;
		}
	}

	return 0;
}

这样的复杂度有点大,但是可以作为上面第一个方法的补充,即当循环了10000次仍然不能得到结果的时候,可以选择这个方法进行补充。

;