Как я могу генерировать случайные числа int в пределах заданного диапазона (без дубликатов!) в конструкторе класса?

#c #class #random #constructor

#c #класс #Случайный #конструктор

Вопрос:

Я самостоятельно изучаю 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*****************";
 }
  

Будет 3 ученика этой структуры класса, объявленной в main :

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

}
  

Мне нужно сгенерировать уникальный идентификатор учащегося для каждого учащегося в конструкторе в диапазоне значений, скажем, от 0 до 10.

Я скопировал следующий фрагмент кода в конструктор. Он генерирует мое случайное число для меня в пределах желаемого диапазона:

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

Проблема в том, что мне нужно избавиться от любых дубликатов в пределах диапазона генерируемых случайных чисел.

Комментарии:

1. Исправление: int random_integer=0; следует читать int random_integer;

2. Почему вы 1) используете эту сумму из 2 случайных чисел (которая в принципе не дает вам случайное число в желаемом диапазоне) 2) предполагаете, что случайное число может служить идентификатором?

3. Небольшое замечание: имя класса вводит в заблуждение — объект кажется ближе к student , чем к classroom . Вам следует подумать о том, чтобы называть свои классы так же, как вы бы их описали — в этом случае они представляют и содержат данные об ученике — поэтому они должны называться примерно так Student .

4. re: исправление — инициализировать его равным 0, а затем установить его равным чему-то другому, прекрасно и на самом деле является хорошей практикой кодирования.

5. Не уверен, как работает код, как я уже сказал, я просто скопировал его. но, похоже, он делает то, что мне требуется (т. Е. генерирует число от 0 до 10). и я попытался придумать альтернативы моей основной проблеме, но это первое решение, которое я смог придумать.

Ответ №1:

Почему число должно быть случайным? Разве вы не можете просто использовать статический int, который увеличивается каждый раз, когда вам нужно сгенерировать новый номер ученика?

Комментарии:

1. Поскольку закрытые поля в классе доступны только из общедоступных функций-членов, а не непосредственно из основной программы.

2. любое сгенерированное число должно быть перенесено из каждого экземпляра класса. это проще, чем кажется!!!

3. И конструктор при запуске не знает о существовании других экземпляров класса, пока они не будут объявлены в main. в любом случае, я так это вижу. Поэтому я считаю, что это не так просто, как кажется, когда вы изначально сталкиваетесь с этой проблемой.

4. Я полагаю, что jedward упоминал выше статические переменные-члены. это может быть ключом к решению этой проблемы

5. ни одна из этих причин не объясняет, почему идентификатор студента должен быть случайным . Добавьте статическую переменную static int next_student_id = 0 , затем в вашем конструкторе сделайте student_id = next_student_id . Затем просто добавьте get_student_id() функцию-член, которая возвращает student_id.

Ответ №2:

Просто создайте вектор со всеми возможными идентификаторами учащихся. в вашем случае 0 .. Диапазон.

выполните random_shuffle и выберите первые три идентификатора и назначьте их

Я добавил рабочее решение.

 //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  ];
    }
};
  

Комментарии:

1. Да, я мог бы это сделать, мне нужно будет посмотреть, как случайная перетасовка работает с вектором. Но будет ли это по-прежнему предотвращать дубликаты??

2. Это предотвратило бы дубликаты, но вы не можете сделать это из конструктора, как вы просите. Это действительно не решает проблему и, вероятно, вводит в заблуждение.

3. Почему это не сработает… Просто сохраните i = 0 как последнее использование идентификатора. Каждый класс может присвоить себе идентификатор в конструкторе из вектора и впоследствии увеличить i. идентификатор будет случайным и также не будет повторяться

4. @Mr_leighman Нет, random_shuffle не удаляет повторяющиеся элементы в контейнере. Если вам нужно удалить дубликаты из контейнера, используйте std::unique_copy

5. @Mahesh… Как вы думаете, что делает random_shuffle ?

Ответ №3:

Один из способов сделать это — использовать то, что называется статической переменной-членом. Обычно каждый объект получает свою собственную копию переменных-членов. В вашем коде у каждого учащегося будет своя копия name[25] , student_id и т.д. Но то, что вы хотите, это то, что будет общим для каждого экземпляра класса (каждый из элементов в classroom students[3] являются экземплярами classroom класса.)

Вот несколько заметок о статических переменных-членах. Обратите внимание, что они представляют собой решение очень похожей проблемы — они присваивают уникальные идентификаторы каждому экземпляру класса. Единственное различие между тем, что они представляют здесь, и тем, что вы запрашиваете, заключается в том, что вы просите, чтобы оно было рандомизированным, а не последовательным.

Таким образом, вместо статической переменной-члена, отслеживающей одно число (последнее назначенное), вы захотите, чтобы ваша статическая переменная-член отслеживала все ранее назначенные идентификаторы. Должен работать 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]; 
}
  

Приведенный выше код — это один из способов, которым вы могли бы это сделать, сохраняя используемые идентификаторы учащихся в векторе, а затем каждый раз, когда вы создаете нового ученика, убедитесь, что случайно сгенерированный идентификатор не соответствует уже назначенному идентификатору.

Еще одно замечание: вы должны запускать генератор случайных чисел только один раз (особенно если ваше начальное значение — это время). Поскольку вы заполняли его 3 раза за такое короткое время, создаваемые случайные числа были одинаковыми.

Комментарии:

1. Я полагаю, что ваш приведенный выше ответ соответствует тому, что мне нужно. Если мне не нужно генерировать случайные числа и меня устраивают только последовательные числа, я буду просто использовать последовательные числа до тех пор, пока я достигаю своей цели: уникальной идентификации каждого экземпляра класса. Спасибо

2. Предоставленный мной код будет генерировать случайные уникальные числа. Если вам нужны последовательные (также уникальные) числа, вы можете изменить static vector<int> used; на static int last_used; , изменить vector<int> classroom::used = vector<int>(); на int classroom::last_used = 0 и заменить строки 33-53 моего решения на student_id = last_used ; .

3. У меня аналогичная настройка, и кажется, что каждый раз, когда я создаю экземпляр своего объекта, я получаю тот же результат. Почему это?

Ответ №4:

Для всех тех, кто хочет знать решение моей проблемы создания уникального идентификатора для каждого экземпляра класса, вот оно:

 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  ;
  

Этот код создавал уникальные последовательные номера для каждого экземпляра структуры класса classroom;
Пожалуйста, обратите внимание, что я знаю, что Class classroom не является идеальным именем, поскольку оно конфликтует с именем class, но я использовал это, поскольку скопировал базовое название из вопроса учебника!

Я пришел к выводу, что ответ Алана выше помог мне больше всего и предоставил мне самое простое решение.И поэтому Алан получает от меня галочку.

Я хотел бы также поблагодарить Jedwards, ваш ответ, если он будет продолжен, также мог бы быть альтернативным решением… но, как оказалось, использование статического int было ключевым, и генерировать случайные числа и создавать векторы не было необходимости.

И спасибо также парапуре Раджкумару и другим участникам