• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Losowanie liczb bez powtarzania

Object Storage Arubacloud
+1 głos
1,426 wizyt
pytanie zadane 5 kwietnia 2017 w C i C++ przez galezovsky Nowicjusz (230 p.)

Cześć mam taki oto kod, który mam mi pomóc w losowaniu liczb bez powtarzania. W miejscu //TUTAJ, mam problem, ponieważ chcę aby program losował liczbę dopóki jest inna niż wcześniejsza, wcześniejsza, jeszcze wcześniejsza i tak do pierwszej wylosowanej liczby.

{
    int n, p, o;
 
    printf("Podaj ile liczb chcesz wylosowac: ");
    scanf_s("%d", &n);
    printf("Podaj od jakiej liczby chcesz losowac: ");  //wartosc minimalna
    scanf_s("%d", &p);
    printf("Podaj liczbe do jakiej chcesz losowac: ");  //wartosc maksymalna
    scanf_s("%d", &o);
 
    srand(time(NULL));  //generator liczb losowych
 
    int tab[1000];
    int i, j;
   
    for (i = 1; i <= n; i++)
    {
        tab[i] = rand() % (o - p) + p;
    }                                   //losowanie liczb
 
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n-j; j++)
        {
            if (tab[i] == tab[j+i]) //jeżeli liczba nastepna jest taka sama
            {
                do
                {
                    tab[j+i] = rand() % (o - p) + p;
                } while (tab[i] != tab[j + i]); //to losuj liczbe dopoki bedzie inna            //TUTAJ!
            }
        }
    }
 
    printf("Twoje liczby to: ");
    for (i = 1; i <= n; i++)
    {
        printf("%d ", tab[i]);
    }
 
    return 0;
}

 

6 odpowiedzi

+1 głos
odpowiedź 6 kwietnia 2017 przez mokrowski Mędrzec (155,460 p.)
edycja 6 kwietnia 2017 przez mokrowski

Wersja "na wypasie", z rozbudowaną kontrolą błędów i złożonością obliczeniową O(n):


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

typedef struct {
    size_t counter;
    int minValue;
    int maxValue;
    size_t valuesSize;
    int * values;
} range_t;

range_t initRange(void);
void shuffleValues(range_t * range);
void showRange(const range_t * range);
void destroyRange(range_t * range);

static void fillRange(range_t * range);
static void readInt(int * value, const char * message);
static void readSizeTWithoutZero(size_t * value, const char * message);
static bool isCorrectData(const range_t * range);
static void inputRangeBounds(range_t * range);

int main(void) {
    range_t range = initRange();

    shuffleValues(&range);

    printf("Zakreś liczb o które prosiłeś to:\n");
    showRange(&range);

    destroyRange(&range);

    return EXIT_SUCCESS;
}

static void fillRange(range_t * range) {
    for(size_t i = 0; i < range->valuesSize; ++i) {
        range->values[i] = i + range->minValue;
    }
}

static void readInt(int * value, const char * message) {
    printf("%s", message); 
    while(scanf(" %d", value) != 1) {
        fprintf(stderr, "\nTo nie jest liczba! Próbuj jeszcze raz.\n");
        printf("%s", message); 
        int c;
        while((c = getchar()) != '\n' && c != EOF);
    }
}

static void readSizeTWithoutZero(size_t * value, const char * message) {
    do {
        printf("%s", message); 
        while((scanf(" %zu", value) != 1)) {
            fprintf(stderr, "\nTo nie jest liczba! Próbuj jeszcze raz.\n");
            printf("%s", message); 
            int c;
            while((c = getchar()) != '\n' && c != EOF);
        }
        if(!*value) {
            fprintf(stderr, "\nWartość powinna być większa niż zero.\n");
            continue;
        }
    } while(*value == 0);
}

static bool isCorrectData(const range_t * range) {
    bool answer = true;
    if(!(range->minValue < range->maxValue)) {
        fprintf(stderr, "\nWartość minimalna ilości losowanych liczb powinna"
               " być mniejsza niż maksymalna!\n");
        answer = false;
    } 
    if((range->counter - 1) > (size_t)(range->maxValue - range->minValue)) {
        fprintf(stderr, "\nIlość liczb losowanych jest większa niż zakres\n");
        answer = false;
    }
    if(!(range->minValue < range->maxValue)) {
        fprintf(stderr, "\nWartość minimalna powinna być mniejsza niż" 
                " maksymalna!\n");
        answer = false;
    }
    if(!answer) {
        fprintf(stderr, "Próbuj jeszcze raz.\n");
    }
    return answer;
}

static void inputRangeBounds(range_t * range) {
    do {
        readSizeTWithoutZero(&range->counter, 
                "Podaj wartość większą niż 0, ile liczb chcesz wylosować: ");
        readInt(&range->minValue,
                "Podaj od jakiej liczby (włącznie) chcesz losować: ");
        readInt(&range->maxValue,
                "Podaj do jakiej liczby (włącznie) chcesz losować: ");
    } while(!isCorrectData(range));

    range->valuesSize = (range->maxValue + 1 ) - range->minValue;
}

range_t initRange(void) {
    range_t range;

    inputRangeBounds(&range);
    range.values = malloc(range.valuesSize * sizeof(int));
    fillRange(&range);

    return range;
}

void shuffleValues(range_t * range) {
    srand(time(NULL));
    size_t dstIndex;
    int tmp;
    for(size_t i = 0; i < range->counter; ++i) {
        dstIndex = rand() % range->valuesSize;
        // Swap values
        tmp = range->values[i];
        range->values[i] = range->values[dstIndex];
        range->values[dstIndex] = tmp;
    }
}

void showRange(const range_t * range) {
    size_t lastIndex = range->counter - 1;
    for(size_t i = 0; i < lastIndex; ++i) {
        printf("%d, ", range->values[i]);
    }
    printf("%d\n", range->values[lastIndex]);
}

void destroyRange(range_t * range) {
    free(range->values);
}
0 głosów
odpowiedź 5 kwietnia 2017 przez 10kw10 Pasjonat (22,880 p.)
Mozesz losowac do innej zmiennej, a nie od razu do tablicy. I wtedy sprawdzasz, lecisz po calej tablicy i patrzysz czy juz jest. Potem przypisujesz na koniec. Pasowaloby tez miec liczbe wylosowanych chyba ze uzyjesz vectora.
komentarz 5 kwietnia 2017 przez galezovsky Nowicjusz (230 p.)
Nie do końca rozumiem. Jak przejrzeć to tablicę ponownie?
komentarz 5 kwietnia 2017 przez 10kw10 Pasjonat (22,880 p.)
Raczej petla for
0 głosów
odpowiedź 5 kwietnia 2017 przez TheHabuUser Nowicjusz (230 p.)
kolega 10kw10 dobrze ci poopowiada....

Chodzi mu o to że tworzysz zmienna int temp = (akutalny rand), potem wpuszczasz ja do fora i sprawdzasz czy jest taka sama tab[0..n] != temp, jeżeli true to tab[i+1] = temp;

Pamietaj ze to nie zadziała jeżeli będziesz chciał wylosować np 5 licz a masz zakres liczb 1-3 :)
komentarz 5 kwietnia 2017 przez galezovsky Nowicjusz (230 p.)
for (i = 1; i <= n; i++)
	{
		tab[i] = rand() % (o - p) + p;
	}									//losowanie liczb

	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= n-j; j++)
		{
			if (tab[i] == tab[j+i])	//jeżeli liczba nastepna jest taka sama
			{
				int liczba = rand() % (o - p) + p;
				do
				{
					int k = i;
					if (liczba != tab[k])
					{
						k--;
					}
					else
					{
						liczba = rand() % (o - p) + p;
					}
				} while (p >= 1);
				
				liczba = tab[j + i];
			}
		}
	}

	printf("Twoje liczby to: ");
	for (i = 1; i <= n; i++)
	{
		printf("%d ", tab[i]);

 

komentarz 5 kwietnia 2017 przez galezovsky Nowicjusz (230 p.)
Dobra zrobiłem coś takiego, ale nadal to samo
komentarz 5 kwietnia 2017 przez TheHabuUser Nowicjusz (230 p.)
Zaraz pobiorę jakies minGW bo nie obcuje na co dzień z c/c++ i ci pomoge, ale na pewno unikaj inicjalizowania zmiennych w pętlach whilach i ifach bo za każdym wejściem jest inicjalizacja .... np int liczba .... zaczynaj od i=0 bo marnujesz jedno miejsce w tablicy xd
komentarz 6 kwietnia 2017 przez Fenix Nałogowiec (26,750 p.)
Nie musisz nic pobierać, są shelle z c/cpp online ;)
0 głosów
odpowiedź 5 kwietnia 2017 przez Mateusz Analityk Stary wyjadacz (13,710 p.)

Proponuję napisać funkcje która sprawdzi tobie czy liczba przez ciebie wylosowana już jest w tablicy. Jeśli napiszesz funkcje która dla takich przypadków zwróci wartość 0, lub 1 i dla tego wykonasz odpowiednie później operacje  tzw. nie dodasz do tablicy znaków albo dodasz... no to jesteś w niebie.

Aby zrobić coś takiego piszesz w kodzie:

#inculde <stdbool.h>

bool filtr_losowanie_bez_powtórzeń(int losowa_liczba){

// tutaj treść

}

A potem tylko sobie wywołujesz, ważne by mieć ustawiony standard C99, a sprawdzasz to jak koledzy pisali np. w pętli for sprawdzając po kolei elementy tablicy

0 głosów
odpowiedź 6 kwietnia 2017 przez mitelak Pasjonat (23,330 p.)
int wylosuj(int tab[], int i, int min, int max){
    int j = 0;
    int liczba = rand() % (max - min) + min;
    for(j; j<i; j++){
        if(tab[j] == liczba){
            liczba = rand() % (max - min) + min;
            j = 0;
        }
    }
    return liczba;
}

 Funkcje wklejasz przed mainem jako argumenty przy wywołaniu podajesz po kolei tablice, i (komorka na ktorej sie znajdujesz), min i max to zakres losowania. Pamiętaj, że w takim wariancie jeżeli zakres losowanej liczby będzie mniejszy niż długość tablicy to program się zapętli!

Wywołujesz w ten sposób: 
 

for (i = 0; i < n; i++)
    {
        tab[i] = wylosuj(tab, i, p, o);
    }

Taki sam kod możesz zrobić oczywiście nie jako funkcja (wtedy robisz to w Twojej pętli przed przypisaniem wartości a na końcu tab[i] przypisujesz wartość liczba :) 

0 głosów
odpowiedź 6 kwietnia 2017 przez Patryk Rafał Bywalec (2,700 p.)
A ja bym to zrobił tak zrobol sobie wektor z zakresem liczb np 49 i w pętli bym go tymi liczbami wypełnił ale musisz mieć też tablice gdzie przechowujesz elementy wylosowane. A teraz do sedna lisujesz sobie index z wektora liczbe i wstawiamy do tablicy a z wektora kasuje wylosowana liczbę i tym sposobem unikniesz powtórzeń

Podobne pytania

–1 głos
0 odpowiedzi 1,973 wizyt
0 głosów
3 odpowiedzi 452 wizyt
pytanie zadane 28 kwietnia 2017 w C i C++ przez vasquez Początkujący (480 p.)
0 głosów
1 odpowiedź 141 wizyt

92,579 zapytań

141,432 odpowiedzi

319,664 komentarzy

61,964 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...