【问题标题】:Random generating a array of enum with no repeat elements (C++)随机生成一个没有重复元素的枚举数组(C++)
【发布时间】:2018-01-20 10:41:33
【问题描述】:

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

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;

    }
}

我做错了什么?

【问题讨论】:

  • Fruit f [size]; 其中size 不是编译时间常数,作为 C++ 代码无效,尽管它可以被一些编译器接受为语言扩展(然后可能以 C99 可变参数数组为模型)。请改用std::vector
  • 使用 0、1、2、3 等填充数组的一种简单方法是使用 std::iota。然后使用std::shuffle 打乱该数组。
  • @Cheersandhth.-Alf,即使我更改为 const 数字,它仍然有重复元素
  • 你为什么期望你的内部 for 循环来防止重复?
  • @Cheersandhth.-Alf,我不允许使用我在课堂上没有学过的东西来编码。所以vector和shuffle和iota,我不能使用。还是谢谢

标签: c++ arrays enums


【解决方案1】:

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

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

内循环开始,j 为 0。

f[i] = static_cast &lt;Fruit&gt;(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++ 功能(安全容器和预定义算法),并重新考虑您的整个程序逻辑。其他答案和 cmets 已经充分涵盖了这一点。

【讨论】:

  • 一些关于低效率和循环终止的词可以大大改善这个答案,恕我直言。另外,简单介绍一下标准解决方案。
  • @Cheersandhth.-Alf:也许吧。我认为如果它基于 OP 的原始方法并且实际上解释了为什么它没有按预期工作,那么答案可能更容易获得。至于标准解决方案,其他人已经介绍过了;不幸的是,OP 的老师似乎并没有“允许”它(叹气)。
  • @Cheersandhth.-Alf:话虽如此,关于循环终止的事情很重要,所以我将添加它。谢谢! :)
  • @ChristianHackl,我尝试使用具有相似代码的指针来检查重复项,但它仍然给我重复项,你能帮我看看我的代码的哪一部分出错了吗?非常感谢! pastebin.com/U0yve2rQ
  • @engkhsky:我从不查看发布在远程站点上的代码,但是如果您还可以提供 MCVE,您当然可以在 Stack Overflow 上提出一个新问题。
【解决方案2】:

获取带有枚举长度的数组,初始值为 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);

【讨论】:

  • 对不起,我不明白“每个枚举产生随机检查该数组中的索引是否为 0”的部分。能再解释一下吗?
【解决方案3】:

首先,不要创建变长数组,直接使用vector即可:

水果 f [大小];

枚举类型在这里不相关,因此要解决您的问题,您只需创建一个包含所有可能的 int 值的向量,然后对向量进行洗牌 (live example):

#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

【讨论】:

    【解决方案4】:

    如果您从集合中随机选择一个元素,然后准备好再次选择该元素,那么您会得到重复是很合理的。

    我会建议另一种方法。为什么不先对枚举数组进行随机排序,然后选择第一个 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;
    
    }
    

    【讨论】:

      【解决方案5】:

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

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

      私有 std::vector ::RanomFruit() { auto baseList = new List {Fruit::Durian, Fruit::Papaya, Fruit::Apple, Fruit::Orange, Fruit::Mango, Fruit::Jackfruit, Fruit::Strawberry};

      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;
      

      }

      【讨论】:

      • 这甚至不是 C++。
      猜你喜欢
      • 2016-05-15
      • 1970-01-01
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多