Programmieren C/C++. In einem Array sollen zufällig Zahlen von 1-20 verteilt sein, aber jede Zahl nur einmal. Wer weiß weiter?

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet
Diese Frage kommt hier in letzter Zeit fast jede Woche. :)

Hier ist meine Antwort bzgl. C vom letzten mal:

https://www.gutefrage.net/frage/array-mit-zufallswerten-fuellen-jede-zahl-von1-9darf-nur-1-mal-vorhanden-sein?foundIn=list-answers-by-user#answer-207858604

Allerdings solltest du meinen peinlichen Fehler und die Kommentare darunter beachten, und die Wertvertauschung auf jeden Fall mit einer Temporären Variablen erledigen, also so:

int tmp = arr[i];
arr[i] = arr[idx];
arr[idx] = tmp;

Davon abgesehen bezieht sich deine Frage auf C und C++, also beides.

Allerdings würde ich die Aufgabe in C und C++ VÖLLIG anders realisieren, denn die beiden Sprachen haben eigentlich nur ein gemeinsames "C" im Namen und sollten ansonsten als unterschiedliche Dinge betrachtet werden, auch wenn viele Leute behaupten, dass es kaum Unterschiede gäbe!

Hier ist eine Version in C++ ab Version 11 (!), die ziemlich exzessiven Gebrauch von der STL macht:

#include <algorithm> // copy
#include <chrono> // system_clock
#include <iostream> // cout
#include <iterator> // ostream_iterator
#include <numeric> // iota
#include <random> // default_random_engine

int main(void) {
using namespace std;

// beide Enden inklusive: [start,end]
constexpr int start = 1;
constexpr int end = 20;

// Anzahl Elemente im abgeschlossenen Intervall
constexpr int elems = end - start + 1;

// Vektor anlegen und fuellen
vector values(elems);
iota(values.begin(), values.end(), start);

// nur zu Debug-Zwecken
ostream_iterator out(cout, " ");
copy(values.begin(), values.end(), out);
cout << endl;

// aktuelle Zeit als Seed verwenden
auto now = chrono::system_clock::now();
auto seed = now.time_since_epoch().count();

// Vektor durcheinander wuerfeln
auto prng = default_random_engine(seed);
shuffle(values.begin(), values.end(), prng);

// nochmal Debug-Output
copy(values.begin(), values.end(), out);
cout << endl;
}

Das ganze ist recht effizient (bis auf die Initialisierung des Vektors, was mit einem back_inserter_iterator noch mal deutlich besser geht) und macht im Grunde genommen das Selbe wie die verlinkte C-Version, nur eben "auf C++ Art".

Die Ausgabe sieht z. B. so aus:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 
16 10 14 13 20 8 11 1 4 17 19 18 3 6 15 7 9 5 2 12

Oben noch frisch initialisiert und sortiert, unten hingegen durcheinander gewürfelt, wobei jede der gewünschten Zahlen zwangsläufig nur ein einziges mal vorkommt.

Wie gesagt, das ist die C++11 Version. Achte beim Übersetzen auf die entsprechenden Compiler-Flags!

Wenn du einen älteren Compiler verwendest, musst du neben einigen anderen Änderungen anstelle von shuffle() die Funktion random_shuffle() mit einem anderen Zufallszahlengenerator verwenden. (die beiden letzten Punkte gelten in neuen C++ Versionen als veraltet, und sollten nicht mehr verwendet werden)

Der Code sollte eigentlich selbsterklärend sein, aber wenn du etwas nicht verstehst, dann suche dir einfach die entsprechende Funktion in der Referenz deiner Wahl raus, z. B.:

http://www.cplusplus.com/

Viel Spaß! ;)

Ich würde die Sache anders angehen.

Nim lieber die zahlen von 1-20 und dann verteile sie zufällig in die arrays und nicht anders herum.