instanzen einer klasse sortieren



  • Hi,

    nur als Ergänzung: Wenn Du sowieso immer mit sortiertem Container arbeiten willst, kannst DU gleich ein std::set oder std::multiset nehmen.

    Gruß,

    Simon2.



  • Er will nach 3 verschiedenen Kriterien sortieren (vermutlich mal das eine, mal da andere), da braucht er doch drei verschiedene Comparator Klassen, oder nicht? (ergo kein operator< für die Klasse und auch kein set o.ä.) Oder irre ich mich da jetzt.



  • Shinja schrieb:

    Er will nach 3 verschiedenen Kriterien sortieren (vermutlich mal das eine, mal da andere), da braucht er doch drei verschiedene Comparator Klassen, oder nicht? (ergo kein operator< für die Klasse und auch kein set o.ä.) Oder irre ich mich da jetzt.

    Stimmt schon, allerdings bin ich mir nicht sicher, ob er das Sortierkriterium wechseln will. Wenn, dann hast Du natürlich Recht.

    Gruß,

    Simon2.



  • Er braucht da nicht drei verschiedene Comperatorklassen. Da reicht Eine mit verschiedenen Vergleichsfunktionen die man im Konstruktor dieser Klasse über ein enum einstellt. Dies erscheint mir besser handhabbar und flexibler.



  • danke für eure Antworten. Leider durchblicke ich als Anfänger das mit MyComparator noch nicht ganz.

    ich möchte immer anders sortieren. Das hängt dann von der Benutzereingabe ab.
    Ich kann aber mit der Klasse MyComparator immer nur 2 vergleichen. Das heißt ich muss mir dann händisch einen Sortieralgorithmus bauen?

    Könnt ihr mir das an einem konkretes Beispiel zeigen z.B. anhand dem unten angeführten Beispiel.

    danke!
    michi

    #include <iostream>
    using namespace std;
    
    class name{
            private:
                    string vorname;
                    string nachname;
                    int alter;
            public:
                    name(string vorname,string nachname,int alter):vorname(vorname),nachname(nachname),alter(alter){};
    
                    string getVorname(){
                            return vorname;
                    }
    
                    string getNachname(){
                            return nachname;
                    }
    
                    int getAlter(){
                            return alter;
                    }
                    void ausgabe(){
    
                    }
    
    };
    

    und die klasse liste

    #include <iostream>
    #include <vector>
    #include "name.cpp"
    using namespace std;
    
    class liste{
    	private:
    	vector <name> liste;
    	public:
    void hinzufuegen(name &a){
    		liste.push_back(a); 
    }
    
    void ausgabe(){
    // TODO: sortierte ausgabe nach Nachname
    
    for(unsigned int i=0;i<liste.size();i++){
         cout << "--------------------------------------------\n";
         cout << "vorname: " << liste[i].getVorname() << endl;
         cout << "nachname: " << liste[i].getNachname()<< endl;
         cout << "alter: " << liste[i].getAlter() << endl;
    }
    
         cout << "--------------------------------------------\n";
    }
    
    };
    
    int main(){
    liste l1;
    cout << "Instanzen Sotierer v.1.02" << endl;
    name n1("Thorsten","Schmied",26);
    name n2("Martin","Meier",23);
    name n3("Hubert","Mueller",24);
    
    l1.hinzufuegen(n1);
    l1.hinzufuegen(n2);
    l1.hinzufuegen(n3);
    l1.ausgabe();
    
    return 0;
    }
    


  • das wäre dann sowas wie (ungetestet)

    class NameComperator{
    public:
        bool operator()(const name& n1,const name& n2){
            return n1.getname()<n2.getname();
        }
    };
    

    Nutzen tust du es dann so (beispiel ist wenn die Namen in einem vector gespeichert sind, bitte anpassen):

    #include <algorithm>
    #include <vector>
    //...
    std::vector<name> vn;
    //füllen des vectors
    std::sort(vn.begin(),vn.end(),NameComperator())
    

    Analog für Nachname und Alter.

    Ich bin selbst noch Anfänger, sollte ich mich geirrt haben sorry!



  • Ja, der Komparator vergleicht immer zwei Objekte - der wird im Sortieralgorithmus dann entsprechend of bemüht mit verschiedenen Eingabewerten:

    struct MyComparator : public binary_function<name,name,bool>
    {
      enum{sort_vn,sort_nn,sort_al} sort_typ;
      MyComparator(sort_typ t) : typ(t) {}
      bool operator()(const name& l,const name& r)
      {
        //berechne l<r
        switch(typ)
        {
        case sort_vn: return l.getVorname()<r.getVorname();
        case sort_nn: return l.getNachname()<r.getNachname();
        case sort_al: return l.getAlter()<r.getAlter();
        }
      }
    private:
      sort_typ typ;
    };
    
    class liste
    {
      ...
    public:
      ...
      void sortiere(MyComparator::sort_typ typ)
      { sort(liste.begin(),liste.end(),MyComparator(typ)); }
    };
    

    (PS: Übrigens ist es nicht sinnvoll, einer Klasse und einer ihrer Member-Variablen den selben Namen zu verpassen ;))



  • Braunstein schrieb:

    Er braucht da nicht drei verschiedene Comperatorklassen. Da reicht Eine mit verschiedenen Vergleichsfunktionen die man im Konstruktor dieser Klasse über ein enum einstellt. Dies erscheint mir besser handhabbar und flexibler.

    Würg. Das ist definitiv nicht flexibler, und ob es in irgendeiner Hinsicht handhabbarer ist, ist auch zweifelhaft. Eher umständlich, konfus und obendrein falsch.

    Wenn die Ordnungsrelation nicht dem Objekt inhärent ist, dann sollte sie nicht als op< implementiert werden.



  • Ich habe nicht vom operator< gesprochen sondern sowas wie von CStoll gemeint, falls es das ist was dich stört.



  • Braunstein schrieb:

    Ich habe nicht vom operator< gesprochen sondern sowas wie von CStoll gemeint, falls es das ist was dich stört.

    Ah, ja. Sorry.



  • danke für eure antworten.

    wenn ich es mit der sort funktion und dem comparator mache bekomme ich eine komische fehlermeldung.(siehe unten)

    danke + lg
    michi

    #include <iostream>
    #include <vector>
    #include "name.cpp"
    #include <algorithm>
    using namespace std;
    
    class liste{
    	private:
    	vector <name> vec;
    	public:
    void hinzufuegen(name &a){
    		vec.push_back(a); 
    }
    
    void ausgabe(){
    		cout << vec.size();
    		for(unsigned int i=0;i< vec.size();i++){
    			cout << "--------------------------------------------\n";
    			cout << "vorname: " << vec[i].getVorname() << endl;
    			cout << "nachname: " << vec[i].getNachname()<< endl;
    			cout << "alter: " << vec[i].getAlter() << endl;
    			}
    			cout << "--------------------------------------------\n";
    }
    
    bool comp(const name& l, const name& r) { return l.getVorname()<r.getVorname(); } 
    
    void sortiere(){
    	std::sort(vec.begin(), vec.end(), comp);
    	}
    };
    
    int main(){
    liste l1;
    cout << "Instanzen Sotierer v.1.02" << endl;
    name n1("Thorsten","Schmied",26);
    name n2("Martin","Pauer",23);
    name n3("Hubert","Mueller",24);
    
    l1.hinzufuegen(n1);
    l1.hinzufuegen(n2);
    l1.hinzufuegen(n3);
    l1.ausgabe();
    l1.sortiere();
    
    return 0;
    }
    
    g++ -c -pipe -Wall -W -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic  -DQT_NO_DEBUG -DQT_SHARED -DQT_THREAD_SUPPORT -I/usr/lib64/qt-3.3/mkspecs/default -I. -I. -I/usr/lib64/qt-3.3/include -o Isortiere.o Isortiere.cpp
    Isortiere.cpp: In member function »bool liste::comp(const name&, const name&)«:
    Isortiere.cpp:28: Fehler: Die Übergabe von »const name« als »this«-Argument von »const std::string name::getVorname()« streicht Qualifizierer
    Isortiere.cpp:28: Fehler: Die Übergabe von »const name« als »this«-Argument von »const std::string name::getVorname()« streicht Qualifizierer
    Isortiere.cpp: In member function »void liste::sortiere()«:
    Isortiere.cpp:32: Fehler: Argument des Typs »bool (liste::)(const name&, const name&)« passt nicht zu »bool (liste::*)(const name&, const name&)«
    /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algo.h: In function »void std::partial_sort(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<name*, std::vector<name, std::allocator<name> > >, _Compare = bool (liste::*)(const name&, const name&)]«:
    /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algo.h:2666:   instantiated from »void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<name*, std::vector<name, std::allocator<name> > >, _Size = long int, _Compare = bool (liste::*)(const name&, const name&)]«
    /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algo.h:2749:   instantiated from »void std::sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<name*, std::vector<name, std::allocator<name> > >, _Compare = bool (liste::*)(const name&, const name&)]«
    Isortiere.cpp:32:   instantiated from here
    /usr/lib/gcc/x86_64-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_algo.h:2477: Fehler: ».*« oder »->*« muss verwendet werden, um Zeiger auf Element in »__comp (...)« aufzurufen
    


  • getVorname ist nicht const.

    .cpp-Dateien sollte man nicht inkludieren (was sage ich... werden nie (!) inkludiert).



  • wenn ich get Vorname auf const setzte erhalte ich immer noch eine

    Fehlermeldung:

    Isortiere.cpp: In member function »void liste::sortiere()«:
    Isortiere.cpp:32: Fehler: Argument des Typs »bool (liste::)(const name&, const name&)« passt nicht zu »bool (liste::*)(const name&, const name&)«
    


  • Das ist das Problem mit Methodenzeigern - sie können nicht wie normale Zeiger verwendet werden. (auch wenn's nicht so aussieht - comp() erwartet drei Argumente - von denen das erste ( list* this ) nicht von sort bereitgestellt wird)

    Die Lösung ist ganz einfach - deklariere die Funktion comp() als statische Methode oder nimm sie ganz aus der Klasse liste heraus (die Vergleichsfunktion gehört sowieso eher zur name- als zur liste-Klasse).



  • danke für deine Hilfe CStoll.
    Daran ist es gelegen.

    lg
    michi



  • Hallo! Kann mir das jemand erklären wie das funktioniert: eigenen Operator erstellen. Hab nämlich gelesen das das eigentlich gar nicht gehen dürfte um so mehr interessiert es mich wie das ganze funktioniert. Könnte mir jemand das ganze Schritt für schritt erklären.

    MFG THE_ONE



  • Erstens hat das wenig mit dem Threadtitel zu tun.
    Zweitens: wenn ich mich richtig an vorhergehende Threads darber erinnere, ist das, wie du selbst sagst, nicht möglich. (bin mir jetzt nicht 100% sicher, ob nicht dich einer eine Möglichkeit gefunden hatte)



  • @One: Neue Operatoren erstellen kannst du nicht. Aber du kannst die vorhandenen Operatoren für deine eigenen Klassen überladen, indem du eine Funktion mit dem Namen "operator x" (für 'x' setzt du den Operator ein, den du anpassen willst) anlegst - mit einigen Ausnahmen kannst du sogar frei entschreiden, ob du das als globale Funktion oder Klassenmethode (dabei wird der erste Operand als *this übergeben) definieren willst.


Anmelden zum Antworten