随机生成一个没有重复元素的枚举数组 (C++)

Random generating a array of enum with no repeat elements (C++)

本文关键字:元素 枚举 C++ 数组 随机 一个      更新时间:2023-10-16

我正在尝试生成一个没有相同元素的枚举数组,但我所做的仍然给了我重复的元素

const int MAXNO = 6;
enum Fruit {Durian, Papaya, Apple, Orange, Mango, Jackfruit, Strawberry};
int main ()
{
srand (time (NULL));
int size = rand () % 6 + 1;
Fruit f [size];
cout << "Size: " << size << endl;
for (int i = 0; i < size; i++)
{
f[i] = static_cast <Fruit>(rand() % MAXNO);
for (int j = 0; j < i; j++)
{
do 
{
f[i] = static_cast <Fruit>(rand() % MAXNO);
}while(f[i] == f[j]);
}       
cout << f[i] << endl;
}
}

我做错了什么?

您的内部循环旨在检查其他数组元素是否存在重复项,但一旦一个元素不是重复项,您就会提前终止检查。换句话说,您不搜索重复项,而是搜索非重复项

假设i是 2,f[0]Applef[1]Orange

内部循环启动,j为 0。

f[i] = static_cast <Fruit>(rand() % MAXNO);创建一个Orange。它应该被检测为重复项,但事实并非如此。

怎么来了?

这是因为在do...while条件下,您将f[2]f[0]进行比较。它们不相等,因此循环终止。

根据您原始方法,快速解决此问题的是比较所有元素的相等性,理想情况下在单独的函数中:

bool exists(Fruit* begin, Fruit* end, Fruit fruit)
{
for (Fruit* iter = begin; iter != end; ++iter)
{
if (*iter == fruit)
{
return true;
} 
}
return false;
}

然后将循环更改为如下所示的内容:

for (int i = 0; i < size; i++)
{
bool duplicate = false;
do
{
f[i] = static_cast <Fruit>(rand() % MAXNO);
duplicate = exists(f, f + i, f[i]);
} while (duplicate);
}

但是这个解决方案仍然存在一些问题,最严重的(在我看来)是循环终止条件取决于随机运气。从理论上讲,该程序可能会循环很长时间甚至永远。

更好的设计是使用老师显然不允许您使用的所有标准C++功能(安全容器和预定义算法),并重新考虑整个程序逻辑。其他答案和评论已经充分涵盖了这一点。

获取数组的枚举长度和初始值为 0,并且对于每个随机枚举生成,检查该数组中的索引为 0,如果为 true,则使该数组上的枚举索引为 1。

获取枚举大小的数组长度 并以 0 开头

int produced_value[MAXNO] = {0}; //be new array
-------------------------
| 0 | 0 | 0 | 0 | 0 | 0 |
-------------------------

这个数组显示了哪个枚举以前产生过。 每次生成随机枚举并希望在检查该数组之前不生成枚举时。如果该数组中的索引为零,则之前未生成且不重复元素使用它并更新数组。

例如

int a;
while(produced_value[(a = rand() % MAXNO)]); //this loop find a that value in produced_value is 0
/* if a == 2 then should update array
-------------------------
| 0 | 0 | 1 | 0 | 0 | 0 |
---------~~~-------------
*/
produced_value[a] = 1; // mark 'a' as produced 
//Then use Unique int in the enum range
f[i] = static_cast <Fruit>(a);

首先,不要创建一个可变长度的数组,只使用 vector:

果实 f [大小];

枚举类型在这里无关紧要,所以要解决你的问题,你可以创建一个包含所有可能的 int 值的向量,然后洗牌向量(实时示例):

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>

const int MAXNO = 6;
int main ()
{
std::vector<int> v;
v.reserve(MAXNO);
for (int i = 0; i < MAXNO; ++i)
{
v.push_back(i);   
}
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
for (auto& e: v)
{
std::cout << e << " ";
}
}

3 4 0 1 2 5

如果您从集合中随机选择一个元素,然后使该元素准备好再次拾取,则获得重复项是相当合理的。

我建议另一种办法。为什么不先随机排序枚举数组,然后选择第一个size元素?通过这种方式,您不会获得重复项,并且始终以随机顺序排列第一个size元素。 另请注意,您有7枚举,这意味着MAXNO应该7否则像int size = rand () % MAXNO;这样的表达式永远不会返回6这是列表Strawberry中的有效枚举。

如下所示,某些东西应该可以工作:

#include <iostream>
#include <chrono>
using namespace std;
const int MAXNO = MAXNO*2;
enum Fruit {Durian, Papaya, Apple, Orange, Mango, Jackfruit, Strawberry};
int main ()
{
srand (time (NULL));
Fruit ff [Strawberry+1] = {Durian, Papaya, Apple, Orange, Mango, Jackfruit, Strawberry};
const int NIT = 7;
for(int i=0 ; i < NIT ; i++ ){
const int ii = (rand() % MAXNO);
const int jj = (rand() % MAXNO);
swap(ff[ii],ff[jj]);
}
//simply output the firse `size` element
//from the randomly ordered array.
const int size = rand () % MAXNO;
for (int i=0;i<size;i++)
cout<<ff[i]<<endl;
}

您可以使用以下代码: 如果您对此有任何问题,请告诉我

enum Fruit {Durian, Papaya, Apple, Orange, Mango, Jackfruit, Strawberry};

私有标准::矢量 ::RanomFruit() { 自动基本列表 = 新列表 {水果::D urian, 水果::P apaya

, 水果::苹果, 水果::橙子, 水果::芒果, 水果::菠萝蜜, 水果::草莓};
auto fruitArray = std::vector<Fruit>(7);
Random *random = new Random();
for (int i = 0; i <= 6; i++)
{
int randNumber = random->Next(6 - i);
fruitArray[i] = baseList[randNumber];
baseList->RemoveAt(randNumber);
}
return fruitArray;

}