Losowanie liczb bez powtórzeń. Dwa podejścia, dwa języki (C/C++)
Podzieliłem posta na dwie części, dla języka C oraz C++
Dwa pojęcia pomocnicze, aby było wiadomo co przez te słowa rozumiem:
- zakres losowanych liczb – To jest przedział liczb naturalnych (od 0 do nieskończoności), z których będziemy wybierali liczby
- ilość losowanych liczb – Liczba elementów będących w tablicy które się nie powtarzają wewnątrz tablicy
Język C
Pierwsze podejście jest intuicyjne sprawdzające się do takiego algorytmu:
- Wylosuj liczbę 'n’
- Sprawdź czy istnieje liczba 'n’ w tablicy 'tab’
- Jeśli TAK to przejdź do kroku 1
- Jeśli NIE to dodaj n do tablicy 'tab’
- Jeśli potrzeba więcej liczb przejdź do kroku 1
Aby znaleźć bardziej czasowo efektywny algorytm. Warto zastanowić się na takim przypadkiem:
Mamy zakres 15 liczb od 1 do 15 i chcemy mieć w tablicy 15 liczb bez powtarzania.
Wynikiem takiego losowania, taki sam jak przetasowanie[1] tablicy z kolejno wartościami od 1 do 15.
[1] – Zna ktoś lepsze tłumaczenie słowa shuffle ?
Algorytm który będzie losował n liczb losowych bez powtórzeń, z zakresu od p do k:
- Utwórz tabelę na k-p+1 elementów (tak duży rozmiar aby pomieścić cały zakres)
- Przetasować całą tablicę
- Wynik znajduje się w pierwszych n elementach
Algorytm na przetasowanie z którego będę korzystał nosi nazwę Fisher–Yates shuffle (algorytm nazwany po jego twórcach Ronald Fisher oraz Frank Yates)
Dla tablicy o nazwie tab i rozmiarze n, kolejne kroki to:
- Pętla for od i=n-1 do i>0 krok co i–
- Do zmiennej j przypisz losową wartość w zakresie od 0 do i włącznie
- Zamień tab[j] z tab[i]
void FY_shuffle(int _array[],int size,
int (*rnd_gen)(int begin,int end))
{
int i,j;
for(i=size-1; i>0 ;i--)
{
j = rnd_gen(0,i);
swap(&_array[j],&_array[i]);
}
return ;
}
Parametrami tej funkcji jest:
- int _array[] – tablica do przetasowania
- int size – rozmiar tablicy
- int (*rnd_gen)(int begin,int end) wskaźnik do funkcji która zwraca losową wartość w określonym przedziale od begin do end włącznie. Ten zabieg ma na celu uniezależnienie się od funkcji rand(), w przypadku gdybyśmy chcieli skorzystać z innych generatorów liczb losowych.
Język C++
Przy języku C++ od razu przeskoczę do algorytmu przetasowywania.Otóż tego algorytmu nie trzeba na własną rękę implementować. Funkcję std::random_shuffle można znaleźć w bibliotece algorithm. Pozwala na przetasowanie wewnątrz kontenerów takich jak vector, list itp.
O języku C++ nie ma co pisać, bo wszystko ma w sobie 🙂