Problem mit Zufallszahlenfolge



  • volkard schrieb:

    Und ich wundere mich über die immer gleiche Ausgabe.

    Also ich kriege

    gezogene Zufallszahl: 2
    gezogene Zufallszahl: 3
    gezogene Zufallszahl: 4
    gezogene Zufallszahl: 8
    gezogene Zufallszahl: 10
    gezogene Zufallszahl: 12
    

    Gruß,
    -- Klaus.


  • Mod

    @ Klaus82: Ich würde die Zahl nach hinten tauschen, vor dem Löschen. Die Reihenfolge ist schließlich nicht wichtig. Mit einem erase in der Mitte geht sonst nämlich auch der Fall "6 aus 43743847249" schief.



  • SeppJ schrieb:

    @ Klaus82: Ich würde die Zahl nach hinten tauschen, vor dem Löschen. Die Reihenfolge ist schließlich nicht wichtig. Mit einem erase in der Mitte geht sonst nämlich auch der Fall "6 aus 43743847249" schief.

    Wie meinen?

    Ich sage dem Zufallszahlengenerator, dass er mir Zufallszahlen von 1 bis 'Länge-der-zu-ziehenden-Zahlen' geben soll.

    Die Zufallszahl gibt den Eintrag des Arrays an.

    Diesen Eintrag lösche ich, dass diese Zahl nicht wieder gezogen werden kann.

    Dann geht das Spiel von vorne los, d.h. die maximale Zahl des Generators ist um eins kleiner.

    Ich initialisiere den Generator immer wieder neu, mag vielleicht ein Problem sein.

    Aber warum soll ich was tauschen? 😕

    Gruß,
    -- Klaus.



  • Vorschlag für kleine Ämderungen

    #include <iostream>
    #include <random>
    #include <vector>
    
    int main()
    {
        std::mt19937 engine;//nicht den fricken mt in einer innere Schleife für je eine Zahl 
    		//konstruieren lassen. 
    
    	std::vector<unsigned int> zahlen_zum_ziehen;
    
        for(unsigned int i = 1; i <= 49; ++i)
            zahlen_zum_ziehen.push_back( i );
    
        for(unsigned int i = 1; i <= 6; ++i)
        {
            unsigned int zufallsindex = std::uniform_int_distribution<unsigned int>(1,zahlen_zum_ziehen.size())(engine);
    
            std::cout << "gezogene Zufallszahl: " << zahlen_zum_ziehen[ zufallsindex ] << std::endl;
    
    		/*
            auto it = zahlen_zum_ziehen.begin() + zufallsindex;//hier kein -1
            zahlen_zum_ziehen.erase( it );
            */
            std::swap(zahlen_zum_ziehen[zufallsindex],zahlen_zum_ziehen[zahlen_zum_ziehen.size()-1]);
            zahlen_zum_ziehen.pop_back();
        }
    
        return 0;
    }
    


  • Klaus82 schrieb:

    volkard schrieb:

    Und ich wundere mich über die immer gleiche Ausgabe.

    Also ich kriege

    gezogene Zufallszahl: 2
    gezogene Zufallszahl: 3
    gezogene Zufallszahl: 4
    gezogene Zufallszahl: 8
    gezogene Zufallszahl: 10
    gezogene Zufallszahl: 12
    

    Gruß,
    -- Klaus.

    Ich auch, und zwar JEDES mal. Hast aus Versehen [i] ausgegeben.


  • Mod

    Klaus82 schrieb:

    Aber warum soll ich was tauschen? 😕

    Weil erase auf die Mitte eines vectors furchtbar langsam ist! Da ist doch gerade der ganze Vorteil der Methode (nämlich dass sie in keinem Fall große Nachteile hat) futsch.

    Ich sehe gerade, volkard hat das soeben gut vorgemacht.



  • Klaus82 schrieb:

    Ich sage dem Zufallszahlengenerator, dass er mir Zufallszahlen von 1 bis 'Länge-der-zu-ziehenden-Zahlen' geben soll.

    Oh, die 0 vergessen. Da steht ja die 1, auch eine mögliche Zieh-Zahl.



  • Klaus82 schrieb:

    Ich initialisiere den Generator immer wieder neu, mag vielleicht ein Problem sein.

    Jo. Aber die distribution hat vermutlich das gleiche Problem, daß sie nur Gleichverteilung über eine große Anzahl von Ziehungen garantiert.



  • volkard schrieb:

    Klaus82 schrieb:

    Ich sage dem Zufallszahlengenerator, dass er mir Zufallszahlen von 1 bis 'Länge-der-zu-ziehenden-Zahlen' geben soll.

    Oh, die 0 vergessen. Da steht ja die 1, auch eine mögliche Zieh-Zahl.

    Kann sein, spiele kein Lotto. 😉

    Okay, dann verstehe ich das mit dem Swap. Ich war auf der 'stochastischen Ebene' und hatte mich gefragt, wo das Problem sei.

    Also bei dem Vektor ist es das Problem, dass Indexzugriff vorliegt, d.h. sobald ich ein Element irgendwo lösche, muss der Indexzugriff neu sortiert werden - das kostet Zeit.

    Also das Argument ist, zwei Elemente zu tauschen ist kein großer Aufwand, weil der Indexzugriff dadurch nicht gestört wird.

    Und ein Element am Ende (oder am Beginn) zu löschen hält sich vom Aufwand ebenfalls in Grenzen - ja?

    Ich hatte auch überlegt das ganze mit einer Liste zu machen, weil dann der Löschvorgang nicht aufwendig ist. Allerdings dann das Anzeigen der gezogenen Zahl, weil ich die Liste entlanglaufen muss:

    std::list<int> zahlen_zum_ziehen;
    // stuff
    auto it = zahlen_zum_ziehen.begin() + zufallsindex -1;
    std::cout << "Zufallszahl ist: " << *it << std::endl;
    

    Gruß,
    -- Klaus.



  • Klaus82 schrieb:

    volkard schrieb:

    Klaus82 schrieb:

    Ich sage dem Zufallszahlengenerator, dass er mir Zufallszahlen von 1 bis 'Länge-der-zu-ziehenden-Zahlen' geben soll.

    Oh, die 0 vergessen. Da steht ja die 1, auch eine mögliche Zieh-Zahl.

    Kann sein, spiele kein Lotto. 😉

    Den Index 0 haste vergessen, da steht die Lottozahl 1 drin.



  • volkard schrieb:

    Vorschlag für kleine Ämderungen

    // ......
    
    		/*
            auto it = zahlen_zum_ziehen.begin() + zufallsindex;//hier kein -1
            zahlen_zum_ziehen.erase( it );
            */
            std::swap(zahlen_zum_ziehen[zufallsindex],zahlen_zum_ziehen[zahlen_zum_ziehen.size()-1]);
            zahlen_zum_ziehen.pop_back();
        }
    
        return 0;
    }
    

    Ich werfe an der Stelle einfach mal das Erase-Remove-Idiom ein, wobei das schon fast eher Overkill ist.



  • Hier stand Blödsinn - habs kapiert! 😃



  • Klaus82 schrieb:

    Ich hatte auch überlegt das ganze mit einer Liste zu machen, weil dann der Löschvorgang nicht aufwendig ist. Allerdings dann das Anzeigen der gezogenen Zahl, weil ich die Liste entlanglaufen muss:

    std::list<int> zahlen_zum_ziehen;
    // stuff
    auto it = zahlen_zum_ziehen.begin() + zufallsindex -1;
    std::cout << "Zufallszahl ist: " << *it << std::endl;
    

    Gruß,
    -- Klaus.

    Naja, bei uns ist das Initialisieren noch extrem aufwändig bei 6 aus 1000000, braucht immerhin mindestens mal am Anfang 1000000 Operationen.
    Ich schreibe mal allgemein k aus n.

    Das muss auch unabhängig von n gehen. Vielleicht mit ungefähr k^2 Operationen, wenn man sich die gezogenen Zahlen merkt, statt der noch nicht gezogenen. Und damit meine ich nicht den Weg, so lange zu ziehen, bis man eine ungezogene hat, sondern schon echt einen Index ziehen und anhand der gezogenen die Zahl draus machen.



  • Du Volkard, die Links unter Magazin - empfohlene Artikel lassen sich nicht aufrufen! Hast noch nicht gemerkt? http://www.c-plusplus.net/forum/310212



  • Sandor++ schrieb:

    Du Volkard, die Links unter Magazin - empfohlene Artikel lassen sich nicht aufrufen! Hast noch nicht gemerkt? http://www.c-plusplus.net/forum/310212

    Bitte konkreter. Und Du wirst bemerken, daß keiner dieser Links meine Frage behandelt.



  • Direkt unter dem Satz: Oft empfohlene Artikel sind unter anderem.
    [url]
    http://magazin.c-plusplus.net/artikel/Ein- und Ausgabe in CPlusPlus - IO-Streams
    [/url]

    die restlichen darunter auch.



  • Ah, das war nicht ironisch gemeint.
    Ich leite es weiter an den, der das Serverpasswort hat.



  • Äh, Volkard, der in deinem Sig funktioniert auch nicht oder raff ich da was nicht? 😕



  • Sandor++ schrieb:

    Äh, Volkard, der in deinem Sig funktioniert auch nicht oder raff ich da was nicht? 😕

    Jo, auch kaputt.



  • Das waren waren bestimmt die mit den drei Buchstaben. 🙂


Anmelden zum Antworten