Algorithmus gesucht ...



  • Sonne55 schrieb:

    Leider macht er das nicht, weil man den count if Befehl wohl nicht zwei mal hintereinander anwenden kann...

    Wie kommst du auf solche Schlussfolgerungen? Eine Funktion die man nur einmal aufrufen kann ist reichlich sinnlos. Les doch lieber mal die Fehlermeldungen und versuche diese zu verstehen! Die Fehlermeldung wegen Redefinition von first und last liegt daran, dass du beide Variablen zweimal definierst. Nach der ersten Definition darfst du diese nicht erneut definieren. Du kannst aber den bereits vorhandenen Variablen einfach einen neuen Wert zuweisen:

    first = prufzahlen.lower_bound(x/2);
    last  = prufzahlen.lower_bound(x+1);
    

    Das geht natürlich nur wenn die Typen übereinstimmen aber hier speichern wir ja in beiden Fällen Iteratoren in eine std::map<int, int> also passt das.

    Sonne55 schrieb:

    Also bei map kann man 2 Zahlen miteinander verkoppeln. Gibt es auch einen Contener, wo man 3 Zahlen miteinander verkoppeln kann?

    Wie verstehst du verkoppeln? Verkoppeln heißt hier, dass es einen Schlüssel/Key und Werte gibt und man eine feste Zuordnung von einem Key zu einem Wert hat. In deinem Code nutzt du aber das bisher noch nicht. Wenn du einfach nur zwei oder mehr Werte speichern willst geht das auch in einem vector :

    std::vector<std::pair<int, int>> x; // vector von int Paaren
    std::vector<std::tuple<int, int, float>> y; // vector von 2 ints und einem float
    

    Bei pair kann man immer zwei Werte kombinieren und bei tuple beliebig viele. Aber jetzt gibts natürlich keinen Zusammenhang zwischen den einzelnen Werten wie bei einer map .



  • sebi707 schrieb:

    In deinem Code nutzt du aber das bisher noch nicht.

    Doch doch, sebi707, 1 repräsentiert PZ und 2 Vf, die dürfen nicht verrücken. Das ist eine feste Zuordnung.

    Ich hätte die beiden, also PZ und VF noch gern numeriert.

    Vielen Dank für die Ausführungen ....



  • Ich habs jetzt so gemacht, einfach neuen Variablen creiert. Elegant ist das nicht, und er zählt unten auch nicht. Mir ist auch nicht deutlich, warum das nach dem Weglassen der beiden "auto" funktioniert.

    #include <iostream>
    #include <stdio.h>
    #include <cmath>
    #include <map>
    using namespace std;
    
    int pzz=1; //Primzahlzähler
    int vfz=1; //Vielfachenzähler
    int ruz=1; //Rundenzähler
    
    int main()
    {
        map <int,int> prufzahlen;
        map<int,int>::iterator iter;
        int x, i;
        for (x = 31; x <= 1200; x=x+30)
        {
            ruz++;
            for (i = 2; i < x; i++)
            {
                if (x%i == 0)
                    break;
                //cout<<i<<"= i \n";
            }
    
            if (i == x)
            {
                cout<<"Nr. "<<ruz<<" "<<x<<" = "<<pzz<<". Pz. \n";
                pzz++;
                 prufzahlen.insert(pair<int, int>(x, 1));
            }
            else
            {
                cout<<"Nr. "<<ruz<<" "<<x<<" = "<<vfz<<". uVf. \n";
                vfz++;
                prufzahlen.insert(pair<int, int>(x, 2));
            }
    
           for (iter = prufzahlen.begin(); iter != prufzahlen.end(); iter++)
                    {
               //     cout << iter->first << " ";
                 //   cout << iter->second << " ";
                   // cout << endl;
    
                    }
            std::cout << "Kettelänge= " << prufzahlen.size()+1 << " "<<'\n';
            double helfte=x/2;
            cout<<"Hälfte "<<helfte<<"\n";
            int a=1;
            int b=helfte;
            auto first = prufzahlen.lower_bound(a);// erstes Element:
            auto last  = prufzahlen.lower_bound(b); // "eins hinter das letzte Element"
            auto is_1 = [](const map<int,int>::value_type& p){return p.first==1; };
            // das eigentliche zaehlen:
            auto n = count_if(first, last, is_1);
            cout<<"davon unten "<< n <<" PZ"<< endl;
    
            a=helfte;
            b=x+1;
    
            first = prufzahlen.lower_bound(a);
            last  = prufzahlen.lower_bound(b);
            auto is_2 = [](const map<int,int>::value_type& p){return p.second==2; };
            auto nx = count_if(first, last, is_2);
            cout<<"davon oben "<< nx <<" Vf und "<<((ruz/2)- nx)<<" PZ"<< endl;      
        }
        return 0;
    }
    


  • Sonne55 schrieb:

    Mir ist auch nicht deutlich, warum das nach dem Weglassen der beiden "auto" funktioniert.

    Dort wo bei der Variablendefinition das auto steht, da steht ja normalerweise der Typ der Variable. Wenn ich das ganze mit ints schreibe wird es dir vielleicht klarer:

    int a = 1;
    int a = 2; // compiliert nicht, Neudefinition von a
    

    Wenn du schon eine int Variable mit dem Namen 'a' angelegt hast darfst du keine weitere anlegen wie dir vielleicht bekannt ist. Bei auto ist das nichts anderes außer, dass du den Typ der Variable nicht selbst hinschreibst.

    Sonne55 schrieb:

    Doch doch, sebi707, 1 repräsentiert PZ und 2 Vf, die dürfen nicht verrücken. Das ist eine feste Zuordnung.

    Die Paare bleiben auch beim vector zusammen. Der Vorteil bei einer map ist aber, dass man von dem Key (welcher einzigartig sein muss) schnell den dazugehörigen Wert erhalten kann. In deinem Fall könntest du also nachschauen ob eine Zahl y eine Primzahl oder ein Vielfaches ist indem du prüfst ob prufzahlen[y] gleich 1 oder 2 ist. Genau das machst du bisher aber noch nicht.



  • sebi707 schrieb:

    Wenn du schon eine int Variable mit dem Namen 'a' angelegt hast darfst du keine weitere anlegen wie dir vielleicht bekannt ist.

    Deshalb habe ich ja zuerst

    double helfte=x/2;
            cout<<"Hälfte "<<helfte<<"\n";
            int a=3;
            int b=helfte;
    

    geschrieben und dann nochmal ohne int

    a=helfte;
            b=x+1;
    

    um den Start und Stopwert zu ändern.

    Kann das sein, daß er die untere Reihe nicht zählt (es ist der erste Block), weil Helfte Double ist, map aber mit int int angelegt ist?

    Sonne55 schrieb:

    In deinem Fall könntest du also nachschauen ob eine Zahl y eine Primzahl oder ein Vielfaches ist indem du prüfst ob prufzahlen[y] gleich 1 oder 2 ist. Genau das machst du bisher aber noch nicht.

    Das kenn ich nicht, wie geht das?



  • Sorry, aber das Programm ist richtiger Schrott.

    Das ist doch alles zusammenkopiert, ohne dass Du es verstanden hast.

    Was für Lehrmaterialien hast Du?
    Wie lautet die Aufgabe?
    Und interessehalber: Durch wen wurde die Aufgabe gestellt?

    Und dann können wir Dir eventuell ein paar wertvolle Hinweise geben.



  • Furble Wurble schrieb:

    Sorry, aber das Programm ist richtiger Schrott.

    mag sein ...aber bislang macht es, was ich will...

    Furble Wurble schrieb:

    Das ist doch alles zusammenkopiert, ohne dass Du es verstanden hast.

    stimmt für die Befehle, die ich bislang nicht kenne!

    Furble Wurble schrieb:

    Was für Lehrmaterialien hast Du?

    Nur Internet und Dirk Louis (C++) - hab vor 3 Jahren gekauft das Buch. Da steht relativ wenig zu den Algorithmen, gerade daß sie erwähnt und gelistet werden. Also, wenn jemand noch was auf DLouis aufbauendes, tiefergehendes deutssprachiges speziell für Xcode und C++ weiß, soll er das mal hier empfehlen.

    Furble Wurble schrieb:

    Wie lautet die Aufgabe?

    gar nicht - bin einfacher Imker und mache Hobbymathe in der kalten Jahreszeit. Momentan interessieren mich Primzahlen, und Programmieren macht man am besten anhand konkreter Aufgaben, damit man gezwungen ist, die Befehle gleich in richtiger Umgebung einzusetzen. Wenn man einen Schritt geschafft hat, macht man den Nächsten. So wachsen die Aufgaben. Ich will jetzt keine 1 in Programmieren vom Forum erhalten. Die Programme sollen nur die Aufgabe lösen. Das tun oft auch umständliche Programme.

    Furble Wurble schrieb:

    Und interessehalber: Durch wen wurde die Aufgabe gestellt?

    Durch mich. Durch niemanden sonst. Kein Kurs, kein Lehrpensum, keine Volkshochschule, kein Lehrer, kein Bekannter, der sich für das Programmieren interessiert, nur ich, Kakautasse und Xcode. Mein Interesse gilt der Mathematik, habe aber nur 10 Klassen. Das gute ist am Computer, daß man sich mathematische Fragen stellen kann, und diese am Computer objektiv numerisch Lösen kann. z. B. wie lautet die 333333. Primzahl? Mag zwar für andere lächerlich sein, macht aber ungemein Spaß, sowas selbst zu fragen und zu lösen.... (mithilfe der Programmierung)

    Furble Wurble schrieb:

    Und dann können wir Dir eventuell ein paar wertvolle Hinweise geben.

    so ich hoffe, was ich Dir hier bekannt habe, ist alles legal und erlaubt und auch Ok.. man weiß ja nie, was alles so verboten ist und wwer wo was dagegen hat....



  • Sonne55 schrieb:

    Furble Wurble schrieb:

    Wie lautet die Aufgabe?

    gar nicht - bin einfacher Imker und mache Hobbymathe in der kalten Jahreszeit. Momentan interessieren mich Primzahlen, und Programmieren macht man am besten anhand konkreter Aufgaben, damit man gezwungen ist, die Befehle gleich in richtiger Umgebung einzusetzen. Wenn man einen Schritt geschafft hat, macht man den Nächsten. So wachsen die Aufgaben.

    Okay. Jetzt weiß ich worum es geht, bzw. worum es nicht geht. Es geht um Spaß und Interesse. Es geht nicht um Hausaufgaben. Das eröffnet natürlich ganz neue Möglichkeiten.

    Wachsende Aufgaben verlangen umso mehr nach einer gewissen Struktur:
    Versuch mal den Primzahltest in eine Funktion auszulagern und sieh wieviel übersichtlicher das Programm wird. Z.B.

    bool ist_prim(int x);
    

    Auch das ausgeben der gesamten map prufzahlen kannst Du in eine Funktion auslagern.

    Deine magischen 1 und 2, mit der logischen Bedeutung "ist Primzahl", bzw. "ist keine Primzahl" ist mir auch ein Dorn im Auge...aber dazu vielleicht später mehr.



  • Sonne55 schrieb:

    Sonne55 schrieb:

    In deinem Fall könntest du also nachschauen ob eine Zahl y eine Primzahl oder ein Vielfaches ist indem du prüfst ob prufzahlen[y] gleich 1 oder 2 ist. Genau das machst du bisher aber noch nicht.

    Das kenn ich nicht, wie geht das?

    Sollte eigentlich in jedem Buch das std::map behandelt drin stehen. So kann das z.B. aussehen: http://www.cplusplus.com/reference/map/map/operator[]/ (leider nur Englisch).
    In deinem Fall kannst du einfach mit prufzahlen[61] oder irgendeiner anderen Zahl/Variable nachschauen was du für 61 ausgerechnet hattest. Vorsicht: Bei Elementen die nicht in der map sind gibt es keinen Fehler sondern dieser Wert wird einfach erstellt und als leeres Element bzw. bei Zahlen als 0 initialisiert.

    PS: Da du an Zahlenrätsel Spaß hast kann ich dir Project Euler empfehlen (leider auch Englisch, gibt aber glaube ich irgendwo deutsche Übersetzungen). Im Gegensatz zu selbst gestellten Fragen kann man hier seine Lösung überprüfen und schon öfter war meine erste Lösung falsch weil ich irgendwas nicht bedacht habe.



  • Nur mal zwischendurch: Also, wenn jemand noch etwas auf den Einführungslehrgang von Dirk Louis aufbauendes C++ Buch kennt, also, wo z. b. die Algorithmen drin ausfürlich erläutert werden, natürlich, auf Deutsch, der kann es hier posten.

    in der Sache weiter im nächsten Posting.



  • Furble Wurble schrieb:

    Z.B.

    bool ist_prim(int x);
    

    Auch das ausgeben der gesamten map prufzahlen kannst Du in eine Funktion auslagern.

    Ich versteh das so:
    bool - ist eine Variable vom Typ "bool" mit wahr (1) oder falsch (0) drin.
    ist_prim - ist, nehm ich an, eine selbstgeschriebene Funktion...?
    (int x)- ist der Übergabewert, wobei ich mich frage, warum der in der Klammer initialisiert wird?

    Aber ich habe mit bool noch nichts gemacht, und mit Funktionen nur ein paar Übungsbeispiele.Die Schwierigkeit dabei war für mich immer die Formulierung der Werteübergabe.

    Furble Wurble schrieb:

    Deine magischen 1 und 2, mit der logischen Bedeutung "ist Primzahl", bzw. "ist keine Primzahl" ist mir auch ein Dorn im Auge...aber dazu vielleicht später mehr.

    Wenn man sich die Summe der Einsen und Zweien eines bestimmten Abschnittes ausgeben läßt, weiß man genau, wieviel PZ und VF in ihr enthalten sind. Weil ich diese Funktion zur Püfung nochbrauche, hatte ich das so konzipiert.

    Frage: Ist das eine C++Konvention die Namen der Funktionen mit Unterstrich zu schreiben, wie z.B. is_2; is_prim



  • Sonne55 schrieb:

    Nur mal zwischendurch: Also, wenn jemand noch etwas auf den Einführungslehrgang von Dirk Louis aufbauendes C++ Buch kennt, also, wo z. b. die Algorithmen drin ausfürlich erläutert werden, natürlich, auf Deutsch, der kann es hier posten.

    Ich hab zwei gefunden:
    http://www.amazon.de/exec/obidos/ASIN/3540256938 (Wird hier im Forum empfohlen, leider etwas veraltet)
    http://www.amazon.de/C--Standardbibliothek-kurz-Rainer-Grimm/dp/3955619680 (Auf Amazon gefunden, etwas kurz, scheint aber vieles nützliches abzudecken, Leseprobe hier)

    Anmerkung: Ich habe keins dieser Bücher gelesen und kann daher nichts zu derren Qualität sagen oder ob das Wissen aus deiner C++ Einführung dazu reicht alles zu verstehen.

    Sonne55 schrieb:

    Aber ich habe mit bool noch nichts gemacht, und mit Funktionen nur ein paar Übungsbeispiele.Die Schwierigkeit dabei war für mich immer die Formulierung der Werteübergabe.

    Schaue nochmal das Kapitel über Funktionen in deinem C++ Buch. Funktionen sind elementar wichtig!

    Sonne55 schrieb:

    Wenn man sich die Summe der Einsen und Zweien eines bestimmten Abschnittes ausgeben läßt, weiß man genau, wieviel PZ und VF in ihr enthalten sind. Weil ich diese Funktion zur Püfung nochbrauche, hatte ich das so konzipiert.

    Für andere Leute und für dich wenn du ein Jahr später nochmal auf deinen Code schaust wird aber nicht sofort klar, dass 1 eine Primzahl bedeutet und 2 eben keine.

    Sonne55 schrieb:

    Frage: Ist das eine C++Konvention die Namen der Funktionen mit Unterstrich zu schreiben, wie z.B. is_2; is_prim

    Zumindest in der C++ Standardlibrary. Für eigene Funktionen/Variablen kann man auch was anderes machen.



  • So ich hab jetzt mal des Bewerten, ob prim oder nicht in eine Funktion ausgelagert.

    Aber wo FurbelWurbel und sebi007, ist der Vorteil?

    Fragen:
    1. Warum funktioniert das i nicht, wenn ich es in der for-Klammer initialisiere mit int i?

    2. Warum muß ich in der Funktion, genauer in der if-Struktur Ergebnis 2 x initialisieren?

    3. Warum muß ich return Ergebnis 2 x schreiben?

    #include <iostream>
    using namespace std ;
    int i;
    
    int pz_test(int param)//Funktion selber
    {
        for (i = 2; i < param; i++)
        {
            if (param%i == 0)
                break;
        }
        if(i==param)
            {int Ergebnis=1;
            return Ergebnis;}
        else
           {int Ergebnis=2;
        return Ergebnis;}
    }
    
    int main(int argc, const char * argv[])
    {
        for (int x=1;x<=25;x=x+1)
        {
            cout<<x<<" = "<<pz_test(x)<<"\n";
        }
        return 0;
    }
    


  • Sonne55 schrieb:

    1. Warum funktioniert das i nicht, wenn ich es in der for-Klammer initialisiere mit int i?

    Weil die Variable dann nur in den geschweiften Klammern von der for Schleife sichtbar ist. Statt das i dann direkt global zu machen kannst du es auch einfach vor der for Schleife, aber in der pz_test Funktion definieren.

    Sonne55 schrieb:

    2. Warum muß ich in der Funktion, genauer in der if-Struktur Ergebnis 2 x initialisieren?

    Weil du der Variable Ergebnis abhängig von einer Bedingung unterschiedliche Werte zuweisen willst. Man kann es tatsächlich noch leicht anders schreiben aber das ist nicht gerade übersichtlicher, daher zeige ich das jetzt mal nicht. Eigentlich brauchst du die Ergebnis aber gar nicht, da du ja direkt den Wert zurück gibst. Man kann auch direkt Zahlen zurückgeben:

    if(i==param)
    {
        return 1;
    }
    else
    {
        return 2;
    }
    

    Sonne55 schrieb:

    3. Warum muß ich return Ergebnis 2 x schreiben?

    Muss man nicht. Wenn du die Variable Ergebnis außerhalb des if Blocks definieren würdest könnte man das auch danach noch nutzen:

    int Ergebnis;
    if(i==param)
    {
        Ergebnis=1;
    }
    else
    {
        Ergebnis=2;
    }
    return Ergebnis;
    

    Eigentlich kann man sich aber auch den Vergleich nach Schleife sparen. Wenn man jetzt noch bool benutzt könnte die Funktion etwa so aussehen:

    bool ist_pz(int param)
    {
        for (i = 2; i < param; i++)
        {
            if (param%i == 0)
                return false;
        }
        return true;
    }
    

    Sonne55 schrieb:

    Aber wo FurbelWurbel und sebi007, ist der Vorteil?

    Man könnte deine Schleife aus deinem ursprünglichen Programm etwa so schreiben:

    for (x = 31; x <= 1200; x=x+30)
    {
        ruz++;
        if(ist_pz(x))
        {
            cout<<"Nr. "<<ruz<<" "<<x<<" = "<<pzz<<". Pz. \n";
            pzz++;
            prufzahlen.insert(pair<int, int>(x, 1));
        }
        else
        {
            cout<<"Nr. "<<ruz<<" "<<x<<" = "<<vfz<<". uVf. \n";
            vfz++;
            prufzahlen.insert(pair<int, int>(x, 2));
        }
    }
    

    Jetzt kann man immerhin anhand des Namens der Funktion ist_pz darauf kommen, dass es sich um einen Primzahltest handelt. Außerdem kannst du den Primzahltest so auch von mehreren Stellen im Programm einfach benutzen und in andere Programme übertragen weil du nur die Funktion kopieren musst. Wenn du dich später dazu entscheidest einen besseren Primzahltest zu programmieren brauchst du nur diese Funktion zu ändern und überall wo diese benutzt wird hast du automatisch den neuen Test.



  • Sonne55 schrieb:

    So ich hab jetzt mal des Bewerten, ob prim oder nicht in eine Funktion ausgelagert.

    Aber wo FurbelWurbel und sebi007, ist der Vorteil?

    Ein großer Vorteil ist, dass Du Übersicht gewinnst. Kurze Funktionen sind lesbarer. Sie sind leichter zu dokumentieren und komplexe Aufgaben lassen sich durch Kombination einzelner Funktionen implementieren.
    sebi707 hat das ja auch schon beantwortet.

    Hier mal Deine Funktion pz_test() aufgebrochen in zwei Funktionen:

    bool ist_prim(int x) {
      for (int i = 2; i < x; i++)
        if (x%i == 0)
          return false;
      return true;
    }
    
    int pz_test(int x) {
      if(ist_prim(x))
        return 1;
      else
        return 2;
    }
    

    Zu Deinen weiteren Fragen: Lies endlich Dein Buch!



  • Also Danke an alle.

    Jetzt noch mal eine Weitermach-Frage.

    Ich habe jetzt 4 Werte zu jeder Zahl:
    1 die Zahl (key)
    2. den value (hier 1 PZ oder 2 Vf)
    3. die wievielte PZ da ist und
    4. wieviel Vf bisher in der Kette sind.
    5. Man könnte noch die laufende Nummer hinzuziehen.

    Welcher Container ist nun der geeignete, unter der Betrachtung, daß ich auf verschiedene Abschnitte zugreifen will und dazu jeweils die Daten brauche? Das Abfrageteil mach ich mit cin erst zum Schluss.

    Man könnte die Daten ja alle in einen vector schreiben, immer 5 hintereinander und dann mathematisch abgreifen. Seht Ihr eine bessere Lösung?

    Im Beispiel kann man in Main nur alternativ das Cout oder das hier auskommentierte prüfzahlen.insert laufen lassen, da sonst das über globale Variable funktionierende getrennte Zählen doppelt läuft und somit falsch Ergebnisse zeitigt.

    #include <iostream>
    #include <stdio.h>
    #include <cmath>
    #include <map>
    using namespace std ;
    int i;
    int Nr=1;
    int pzz=0;
    int vfz=0;
    
    int pz_test(int param)//Funktion selber
    {
        for (i = 2; i < param; i++)
        {
            if (param%i == 0)
                break;
        }
        if(i==param)
           {pzz=pzz+1; return 1;}
        else
           {vfz=vfz+1; return 2;}
    }
    
    int main(int argc, const char * argv[])
    {
        map <int,int> prufzahlen;
        map<int,int>::iterator iter;
        for (int x=1;x<=2000;x=x+2)
        {
            cout<<Nr<<". "<<x<<" = "<<pz_test(x)<<" PNr: "<<pzz<<"   VNr: "<<vfz<<"\n";
            //prufzahlen.insert(pair<int, int>(x,pz_test(x)));
            Nr++;
        }
        for (iter = prufzahlen.begin(); iter != prufzahlen.end(); iter++)
        {
            cout << iter->first << " "<< iter->second <<"\n";
        }
        return 0;
    }
    


  • sebi707 schrieb:

    Sonne55 schrieb:

    Frage: Ist das eine C++Konvention die Namen der Funktionen mit Unterstrich zu schreiben, wie z.B. is_2; is_prim

    Zumindest in der C++ Standardlibrary. Für eigene Funktionen/Variablen kann man auch was anderes machen.

    Man sollte. Hinterfragt immer, ob sich ein masochistischer Stil überhaupt lohnen kann.


Anmelden zum Antworten