//从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次仍然不能得到结果的时候,可以选择这个方法进行补充。