【问题标题】:How can I generate random int numbers within a set range (without duplicates!) within a class constructor?如何在类构造函数中生成设定范围内的随机 int 数(不重复!)?
【发布时间】:2011-12-23 14:26:30
【问题描述】:

我正在通过教科书自学 C++,我有一个问题需要解决,概述如下。

我有以下类结构:

 #include <iostream>
 #include <cstdio>
 #include <ctime> 

 using namespace std;


   class classroom{

     char name[25];
     int student_id;
     float grades[10];
     float average;
     int num_tests;
     float letter_grade;

   public:       
     void enter_name_id(void);
     void enter_grade(void);
     void average_grades(void);
     void letter_grades(void);
     void output_name_id_grade(void);
     classroom();

   };

我为上述类提供了以下构造函数:

 classroom::classroom(){

      int i;

      srand((unsigned)time(0));
      int random_integer=0; 
      random_integer = (rand()%5) + (rand()%5); 

      num_tests=0;
      average=0.0;

      for(i=0;i<10;i++){

        grades[i]=0.0;

      }

      for(i=0;i<27;i++){

         name[i]='-';       
      }
      cout<<"\n*****************Finished*****************";
 }

main 中声明了这个班级结构的 3 名学生:

int main()
{       
  classroom students[3]; 
//and so...

}

我需要为构造函数中的每个学生生成一个唯一的学生 ID,其值范围为 0 到 10。

我已将以下代码 sn-p 复制到构造函数中。它会在所需范围内为我生成随机数:

srand((unsigned)time(0));
  int random_integer=0; 
  random_integer = (rand()%5) + (rand()%5);

问题是我需要删除生成的随机数范围内的任何重复项。

【问题讨论】:

  • 更正:int random_integer=0;应该读为 int random_integer;
  • 你为什么 1) 使用 2 个随机数的总和(这基本上 给你一个所需范围内的随机数) 2) 假设一个随机数可以服务作为标识符?
  • 请注意,类名非常具有误导性——该对象似乎更接近student 而不是classroom。你应该考虑像描述它们一样命名你的类——在这种情况下,它们代表并包含关于学生的数据——所以它们应该被命名为Student
  • re:correction -- 将其初始化为 0,然后将其设置为其他值,这很好,实际上是一种很好的编码习惯。
  • 不确定代码是如何工作的,就像我说的那样,我只是复制了它。但它似乎符合我的要求(即生成 0 到 10 之间的数字)。我确实尝试过考虑主要问题的替代方案,但这是我能想到的第一个解决方案。

标签: c++ class random constructor


【解决方案1】:

为什么数字需要是随机的?难道你不能只使用一个静态 int,每次你需要生成一个新的学号时都会递增?

【讨论】:

  • 因为类中的私有字段只能从公共成员函数访问,而不能直接从主程序访问。
  • 生成的任何数字都需要从类的每个实例中携带。这比听起来容易!!!
  • 并且构造函数在运行时不知道该类的其他实例的存在,直到它们在主中声明。无论如何,这就是我的看法。所以我相信当你最初遇到这个问题时,它并不像听起来那么简单。
  • 我相信 jedward 上面提到的静态成员变量。这可能是解决这个问题的关键
  • 这些原因都不能解释为什么学生 ID 需要随机。添加一个静态变量static int next_student_id = 0,然后在您的构造函数中执行student_id = next_student_id++。然后只需添加一个返回 student_id 的get_student_id() 成员函数。
【解决方案2】:

只需一个包含所有可能学生 ID 的向量。在你的情况下 0..Range。

执行random_shuffle 并选择前三个 id 并分配它们

我添加了一个可行的解决方案。

//Only have one instance of this class.
class IdMgr
{
    std::vector<int> mIds;
    int mCurrentId;
public:
    IdMgr( int Max )
    {
        for ( int i = 0 ; i <= Max; ++i )
            mIds.push_back( i );

        std::random_shuffle( mIds.begin() , mIds.end() );

        mCurrentId = 0;
    }

    //Call this function from your class constructor
    int GetNextId()
    {
        return mIds[ mCurrentId++];
    }
};

【讨论】:

  • 是的,我可以这样工作,我将不得不看看随机洗牌是如何在向量上工作的。但这仍然可以防止重复吗??
  • 它可以防止重复,但你不能像你问的那样在构造函数中这样做。这确实不能解决问题,而且可能具有误导性。
  • 为什么它不起作用...只需将 i = 0 存储为最后一个 id 使用。每个类都可以在构造函数中从向量中为自己分配一个 id 并在之后增加 i 。 id 将是随机的,也不会重复自己
  • @Mr_leighman 不,random_shuffle 不会删除容器中的重复元素。如果您需要从容器中删除重复项,请使用std::unique_copy
  • @Mahesh... 你觉得 random_shuffle 有什么作用?
【解决方案3】:

一种方法是使用所谓的静态成员变量。通常,每个对象都有自己的成员变量副本。在您的代码中,每个学生都将拥有自己的 name[25]student_id 等副本。但是您想要的是在班级的每个实例之间共享的东西(classroom students[3] 中的每个元素都是实例classroom 类。)

这里有一些关于static member variables 的注释。请注意,它们为非常相似的问题提供了一种解决方案——它们为每个类实例分配了唯一的 ID。他们在此处显示的内容与您要求的内容之间的唯一区别是您要求它是随机的,而不是连续的。

因此,您将希望静态成员变量跟踪所有先前分配的 ID,而不是使用静态成员变量跟踪一个数字(分配的最后一个)。 std.vector 或简单的 int 数组应该可以工作。


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h> 
#include <vector>

using namespace std;


class classroom{
    char name[25];
    int student_id;
    float grades[10];
    float average;
    int num_tests;
    float letter_grade;

    static vector<int> used;

public:       
    void enter_name_id(void);
    void enter_grade(void);
    void average_grades(void);
    void letter_grades(void);
    void output_name_id_grade(void);
    classroom();
};

vector<int> classroom::used = vector<int>();

classroom::classroom(){
    int i;
    int random_integer=0; 
    bool rand_ok;
    do
    {
        // Generate Random Integer
        random_integer = (rand()%5) + (rand()%5); 
        //cout << "Generated: " << random_integer << endl;

        rand_ok = true;
        for(i=0; i<used.size(); i++)
        {
            if(used[i] == random_integer){ rand_ok = false; break; }
        }

    } while (rand_ok == false);

    // If we get here, random_integer is not in the used vector
    // therefore accept and store as student_id
    student_id = random_integer;    
    // ... and update used vector
    used.push_back(student_id);

    num_tests=0;
    average=0.0;

    for(i=0;i<10;i++){

    grades[i]=0.0;

    }

    for(i=0;i<27;i++){

     name[i]='-';       
    }
    cout<<"*****************Finished*****************\n";
}


int main()
{       
    // You should only seed the RNG once
    srand((unsigned)time(0));
    classroom students[3]; 
}

上面的代码是您可以做到的一种方式,将使用的学生 ID 存储在一个向量中,然后每次创建新学生时,确保随机生成的 ID 与已分配的 ID 不匹配。

另一个注意事项,您应该只为随机数生成器播种一次(特别是如果您的种子是时间)。由于您在这么短的时间内播种了 3 次,因此生成的随机数是相同的。

【讨论】:

  • 我相信您的上述答案符合我的需要。如果我不需要生成随机数并且只需要我可以使用的连续数字,那么只要实现我的目标,我就会使用连续数字:即唯一标识类的每个实例。谢谢
  • 我提供的代码将生成随机唯一数字。如果你想要连续的(也是唯一的)数字,你可以将static vector&lt;int&gt; used;更改为static int last_used;,将vector&lt;int&gt; classroom::used = vector&lt;int&gt;();更改为int classroom::last_used = 0并将我的解决方案的第33-53行替换为student_id = last_used++;
  • 我有类似的设置,似乎每次创建对象的实例时都会得到相同的结果。这是为什么呢?
【解决方案4】:

对于所有想知道我为类的每个实例创建唯一 id 的问题的解决方案的人,这里是:

class classroom{

         char name[25];
         int student_id;
         float grades[10];
         float average;
         int num_tests;
         float letter_grade;

         **static int next_student_id;**

  public:       
         void enter_name_id(void);
         void enter_grade(void);
         void average_grades(void);
         void letter_grades(void);
         void output_name_id_grade(void);
         classroom();
  };

         **int classroom::next_student_id=1;**

注意,新成员:static int next_student_id已经被创建并在构造函数中使用,它也在类结构之外被初始化。

在构造函数中,我只使用了以下代码:

student_id=next_student_id++;

此代码为班级教室结构的每个实例生成唯一的连续数字; 请注意,我知道班级教室不是一个理想的名称,因为它与班级名称冲突,但我使用了这个名称,因为我从教科书问题中复制了基本命名!

我得出的结论是,Alan 上面的回答对我帮助最大,并为我提供了最简单的解决方案。因此,Alan 得到了我的认可。

我还要感谢 Jedwards,如果你追求你的答案也可能是一个替代解决方案......但事实证明,使用静态 int 是关键,并且不需要生成随机数和创建向量。

还要感谢 parapura rajkumar 和其他贡献者

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 2012-12-03
    相关资源
    最近更新 更多