Autor Wątek: Losowanie z tablicy bez powtorzen[SOLVED]  (Przeczytany 4961 razy)

Offline _user

  • Użytkownik

# Marzec 17, 2015, 19:14:23
Chce  zeby do programu wprowadzalo sie 10 liczb a potem zeby ten program losowo wybieral 8 z nich i wypisywal bez powtorzen.
na razie moj kod wyglada tak
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
 
int podaj(int tab[])
{
  int licznik = 0;
  do
  {
    std::cin >> tab[licznik];
    licznik++;
  } while( licznik < 10 );
 
  return 0;
}
void losuj(int tab[])
{
  int i =(rand() % 8 ) + 0;
  int  licznik = 0;
  cout << "8 wylosowanych liczb z 10 to: ";
  do
    {
      cout << tab[i] << endl;
      licznik++;
    }while(licznik < 8);
}
 
int main()
{
  srand(time(0));
  int tablica[10];
  podaj(tablica);
  losuj(tablica);
  return 0;
}

No ale nie wypisuje ich cos zbytnio losowo - a nie wiem czemu, no i nie ma zabezpieczenia przez powtorzeniami... Wiem ze bylo pare tematow o tym ale ja chce zrobic to bez uzycia petli for.
« Ostatnia zmiana: Marzec 18, 2015, 16:10:02 wysłana przez _user »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Kyroaku

  • Użytkownik

# Marzec 17, 2015, 19:29:01
Cytuj
No ale nie wypisuje ich cos zbytnio losowo
Nie wypisuje ich w ogóle losowo... A przynajmniej nie powinno.
void losuj(int tab[])
{
  int i =(rand() % 8 ) + 0;
  int  licznik = 0;
  cout << "8 wylosowanych liczb z 10 to: ";
  do
    {
      cout << tab[i] << endl;
      licznik++;
    }while(licznik < 8);
}
1. Losujesz liczbę tylko raz, wiec "i" się nie zmienia - wypisujesz 8x zawartość tablicy o stałym indeksie.
2. Chcesz wylosować 8 z 10. Poprawnie utworzyłeś pętlę, ale losujesz liczbę modulo z 8, a więc nigdy nie wylosujesz 8 oraz 9. Powinieneś losować liczbę modulo z 10 (tyle masz elementów w tablicy)
3. Jeśli chcesz bez powtórzeń, to musisz po prostu zapamiętać każdy wylosowany indeks i sprawdzić, czy nowo wylosowany się nie powtórzył.

BTW. W kursie, z którego się uczysz jest temat na ten temat...
http://cpp0x.pl/kursy/Kurs-C++/Poziom-2/Losowanie-bez-powtorzen/293

Offline MatlertheGreat

  • Użytkownik

# Marzec 17, 2015, 19:38:31
int i =(rand() % 8 ) + 0;
  do
    {
      cout << tab[i] << endl;
      licznik++;
    }while(licznik < 8);
Dla czego oczekujesz, że coś takiego będzie działać?

Poświęć trochę własnej pracy i czasu, żeby rozwiązać problem. Nie przychodź z każdym problemem na forum, a dużo więcej się nauczysz szukając rozwiązania samemu ;).

Offline _user

  • Użytkownik

# Marzec 17, 2015, 20:50:08
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

bool sprawdz(int iL, int tab[], int ile)
{
  if(ile <= 0);
    return false;

  int i = 0;
    do
      {
if(tab[i] == iL)
  return true;
i++;
      }while(i < ile);
  return false;
}
int podaj(int tab[])
{
  int licznik = 0;
    do
      {
std::cin >> tab[licznik];
licznik++;
      } while( licznik < 10 );

    return 0;
}
int losuj(int tab[])
{
  int  licznik = 0;
  cout << "8 wylosowanych liczb z 10 to: ";
    do
      {
int i =(rand() % 8 ) + 0;
cout << tab[i] << endl;
licznik++;
      }while(licznik < 8);
    return 0;
}

int main()
{
  srand(time(0));
  int tablica[10];
  int wylosowane = 0;
  podaj(tablica);
  losuj(tablica);
  do
    {
      int Liczba = losuj(tablica);
      if(sprawdz(Liczba, tablica, wylosowane) == false)
{
  tablica[wylosowane] = Liczba;
    wylosowane++;
}
    }while(wylosowane < 8);

    wylosowane = 0;
  do
    {
      cout << tablica[wylosowane] << endl;
      wylosowane++;
    }while(wylosowane < 5);
  return 0;
}
cos dziko liczy

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Marzec 17, 2015, 20:54:05
Cytuj
Chce  zeby do programu wprowadzalo sie 10 liczb a potem zeby ten program losowo wybieral 8 z nich i wypisywal bez powtorzen.
W tym przypadku polecam std::shuffle.

Offline _user

  • Użytkownik

# Marzec 17, 2015, 20:55:03
Wiem o nim ale narazie chce wykonac to ze zdobyta dotad wiedza tylko, wyzej zamiescilem kod, bede wdzieczny za wskazowki czemu tak wariacko mi liczy

Offline Xirdus

  • Moderator

  • +1
# Marzec 17, 2015, 21:21:17
Wiem o nim ale narazie chce wykonac to ze zdobyta dotad wiedza tylko, wyzej zamiescilem kod, bede wdzieczny za wskazowki czemu tak wariacko mi liczy
Czytając niniejszy post, właśnie zdobywasz wiedzę na temat tego, że nie ma sensu wymyślać od nowa czegoś co zostało już zrobione i dostępne jest w bibliotece standardowej :)

BTW poprawiłeś pierwszy punkt Kyroaku, a drugiego i trzeciego nie. No i rozwala mnie to "+ 0" :P

Offline _user

  • Użytkownik

# Marzec 17, 2015, 21:22:14
nie rozumiem...

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Marzec 17, 2015, 22:42:49
Cytuj
bede wdzieczny za wskazowki czemu tak wariacko mi liczy
Wariacki kod, to i wariacko liczy. Widać, że autor kodu chciał coś zrobić, nie miał pojęcia jak, ale coś mu tam gdzieś świtało i popisał sobie trochę kodu.

Pełno takich kwiatków na przykład jak:
int Liczba = losuj(tablica);gdzie losuj() zwraca zawsze zero. Definitywnie autor sam nie wie co robi.

Jeżeli chcesz coś zrobić, to przeanalizuj jak to ma działać, rozrysuj sobie na kartce parę przykładów i zrób je ręcznie, a dopiero koduj wtedy, jak wiesz już dokładnie jak to ma krok po kroku działać.


Dla przykładu rozpiszę omawiany problem, bom w dobrym humorze. :)
Załóżmy że mamy już wypełnioną tą tablicę "tablica" danymi liczbami.
Algorytm losowania będzie wyglądał tak:
- wybierz przypadkową komórkę tablicy,
- zapamiętaj liczbę jaka tam jest,
- usuń tą liczbę z tablicy,
- zwróć zapamiętaną liczbę

Co na C++ może wyglądać tak:
int tablica[10];
int rozmiar_tablicy = 10;
// tutaj gdzieś tablica się wypełnia

for(int i=0;i<8;i++)  // losujemy 8 liczb
{
  int numer_komorki = rand() % rozmiar_tablicy;   // - wybierz przypadkową komórkę tablicy
  int liczba = tablica[numer_komorki];    // - zapamiętaj liczbę jaka tam jest,

  // - usuń tą liczbę z tablicy,
  tablica[numer_komorki] = tablica[rozmiar_tablicy-1];      // przesuń ostatni element tablicy w miejsce usuwanej komórki
  rozmiar_tablicy--;    // skróć tablice o 1 (czyli usuń ostatni element)

  // - zwróć zapamiętaną liczbę
  printf( "%d\n", liczba );
}

Offline _user

  • Użytkownik

# Marzec 18, 2015, 00:39:27
A mozna wersje bez petli for ?
Ahhh ;/
Tam duzo wyjsc ktorych ja nie chce uzyc, ja chce to rozwiazac pewnymi sposobami, bo jak zrobie tak jak napisales to pomine pewien material i go nie przyswoje ;/ a ja chce sie nauczyc a nie byleby tylko ten program napisac.

Jak chce sposobem cos mniej wiecej w ten desen -> http://ideone.com/KRTMTT
« Ostatnia zmiana: Marzec 18, 2015, 00:47:47 wysłana przez _user »

Offline Oti

  • Użytkownik

# Marzec 18, 2015, 12:37:06
Chodzi o to, że chcesz pętlę do-while zamiast for? To strasznie bzdurny powód do narzekania. No ale-poczytaj trochę jak działa pętla for i jak działa pętla do-while, to może zauważysz, że to pętla do-while w tym wypadku powinna być zastąpiona pętlą for. Bo jest oparta na iteratorze, a do takich zastosowań dedykowana jest pętla for(ma uproszczoną składnię do tego).

Offline _user

  • Użytkownik

# Marzec 18, 2015, 12:41:38
Tak wiem juz, bardzo podobnie :) - A nie, niestety nie wiem jak ta petle for zamienic na do - while :/
for(int i=0;i<8;i++)
gdzie tutaj cos losuje ? gdzie rand(), o co chodzi.
No ale wolalbym jednak cos bardziej podobnego do -> http://ideone.com/z8nQBQ
« Ostatnia zmiana: Marzec 18, 2015, 12:45:35 wysłana przez _user »

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Marzec 18, 2015, 13:51:21
Cytuj
A mozna wersje bez petli for ?
Jak masz zrobić coś 8 razy i nie chcesz pętli for - najprawdopodobniej robisz to źle.

Cytuj
No ale wolalbym jednak cos bardziej podobnego do -> http://ideone.com/z8nQBQ
No dobra, ale ten podlinkowany kod przecież jest OK. W czym problem?

Offline _user

  • Użytkownik

# Marzec 18, 2015, 14:04:54
No w tym ze ja swoj problem chce rozwiazac podobnym sposobem jak ten ktory widac w podlinkowanym kodzie.

Wydaje mi sie ze juz jestem prawie blisko, kod dziala troche nie tak jak powinien... nie sprawdza powtorzen a nie mam pojecia dlaczego, spojrzcie na niego, wydaje mi sie ze niewiele tu jest do poprawki
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
 
bool sprawdz(int tab[], int ile, int los)
{
  int i = 0;
  do
    {
      if(tab[i] == tab[los])
    return true;
 
      i++;
    }while(i < ile);
 
  return false;
}
int losuj()
{
  return(rand() % 3);
}
 
int main()
{
  srand(time(0));
  int tablica[3];
  int wylosowanych = 0;
 
  cout << "Podaj 3 liczby: ";
  int i = 0;
  do
    {
      cin >> tablica[i];
      i++;
    }while(i < 3);
 
  cout << "Losowe 2 liczby z podanych 3 to: " << endl;
    do
      {
    int liczba = losuj();
    if(sprawdz(tablica, wylosowanych, liczba) == false)
    {
      cout << tablica[liczba] << endl;
      wylosowanych++;
    }
      }while(wylosowanych < 2);
    return 0;
}

Offline bies

  • Użytkownik

# Marzec 18, 2015, 14:15:35
Pętla:
for (int i = 0; i < max; ++i) {

    // kod wewnątrz pętli

}

To to samo co pętla:
{
    int i = 0
    do {
        if (!(i < max))
            break;

        // kod wewnątrz pętli

        ++i;
    } while (true);
}

I to samo co pętla:
{
    int i = 0
    while (i  < max) {

        // kod wewnątrz pętli

        ++i;
    }
}

Zwracam uwagę że wyrażenie (!(i < max)) jest równoważne (i >= max).

Jeśli znasz jedną z tych pętli to powinieneś zrozumieć jak działają wszystkie. Jak widzisz pętla for w przypadku iteracji n-razy jest znacznie czytelniejsza dlatego KrzysieK czy Oti piszą abyś ją poznał.