简体   繁体   中英

Non-repeating random number generator

I'd like to make a number generator that does not repeat the number it has given out already (C++).

All I know is:

int randomgenerator(){
  int random;
  srand(time(0));
  random = rand()%11;
  return(random);
} // Added this on edition

That function gives me redundant numbers.

I'm trying to create a questionnaire program that gives out 10 questions in a random order and I don't want any of the questions to reappear.

Does anyone know the syntax?

What I would do:

  • Generate a vector of length N and fill it with values 1,2,...N.
  • Use std::random_shuffle .
  • If you have say 30 elements and only want 10, use the first 10 out the vector.

EDIT: I have no idea how the questions are being stored, so.. :)

I am assuming the questions are being stored in a vector or somesuch with random access. Now I have generated 10 random numbers which don't repeat: 7, 4, 12, 17, 1, 13, 9, 2, 3, 10.

I would use those as indices for the vector of questions:

std::vector<std::string> questions;
//fill with questions
for(int i = 0; i < number_of_questions; i++)
{
    send_question_and_get_answer(questions[i]);
}

You are trying to solve the problem "the wrong way".

Try this instead (supposing you have a vector<int> with question ids, but the same idea will work with whatever you have):

  1. Get a random R from 0 to N-1 where N is the number of questions in the container
  2. Add question R to another collection of "selected" questions
  3. If the "selected questions" collection has enough items, you 're done
  4. Remove question R from your original container (now N has decreased by 1)
  5. Go to 1

Sounds like you essentially want to shuffle a deck of cards (in this case, the "cards" being the questions, or question numbers).

In C++, I would do:

#include <vector>
#include <algorithms>

std::vector<int> question_numbers;
for (unsigned int i = 0; i < 10; ++i)
    question_numbers.push_back(i+1);
std::random_shuffle(question_numbers.begin(), question_numbers.end());

// now dole out the questions based on the shuffled numbers

You do not have to hand out all of the questions, any more than you have to deal out a whole deck of cards every time you play a game. You can, of course, but there's no such requirement.

Create a vector of 10 elements (numbers 1-10), then shuffle it, with std::random_shuffle . Then just iterate through it.

Should look more like this: (Note: does not solve your original problem).

int randomgenerator(){
  int random;

  // I know this looks re-dunand compared to %11
  // But the bottom bits of rand() are less random than the top
  // bits do you get a better distribution like this.

  random = rand() / (RAND_MAX / 11);

  return random;
}

int main()
{
    // srand() goes here.
    srand(time(0));

    while(true)
    {
        std::cout << randomgenerator() << "\n";
    }
}

A better way to solve the original problem is to pre-generate the numbers so you know that each number will appear only once. Then shuffle the order randomly.

int main()
{
    int data[] =  { 0,1,2,3,4,5,6,7,8,9,10,11};
    int size   =  sizeof(data)/sizeof(data[0]);

    std::random_shuffle(data, data + size);

    for(int loop = 0; loop < size; ++loop)
    {
        std::cout << data[loop] << "\n";
    }
}
//non repeating random number generator
for (int derepeater = 0; derepeater < arraySize; derepeater++)
{
    for (int j = 0; j < arraySize; j++)
    {
        for (int i = arraySize; i > 0; i--)
        {
            if (Compare[j] == Compare[i] && j != i)
            {
                Compare[j] = rand() % upperlimit + 1;
            }
        }
    }
}

Why not use some STL to perform the checks for you? The idea:

Create an (initially empty) set of 10 integers that will be the indices of the random questions (they will be distinct as a set forbids duplicate items). Keep pushing random numbers in [0, num_of_questions -1] in there until it grows to a size of 10 (duplicates will get rejected automatically). When you have that set ready, iterate over it and output the questions of the corresponding indexes:

std::vector<std::string> questions = /* I am assuming questions are stored in here */
std::set<int> random_indexes;

/* loop here until you get 10 distinct integers */
while (random_indexes.size() < 10) random_indexes.insert(rand() % questions.size());

for (auto index: random_indexes){
    std::cout << questions[index] <<std::endl;
}

I may be missing something, but it seems to me the answers that use shuffling of either questions or indexes perform more computations or use an unnecessary memory overhead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM