Inserting unique random numbers into a vector [dup

2019-09-19 09:59发布

问题:

This question already has an answer here:

  • How to make Random Numbers unique 6 answers

As a part of code for a certain game I want to generate 4 unique random numbers into a vector.

This code works for some number of repeated plays and then application crashes (not responding window).

While I understand that if-condition prevents for-loop from inserting the same number into a vector, how much time does this for-loop takes until it generates unique numbers via rand() function? How srand(time(NULL)) and rand() exactly work together to create random values depending on the system time?

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>

using namespace std;

//plays bulls and cows


int main() {
srand(time(NULL));
string play="yes";
int nums=4;       // number of values in an answer (must NOT exceed 10)
vector<int> answer;


while (play=="yes" || play=="YES" || play=="Y" || play=="Yes" || play=="y") { //plays the game

answer.push_back(rand()%10+1);
  do {                              //fills vector with unique random numbers
    for (int i=1; i<nums; i++) {
      answer.push_back(rand()%10+1);
      if (answer[i]==answer[i-1]) {
        i=i-1;
        continue;
        }
      }
  } while (answer.size()!=nums);

for (int i=0; i<nums; i++) {
  cout<<answer[i];
}

  cout<<"Do you want to play again?"<<'\n';
  cin>>play;
  answer.clear();
} //game ends


if (play=="no" || play=="n" || play=="No" || play=="NO" || play=="N") { //terminates and checks for exceptions
  cout<<"Thank you for playing!"<<'\n';
  return 0;
} else {
  cerr<<"Error: wrong input. Terminating."<<'\n';
  return 0;
}

    return 0; //safety return
}

回答1:

The problem is you always push back the random value in your vector before checking if it's valid. Let's say your program generates these random value in order:

2, 6, 6, 7, 9, 10

What happens is you will insert 2 (i == 2), 6 (i == 3), 6 (i == 4), then realize 6 is repeated twice, so you go back one iteration (i == 3), but both your sixes are still in your vector. So now you will add 7 (i == 4) and you will exit the for loop with 5 values in your vector.

Then when you evaluate your do-while condition, your answer.size() won't ever equal 4 because it already is equal to 5. You are now stuck in an infinite loop, and your application crashes when it consumes all the available memory from your vector growing infinitely.

Also, you appear to have an error in your logic. To make sure you don't have a repeated value (and you are stuck with vectors), you should not only validate the last inserted value but the whole vector. Like this:

#include <algorithm>

if ( std::find(vector.begin(), vector.end(), item) != vector.end() )
   do_this();
else
   do that();


回答2:

Why do you add the new try into answer instead of temporary variable. If the variable is valid, then add it into the answer. In your case, i always keep at 1;

while (play=="yes" || play=="YES" || play=="Y" || play=="Yes" || play=="y") { //plays the game

    int last_try=rand()%10+1;
    answer.push_back(last_try);
    do { //fills vector with unique random numbers
            int new_try=rand()%10+1;

            if (last_try!=new_try)
            {
                answer.push_back(new_try);
                last_try=new_try;
            }
    } while (answer.size()!=nums);


    for (int i=0; i<nums; i++)
    {
        cout<<answer[i]<<"\n";
    }

    cout<<"Do you want to play again?"<<'\n';
    cin>>play;
    answer.clear();
} //game ends


回答3:

Assume that you must use std::vector (and not a std::set). The easiest way to fill your vector with random numbers is to check to see if the number has already been "seen" -- if not, then add it to the vector.

This can be accomplished by using an array of bool as a helper to determine if the number has been seen:

#include <vector>
#include <iostream>
#include <cstdlib>

int main()
{
    std::vector<int> answer;
    int num = 4;

    // 10 numbers
    bool seen[10] = {false};

    // keeps track of numbers added
    int numsAdded = 0;
    while (numsAdded < num)
    {
       int numRand = rand()%10;
       if ( !seen[numRand] )
       {
         // not seen, so add it to vector and update bool array and
         // numsAdded
         answer.push_back(numRand + 1);
         seen[num] = true;
         ++numsAdded;
       }
    }
    for (size_t i = 0; i < num; ++i)
       std::cout << answer[i] << " ";
}

Live Example