Luteres Temat założony przez niniejszego użytkownika |
[Rozdział 21] Losowanie bez powtórzeń - skrócenie kodu » 2016-12-15 02:19:00 Dzień dobry! Robię właśnie zadanie z kursu i trafiłem na takie polecenie. "Na początek sformułujmy nasz problem: Program ma nam wylosować 5 liczb bez powtórzeń. Liczby wylosowane mają być z przedziału od 1 do 10. " I wymyśliłem takie coś (póki co nie przeszedłem do dalszej części kursu, chciałem zrobić to zadanie samemu) #include <iostream> #include <cstdlib> #include <ctime> using namespace std;
int losuj( int t[], int ile, int start, int stop ) { srand( time( NULL ) ); do { ile--; t[ ile ] = rand() %( stop - start + 1 ) + start; } while( 0 < ile ); }
void usun( int t[], int ile, int start, int stop ) { srand( time( NULL ) ); do { ile--; if( t[ ile ] == t[ ile - 1 ] || t[ ile ] == t[ ile - 2 ] || t[ ile ] == t[ ile - 3 ] || t[ ile ] == t[ ile - 4 ] ) do { t[ ile ] = rand() %( stop - start + 1 ) + start; } while( t[ ile ] == t[ ile - 1 ] || t[ ile ] == t[ ile - 2 ] || t[ ile ] == t[ ile - 3 ] || t[ ile ] == t[ ile - 4 ] || t[ ile ] == t[ ile + 1 ] || t[ ile ] == t[ ile + 2 ] || t[ ile ] == t[ ile + 3 ] || t[ ile ] == t[ ile + 4 ] ); } while( ile > 0 ); }
int main() { int tablica[ 5 ]; losuj( tablica, 5, 1, 10 ); usun( tablica, 5, 1, 10 ); cout << tablica[ 0 ] << endl; cout << tablica[ 1 ] << endl; cout << tablica[ 2 ] << endl; cout << tablica[ 3 ] << endl; cout << tablica[ 4 ] << endl; return 0; }
Wydaje mi się, że to działa, ale (z racji tego że małe liczby były) niektóre rzeczy na początku zrobiłem "na piechotę" - mam na myśli szczególnie to: while( t[ ile ] == t[ ile - 1 ] || t[ ile ] == t[ ile - 2 ] || t[ ile ] == t[ ile - 3 ] || t[ ile ] == t[ ile - 4 ] || t[ ile ] == t[ ile + 1 ] || t[ ile ] == t[ ile + 2 ] || t[ ile ] == t[ ile + 3 ] || t[ ile ] == t[ ile + 4 ] ); I nie mam pojęcia jak to zapisać za pomocą jakiegokolwiek wzoru. Liczę także na podpowiedzi jak skrócić ten kod (bazując na wiadomościach, które do tej pory przyswoiłem, jeszcze nie robiłem pętli for) - nie chcę gotowej odpowiedzi tylko małej wskazówki, nakierowania. Oczywiście jeśli widać w tym kodzie jakieś rażące błędy to prosiłbym o ich wskazanie. Dzięki! |
|
czaffik |
» 2016-12-15 14:56:24 No to przynajmniej bez tej pętli for niestety za wiele nie zdziałasz. Też będzie istniało teoretycznie niebezpieczeństwo że pętla sprawdzająca powtarzanie się warunków nigdy się nie skończy bo nowo wylosowana liczba się powtórzy etc, ale jak przedział losowanych liczb będzie większy od liczby losowanych liczb to raczej powinno się udać uniknąć tego kataklizmu. Zapis: while( t[ ile ] == t[ ile - 1 ] || t[ ile ] == t[ ile - 2 ] || t[ ile ] == t[ ile - 3 ] || t[ ile ] == t[ ile - 4 ] || t[ ile ] == t[ ile + 1 ] || t[ ile ] == t[ ile + 2 ] || t[ ile ] == t[ ile + 3 ] || t[ ile ] == t[ ile + 4 ] );
jest w zasadzie nieobliczalny bo wychodzisz w nim poza skale tablicy a tam mogą być zapisane jakieś śmieci, np jeśli ile = 2 to t[2] = t[-2] - a co się znajduje pod t[-2]??? Musisz przerobić pętlę for i w niej porównywać dany element z tymi które już do tej pory wylosowałeś, bo nawet zresztą po co ci wzór do tego zapisu skoro nie możesz go w nic zwinąć. |
|
carlosmay |
» 2016-12-15 14:57:19 nie chcę gotowej odpowiedzi tylko małej wskazówki, nakierowania. |
Korzystaj z dobrodziejstw pętli. do { } while(); przecież znasz. std::srand() wywołuj tylko raz i najlepiej na początku programu. Kod podziel na więcej funkcji zajmujących się tylko jedną czynnością, np: int losuj( int start, int stop ); zwraca wylosowaną liczbę z zadanego przedziału i nic więcej. bool czyByla( int tab[], int rozmiar, int sprawdzana ); sprawdza spośród liczb w tablicy jest sprawdzana. void wypelnijTablice( int tab[], int rozmiar ); z użyciem pętli wypełnia tablicę losowanymi liczbami, sprawdzając uprzednio, czy liczba jest unikatowa. void wypiszTablice( int tab[], int rozmiar ); wypisuje zawartość tablicy. Czym ma zajmować się funkcja void usun( int t[], int ile, int start, int stop ); ? Nie rozumiem przeznaczenia tej funkcji. |
Dobrym pomysłem jest zwracanie wartości logicznej bool niosącej informację czy usuwanie się powiodło. edit: @czafik - No to przynajmniej bez tej pętli for niestety za wiele nie zdziałasz. |
Przecież pętle są zamienne. Za pomocą każdej z nich można zapisać ten sam kod. |
|
czaffik |
» 2016-12-15 15:44:08 @carlosmay - w sumie można i użyć do while, wystarczy dodać zmienną iterującą po elementach, jednak for wydaje się ładniejszy w tym przypadku. |
|
Luteres Temat założony przez niniejszego użytkownika |
» 2016-12-15 22:46:33 void usun( int t[], int ile, int start, int stop ) Ta funkcja w zamyśle miała nadpisywać powtarzające się wyniki dopóki nie przestaną się powtarzać. Dzięki za wskazówki, spróbuję wprowadzić więcej funkcji. |
|
Luteres Temat założony przez niniejszego użytkownika |
» 2016-12-16 18:21:59 Ok, poprzednie ćwiczenie jakoś zrobiłem i nawet wychodziło, teraz spróbowałem kolejnego i coś nie gra. Poprzednio dotarłem do momentu gdzie liczby się losowały, ale się powtarzały, teraz po pierwszym wylosowaniu program przestaje odpowiadać (domyślam się, że jakaś pętla się dzieje, która do niczego nie prowadzi, ale nie potrafię jej zlokalizować). Zmodyfikuj program z pierwszego zadania tak, aby użytkownik musiał podać 10 liczb, a 8 z nich będzie losowanych bez powtórzeń. Sprawdź czy wyniki są poprawne. #include <iostream> #include <cstdlib> #include <ctime> using namespace std;
int losuj( int tablica[] ) { return tablica[( rand() % 10 ) + 0 ]; }
void wypelnijTablice( int t[] ) { int i = 0; do { t[ i ] = i + 1; i++; } while( i < 10 ); }
bool czyByla( int wylosowane[], int wylosowanych, int liczba ) { int i = 0; if( wylosowanych <= 0 ) return false; do { if( wylosowane[ i ] == liczba ) return true; i++; } while( i < 8 ); return false; }
int main() { srand( time( NULL ) ); int tablica[ 9 ]; int liczba; int wylosowanych = 0; int wylosowane[ 7 ]; wypelnijTablice( tablica ); do { liczba = losuj( tablica ); if( czyByla( wylosowane, wylosowanych, liczba ) == false ) { wylosowane[ wylosowanych ] = liczba; cout << "Wylosowana liczba: " << wylosowane[ wylosowanych ] << endl; wylosowanych++; } } while( wylosowanych < 8 ); return 0; }
EDIT: Już wiem.. while( i < 8 ) -> while( i < 7 ) |
|
carlosmay |
» 2016-12-16 20:17:28 magic numbers używaj jak najmniej, a najlepiej wcale. |
|
« 1 » |