Zufallsgenerator ohne Wiederholung der Zahlen in c++

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

OK, ein 4x4 int-Array hat logischerweise 16 int-Felder. Da die Zufallszahlen im Intervall [0, 15] liegen, muss jede dieser Zahlen genau einmal vorkommen! Es sind ja eben 16 Ganzzahlen in dem Interval.

Daher durchläufst du nicht das Array von [0][0] nach [3][3] und guckst ob die Zufallszahl schon drin ist, SONDERN ...

du machst eine for-Schleife mit i von 0 bis 15, welche die "Zufallszahlen" darstellen. Die werden jetzt nicht zufällig generiert, sondern schön nacheinander im Array gespeichert. Und damit das Ganze einen gewissen Zufall behält, speicherst du arr[rand()%4][rand()%4] = i; falls dieses Feld noch NULL also noch nicht belegt ist.

Verständlich so, oder soll ich das schnell coden?

TheRelaxingLion 
Fragesteller
 02.12.2011, 21:37

coden, bitte :D sorry habs nicht ganz verstanden.

0
AstroNerd  02.12.2011, 21:55
@TheRelaxingLion
// Variablen anlegen und initialisieren,
// vor allem schonmal x, y 'wuerfeln',
// da sonst immer arr[0][0] = 0; o. ä.
int arr[4][4];
int x, y;
x = rand() % 4;
y = rand() % 4;

// Array initialisieren, 
// damit kein 'Müll' mehr drin steht ;)
for (int x = 0; x != 4; x++)
    for (int y = 0; y != 4; y++)
    {
        arr[x][y] = 0;
    }

// 'Zufallszahlen' in [0, 15] durchlaufen
for (int i = 0; i != 16; i++)
{
    // Solange kein leeres Feld gefunden wurde,
    // würfel nochmal die x,y Koordinaten
    while(arr[x][y] != NULL)
    {
        x = rand() % 4;
        y = rand() % 4;
    }
    // leeres Feld gefunden, weise 'Zufallszahl' zu
    arr[x][y] = i;
}

Das müsste funktionieren, ansonsten melde dich noch mal. Mein C++ ist etwas eingerostet, progge so gut wie nur noch C#, oder in der Uni mal etwas Java oder PHP für Webseiten. ^^ Das man das Array explizit mit 0 initialisieren muss, da sonst Müll drin steht, wusste ich selbst bis eben gar nicht mehr, hehe. Die Zeiten liegen bei mir schon etwas zurück.

0
AstroNerd  02.12.2011, 23:01
@TheRelaxingLion

Das musst du auch dazu schreiben und hat nichts mit meinem Programm-Ausschitt zutun sondern mit der gegebenen rand-Methode. Google das mal, ich glaube du musstest die Seed mit der aktuellen Uhrzeit initialisieren. Die Seed ist der Ausgangswert anhand der die Zufallszahlen generiert werden. Solange die nicht angegeben wird ist die immer gleich => gleiche Zufallszahlen. Übergibst du die aktuelle Uhrzeit an die Methode, ist bei jedem Programmstart die Seed eine andere => andere Zufallszahlen.

Bzw. so wie ich es programmiert habe, keine anderen Zufallszahlen, sondern eben an anderen Stellen im Array.

Generell sollte man als Programmierer Google benutzen können. ;)

0
AstroNerd  02.12.2011, 23:06
@AstroNerd

Da ich grad das Projekt noch offen hatte hier, bitte schön:

// Vor meinem, obigen Code in die Main-Methode schreiben. srand(time(NULL));

Für die time()-Methode musst du glaub ich noch die time.h includen.

Hoffe es entspricht jetzt dem gewünschten Ergebnis. ;)

PS: Programmieren lernen musst du schon selbst. Hätte ich keinen C++-Compiler auf'em PC gehabt hätte ich Pseudo-Code geschrieben, was jedem Programmierer als Ansatz und Verständnis was ich meine genügen sollte.

0
TheRelaxingLion 
Fragesteller
 03.12.2011, 00:30
@AstroNerd

sorry, ich programmier erst seit 3 Monaten, aber danke es funktioniert jetzt :)

0
AstroNerd  03.12.2011, 01:59
@TheRelaxingLion

Hey, danke erstmal für den Stern. Freut mich das es jetzt so funktioniert, wie es eigentlich gedacht war.

Sorry wenn es evtl. etwas hart gegen dich geäussert war. Darfst du nicht persönlich nehmen, es ist viel mehr als genereller Rat für Programmier-Neulinge gedacht gleich von anfang an den Umgang mit Google mit zu lernen.

Im Prinzip ist es ja so, dass Programmier-Sprachen, die am leichtesten zu erlendenden Sprachen sind, egal welche man nun verwendet. Es ist ja alles nur aus ein paar grundlegenden Konstrukten wie Objekten, Schleifen, Verzweigungen, etc. aufgebaut ist. Das ist recht schnell gelernt und auch in allen Programmier-Sprachen nahezu identisch. Daher gilt ja auch, kennst du eine Programmier-Sprache, kennst du 90% aller Programmier-Sprachen.

Die Kleinigkeiten die sich zwischen den Sprachen unterscheiden, sollte man dann einfach schnell mal nachgooglen können und weiter geht's mit dem Code. Wie gesagt, eigentlich hätte es auch genügen sollen, grob in Pseudo-Code zu beschreiben wie ich es lösen würde und du daraus dann einen gültigen C++ Programm-Code zu schreiben. Wenn dann noch 1 Zeile Code fehlt, wäre es sicher schneller gegangen die zu googlen, anstatt nochmal zu (ich übertreibe bewusst) schreiben das mein Code nicht funktioniert. (Wie gesagt, ist eher allgemein für Neulinge gedacht. Die Situation ist nämlich allseits bekannt.)

Worauf es eigentlich beim Programmieren ankommt ist es, Probleme (mehr oder weniger logisch) lösen zu können. Und da ist es so, dass viele Wege nach Rom führen. Das habe ich ja im ersten Post angeschnitten, wie es auch ginge, ich es aber nicht machen würde, mit einem Auge auf die Performance des Codes:

Lösung 1 wäre die vermutlich intuitivere, aber aus Performance-Sicht ineffizientere. Und zwar fängt man bei arr[0][0] an und durchläuft es über arr[0][1], arr[0][2], bis iwann arr[3][2], arr[3][3]. Für jedes dieser int-Zellen generiert man eine Zufallszahl zwischen [0, 15], muss aber nun bevor man die generierte Zahl in der Zelle speichert, das gesamte 4x4 Array nochmal durchlaufen um zu prüfen ob die Zahl nicht schon vorhanden ist. Im besten Fall durchläuft man das Array auf diese Art 16*16, also 256 mal. Im Normalfall noch weitaus häufiger.

Lösung 2 welche ich verwendet habe, muss man zugegebenermaßen als Neuling erstmal drauf kommen und erkennen, ist aber genau genommen die logischere Lösung (sicher auch Geschmackssache). Durch die Bedingungen die für die Zufallszahlen gelten, sollte man recht schnell erkennen, das die Zahlen 0 bis 15 jeweils 1 Mal vorkommen müssen / dürfen, daher weil sie in einem 4x4 (=16 Felder) Array angeordnet werden sollen. Man muss nun also nicht immer und immer wieder doppelt Zufallszahlen generieren und das gesamte Array prüfen ob es die Zahl schon gibt, sondern ordnet einmal Zufallszahl 0, 1, ... 15 einer beliebigen Zelle im Array zu. Um den Zufall zu erhalten, pickt man sich nun mit der rand()-Methode eine zufällige Zelle im Array heraus, prüft ob sie noch leer (also NULL) ist und wenn das der Fall ist, speichert man dort die aktuelle Zufallszahl i. Steht schon eine Zahl drin, pickt man solange eine beliebige Zelle heraus, bis man eine leere Zelle gefunden hat. Im Schnitt würde ich schätzen, dass so eine Durchlauf-Anzahl von 16*8 also 128 Durchläufe zusammen kommt.

=> Lösung 2 ist im Durchschnitt schon doppelt so effizient, wie Lösung 1 im Bestfall!

Jetzt ist es so, dass man abwägen lernen muss, wann man eine effiziente Variante suchen muss, wann man mit einer simplen und ineffizienteren Variante über die Runden kommt, etc. Bei diesem Beispiel ist es so, dass ich den genauen Anwendungsfall nicht kenne, aber schon daher Lösung 2 verwendet hätte, weil diese allein schon weniger Zeilen Code benötigt als Lösung 1 und somit auch übersichtlicher, simpler und komfortabler ist. Das ist zwar nicht immer so, meist sind effizientere Lösungen eher komplexer und schwieriger zu durchschauen, aber wie gesagt, da muss man ein Gespühr für entwickeln.

Man könnte sogar Lösung 2 noch weiter in in Richtung Effizienz optimieren, dann wäre der Code aber komplexer geworden. Diese Lösung sollte so jetzt ganz gut für deinen Anwendungsfall passen.

Das wollte ich jetzt nochmal so erklären, weil ich eigentlich nicht so der Freund davon bin, gleich eine komplette Lösung zu posten. Stichwort Pseudocode habe ich ja schon zu genüge erwähnt. Hoffe es hat dir für zukünftige Aufgaben etwas gebracht und auch anderen Programmier-Neulingen die hier evtl. zufällig drauf stoßen, hehe. ;-]

Beste Grüße, AstroNerd

0

Du könntest ein Array der Größe 16 machen und da die Werte von 0 bis 15 rein tun. Danach lässt du dir Zufallszahlen erzeugen, die von 0 bis zur Größe des Arrays geht. Die Zahl verwendest du als Index für das Array und verwendest die Zahl, die da unter liegt. Anschließend kopierst du das letzte Element des Array an die zufällige Indexposition und verringerst die Größe des Array um ein. Das wiederholst du so lange, bis das Array leer ist.