Java Zufallszahlen ohne Zurücklegen?
Für ein Teil eines größeren Projekts muss in in Java eine bestimmte Menge an Zufallszahlen erstellen, wobei sich keine doppeln darf.
Zuerst erstelle ich das neue Objekt "zufallszahl" der Klasse "Random".
In der äußeren For-Schleife wird dann für den Index "a" des Arrays "zufallsPosition[]" eine Zufallszahl erzeugt.
Die innere For-Schleife startet ebenfalls beim Anfangswert und läuft solange die Zählvariable "b" kleiner als die Summe aus dem aktuellen "a" und dem Startwert ist. Somit werden alle Indizes durchlaufen, die durch die vorherigen Durchgänge der äußeren For-Schleife schon eine Zufallszahl besitzen.
In der While Schleife wird dann geschaut, ob der Wert des Index "a" (also der oben erzeugten Zufallszahl) dem jeweiligen Wert des Index "b", also den vorherigen Zufallszahlen entspricht. Ist dies der Fall, bekommt das Array an der Stelle "a" eine neue Zufallszahl zugewiesen. Dies passiert (zumindest theoretisch) solange die aktuelle Zufallszahl "a" der aus der inneren For-Schleife "b" entspircht.
Es würde also bedeuten, dass er immer eine neue Zufallszahl erstellt, wenn diese schon im Array vorhanden ist.
Leider funktioniert das nicht und ich weiß selbst nach längerem Überlegen nicht warum :-(
Dann habe ich mal testweise das "==" in der While-Schleife durch ein "!=" ersetzt, d.h. es wird immer eine neue Zufallszahl erstellt bis sie der vorherigen entspricht, was überraschender Weise funktioniert (beispielsweise haben dann alle Indizes den Wert 4).
Code:
"==" in der While Schleife (so, wie es im Code steht)
"!=" in der While Schleife, funktioniert wie gewünscht.
Vielen Dank für Eure Hilfe!
3 Antworten
du hast ein logik fehler
du kannst doch ncihts setzen wenn du noch gar nicht die ganze reihe abgearbeitet hast .
du musst doch alle testen und erst wenn alle tests false ergeben (bzw keiner davon wahr ist) kannst du die neue setzen .
vor die innere FOR schleife packst du ein
bool found = false;
und dann kommt da keine while schleife in der inneren for schleife
sondern nur ein
if (vergleich psotitionen a == b ) {
found = true ;
}
und nach der inneren for schleife
if (!found) { setze neue zufallszahl ;}
und dann musst du dir noch überlegen was passiert wenn du halt ein doppel gefunden hast , den dann darf die äussere schleife ja nicht hochgezählt werden .
also mit der äusseren solltest du kein FOR nehmen sondern ein WHILE und den Zähler nur weiter setzen wenn halt eine neue zufallszahl auch wirklich gesetzt werden konnte.
habs nochmal nachgebessert , du kannst nicht mit einer äusseren FOR schleife arbeiten , lieber mit while
@TechPech1984 bei mir sieht das jetzt so aus:
public void zufall(int von, int bis)
{
System.out.println("");
Random zufallszahl = new Random();
while()
{
zufallsPosition[a] = zufallszahl.nextInt(bis - von + 1) +von;
boolean found = false;
for(int b = von; b < (von + a) ; b++)
{
if(zufallsPosition[a] == zufallsPosition[b])
{
System.out.println("found");
found = true;
}
}
if(found == true)
{
zufallsPosition[a] = zufallszahl.nextInt(bis - von + 1) +von;
}
System.out.println(zufallsPosition[a]);
}
}
Ich frage mich jetzt aber noch, was ich dann als Bedingung in die äußere While-Schleife schreiben soll.
Also ich würde so an die Sache herangehen:
public class RandomNumber {
public static void main(String[] args) {
ArrayList<Integer> randomNumbers = new ArrayList<Integer>();
for(int i = 0; i<10; i++) {
int generatedNumber = generateNumber(1,10);
if(!randomNumbers.contains(generatedNumber)) {
randomNumbers.add(generatedNumber);
} else {
i--;
}
}
System.out.println(randomNumbers);
}
public static int generateNumber(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + min;
return randomNum;
}
}
Du machst nen Loop der 10 mal durchläuft und jedes mal eine neue Random Zahl erstellt. Diese Zahl wird überprüft ob sie in einer Liste von Zahlen enthalten ist. Wenn ja wird der loop "rückgängig" gemacht (weiss nicht genau obs da in Java ne bessere Alternative gibt als den Zähler - 1). Wenn die Zahl einmalig ist, wird sie dem Array hinzugefügt.
zu deiner frage mit dem
ne bessere Alternative gibt als den Zähler - 1
ja , mann macht gar keine schrittweite in die for schleife (das geht bei java) und erhöht nur wenn eine zufallszahl hinzegfühgt wurde.
@NoArtFX danke für Deine Hilfe. Ich glaube, dass deine Idee doch um einiges leichter ist als meine. Eine Frage hätte ich noch: wofür steht das "!" zwischen der Klammer auf und "randomNumbers"? Sowas ist mir an dieser Stelle noch nie begegnet.
Habe das jetzt eingefügt und bei mir steht da "Undeclared Method: contains(...)" und "Undeclared Method: add(...)"
Muss ich noch irgendwas importieren, damit diese Methoden vorhanden sind?
mein tip , übernehme nichts denn du lernst davon nichts, programmieren ist wirklich das selber auf eine lösung kommen egal über welche umwege , ansonsten machste kopie paste, verstehst nicht wie du darauf gekommen bist und damit lernste auch nix .das ist abgucken , so wie wenn du jemand beim fomrel 1 rennen zuguckst, ohne es selber zu machen wirst du halt nicht formel 1 fahrer . ich hab dir doch die lösung schon geschrieben . und du bist ja auch schon fast bei der lösung . warum wirfste alles wech ? jetzt schon aufgeben ... naja .
@TechPech1984 habe keinesfalls aufgegeben, probiere nur deine Variante und die von NoArtFX gleichteitig aus
da nimmt man schlicht kein for sondern ein while mit doppelbedinung wenn zähler nicht max oder einer gefunden wiederhole .
ich mach dir mal ein pseudocode damit du da mal die richtigen gedanken bekommst.
also
du willst 10 zufallszahlen erzeugen , die nicht doppelt sein sollen , was ist zu tun
du fängst mit der 1 position (im array 0. position) an , dann
machst du solange eine neue zufallszahl solange die position noch nicht länger als die endposition ist .
wenn du eine zufallszahl den endlich gefunden hast die nicht drinne vorgekommen ist , setzt du die zufallszahl an die stelle erhöhst du den zähler für die stelle
array[10]
pos = 0
/* erzeugung */
while (pos < 10 ) /* solange nicht alle positionen eine zufalls zahl haben */
{
zufallgefunden = false;
zufall = neuerzufall;
for (i=0 to pos)
{
if (array[i] == zufall)
{
zufallgefunden = true;
break; /* beende for schleife */
}
}
if (!zufallgefunden) /* also wenn NICHT zufallgefunden , also zufallgefunden false ist und das nicht macht daraus true */
{
array[pos] = zufall;
pos++;
}
}
/* ausgabe */
for (i=0 to pos)
{
print array[i];
}
das musst du in java umsetzen
habs nochmal korrigiert wegen dem
zufallgefunden = false;
das war an der falschen stelle .
Es funktioniert endlich, danke erstmal für Deine Hilfe :-)
Die erste FOR-Schleife durchläuft die bisher mit Zufallszahlen zugewiesenen Indizes.
Wenn an einer Stelle der Wert des Index i gleich dem der vor der FOR-Schleife erzeugten Zufallszahl ist, wird die Boolean-Variable auf "true" gesetzt und die for-Schleife wird abgebrochen. Geht der dann wieder an die Stelle "found = false"(an den Anfang von dem, was in der WHILE-Schleife steht)? Alles andere würde ja keinen Sinn ergeben, da sonst, wenn er ganz an den Anfang zu der WHILE-Schleife gehen würde, die zweite Bedinigung, also "found == true", erfüllt wäre und somit die WHILE-Schleife gar nicht ausgeführt werden würde, obwohl mit einer relativ hohen Wahrscheinlichkeit noch nicht alle Stellen mit den "richtigen" Zufallszahlen gefüllt sind.
Ist "found == false", also wenn die zuvor erstellte Zufallszahl noch nicht in den vorherigen Stellen vorhanden ist, ordnet er diese dem aktuellen Index zu. Anschließend wird die Zählvariable um 1 erhöht, sodass die WHILE-SCHLEIFE a) abbricht oder b) noch mal durchläuft, diesmal mit der nächsten Stelle.
In der unteren FOR-Schleife wird das Array durchlaufen und dabei werden die Werte der jeweiligen Indizes ausgegeben, das ist ja klar.
Ich würde mich freuen, wenn Du mir sagen könntest, ob ich es im Allgemeinen richtig verstanden habe und mir Du mir vielleicht die Funktion des "found = true" in der ersten IF-Schleife erklären/erläutern könntest.
ich geb zu die while schleife ist tricky .
und wo du es gerade erklärst sogar zu tricky :) da hab ich zuviel gedacht .
eigentlich kann das
OR zufallgefunden
weg . denn es wiederholt sich ja sowieso solange die end position nicht überschritten wurde und pos sich ja auch nur erhöht wenn eine neue zufallszahl gesetzt wurde .
sorry , da wa ich etwas übereifrig :) mein erster gedanke war ganz anders, deswegen hab ich den fehler mitgeschleppt ;)
ich korrigiere das mal .
könntest du nochmal dein aktuellen code posten , dann kommentier ich das in deinem code rein .
Code:
public void zufall(int von, int bis)
{
System.out.println("");
Random zufallszahl = new Random();
boolean found = false;
int a = von;
while(a < bis || found == true)
{
found = false;
int zufall = zufallszahl.nextInt(bis - von + 1) +von;
for(int b = von; b < (von + a + 1) ; b++)
{
if(zufallsPosition[b] == zufall)
{
found = true;
break;
}
}
if(found == false)
{
zufallsPosition[a] = zufall;
a++;
}
}
for(int i = von; i < (bis +1); i++)
{
System.out.println(zufallsPosition[i]);
}
}
Ja stimmt, es funktioniert auch, wenn man dass "|| found == true" in der Bedingung für die WHILE-Schleife entfernt.
Und nochmal allergrößten Dank Dich, dass Du in Deiner Freizeit anderen Leuten bei ihren Problemen in Informatik hilfst :-)
public void zufall(int von, int bis)
{
System.out.println(""); /* ausgabe nichts */
Random zufallszahl = new Random(); /* radom generator initialisieren */
boolean found = false; /* wird benötigt für die findeung von doppelten zufallszahlen */
int a = von;
while(a < bis) /* solange das ende nicht erreicht ist wiederhole */
{
found = false; /* startwert setzen , fals der bei doppelten fund auf true gesetzt wurde */
int zufall = zufallszahl.nextInt(bis - von + 1) +von; /* zufallszahl erzeugen */
for(int b = von; b < (von + a + 1) ; b++) /* die bisher erzeugen zufallszahlen überprüfen */
{
if(zufallsPosition[b] == zufall) /* wenn zufallszahl schon an einer position vorhanden */
{
found = true; /* dann merk dir das */
break; /* und beende die schleife , ein doppel zu finden reicht */
}
}
if(found == false) /* wenn kein doppel gefunden wurde */
{
zufallsPosition[a] = zufall; /* pack die zufallszahl an aktuelle position */
a++; /* erhöhe die position */
}
}
for(int i = von; i < (bis +1); i++)
{
System.out.println(zufallsPosition[i]);
}
}
reicht dir das ? btw zum lesen ist variable a und b halt echt schlecht gewählt
dann lieber position für a und den standard zähler i für b , denn guten code kann man so lesen ohne nachdenken zu müssen .
Ist so gut verständlich :-)
Danke für den Hinweis, die Variablennamen ändere ich jetzt noch.
sowas kannst du noch ändern
b < (von + a + 1)
i < (bis +1)
in
b <= (von + a)
i <= bis
du kannst auch noch das
boolean found = false;
einfach runter packen und das
found = false;
damit ersetzen .
bei java geht das ja , da die im block ja eigenständige variablen sind, in anderen sprachen darf man das so nicht machen , da wäre dann der fehler , wurde schon definiert .. :)
allerdings wunder ich mich das du die while schleife
while(a < bis)
machst
und aber unten bei der ausgabe
von <= bis
machst
da fehlt doch dann eine position
immer daran denken array fangen bei 0 an nicht bei 1 und gehen bei z.b. array[10] halt nur bis 9
Erstmal danke für die weiteren Optimierungstipps.
Verstehe ich auch nicht, funktioniert aber. Würde dir eigentlich gerne einen Screenshot der Ausgabe schicken, in diesem Antwort-Modus kann ich aber leider keine Bilder einfügen.
Wenn man "while(a<=bis)" hinschreibt, dann scheint es so, als ob die Bedingung nie erfüllt werden kann, weil diese "Java Virtual Machine" die ganze Zeit läuft, der Computer also rechnet.
Danke schonmal für die Tipps. Ich bin gerade dabei es zu überarbeiten.