Odwołuję mój poprzedni komentarz, czy to będzie tablica, czy std::set
, czy cokolwiek - rozwiązanie z losowaniem i sprawdzaniem czy dana liczba była już wybrana będzie nieprzyzwoicie powolne już dla losowania 29999 liczb z zakresu 1..30000. Nie mówiąc już o tym, że na standardowej (i dalekiej od ideału, jak wiadomo) funkcji rand()
nie wylosujemy liczby większej niż RAND_MAX
(przynajmniej 32767) bez kombinowania. ;)
Alternatywa:
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
//#include <iterator> // ostream_iterator
#include <exception>
namespace my {
class Maszyna_Losujaca {
unsigned najmniejsza_wartosc;
std::vector<unsigned> pula;
public:
Maszyna_Losujaca(unsigned najmniejsza_wartosc, unsigned rozmiar, unsigned krok = 1)
: najmniejsza_wartosc(najmniejsza_wartosc), pula(rozmiar) {
if (rozmiar == 0) { throw "Kup sobie kredki na baterie..."; }
for (unsigned i = 0, j = najmniejsza_wartosc; i < pula.size(); ++i, j += krok) {
pula[i] = j;
}
}
std::vector<unsigned> losuj_bez_powtorzen(unsigned ile) throw (const char*) {
if (ile == 0) { throw "Kup sobie kredki na baterie..."; }
if (ile > pula.size()) { throw "Chcesz wylosowac wiecej niz mozesz, pora na niebieskie tabletki..."; }
std::random_shuffle(pula.begin(), pula.end());
return std::vector<unsigned>(pula.begin(), pula.begin() + ile);
}
};
template<typename T>
void print(const T& v) {
std::cout << v << " ";
}
}
int main() {
using namespace std;
srand(time(0));
try {
my::Maszyna_Losujaca lotto(1, 49000);
vector<unsigned> wylosowane = lotto.losuj_bez_powtorzen(5);
cout << "Wylosowano: ";
//C++0x
for (unsigned i : wylosowane) { cout << i << " "; }
// lub
//for_each(wylosowane.begin(), wylosowane.end(), [](unsigned n){ cout << n << " "; });
// etc
//C++03 np:
//copy(wylosowane.begin(), wylosowane.end(), ostream_iterator<unsigned>(cout, " "));
// lub:
//for_each(wylosowane.begin(), wylosowane.end(), my::print<unsigned>);
// zwykły for po indeksach, iteratorach, etc
cout << '\n';
} catch (const char* msg) {
cerr << "PEBKAC: " << msg;
} catch (const exception& msg) {
cerr << "Exception: " << msg.what();
}
return 0;
}
Wada? Około sizeof(unsigned) * rozmiar_puli
wymaganej pamięci, w kontrze do sizeof(unsigned) * ilosc_losowanych
podczas losowania - ale czasowo wyrabia się zdecydowanie lepiej niż "losowanie, sprawdzanie, powtórz", im większa pula - tym większa różnica na korzyść kodu powyżej. ;)