Hashtabelle/Double Hashing



  • Floeee schrieb:

    und dann die remove Funktion dafür aufrufe, sagt mir Member immer noch, dass es vorhanden ist, obwohl der Status auf 0 gesetzt wird und ich nur true return wenn dieser auf 1 ist.

    Ich kann den betroffenen Quelltext nicht nachvollziehen. Was soll er tun? Was mit spontan dazu einfällt: Du hast ein break . Das beendet eine Schleife aber bei der nächstunteren geht's trotzdem weiter. Vielleich return; um die Funktion zu verlassen.

    Floeee schrieb:

    Und einen Fehler habe ich noch, allerdings ist es eher ne Warning, das angeblich meine Funktion nextprimzahl ans Ende kommt ohne einen Wert zu returnen, nur komm ich einfach nicht drauf warum? Sollte doch alles passen.

    Nein. Was geschiet, wenn a grösser als endzahl ist und isprimzahl(a) bisher noch nie 1 zurückgegeben hat?

    PS: In C++ gibt es den Datentyp bool . Statt einem int , der du nur auf 0 und 1 setzt, könntest du einen bool mit true und false nutzen. Ein int lässt sich auch implizit wunderbar in einen bool konvertieren. 0 wird zu false und alles andere wird zu true .



  • Ich verstehe nur nicht, wie a größer als endzahl werden soll, aber du hast recht, dann gäbe es ein Problem 😕

    ad member/remove Funktionen:

    bool DHash<E>::member( const E& e ) const {
      unsigned int hashtemp = hashValue(e) % nmax;   
      unsigned int tmax = nmax; 
      for (size_t j = hashtemp; j < tmax; ++j) {
        if (values[j].daten == e && values[j].status == 1) return true;
        if (j == nmax -1){
           j = 0;
           tmax = hashtemp;
        }
      }
      return false;
    }
    

    In der Member Funktion übergebe ich einen Wert um zu sehen, ob dieser vorhanden ist. Dabei berechne ich mittels Hashfunktion einen temporären Hashwert, an dessen Stelle sich der Wert befinden soll. Es kann aber auch sein, dass es schon Kollisionen gab und er weitergerückt ist, also such ich ab der Stelle hashtemp nach meinem Wert bis ich ans Ende stosse (von da an, fange ich wieder von vorne an und suche bis zu der Stelle wo ich begonnen habe).
    Die gesuchten Daten können aber auch vorhanden sein, aber zu einem früheren Zeitpunkt gelöscht worden sein. Dann wird der status auf 0 gesetzt und sollte nicht mehr gefunden werden.

    template <typename E>
    void DHash<E>::remove( const E e[], size_t s ) {
         for (size_t i = 0; i < s; ++i) {
             for (size_t j = 0; j < n; ++j) {
                 if (values[j].daten == e[i] && values[j].status == 1 ) {
                    values[j].status = 0;
                    break;
                 }
             }
         }
    }
    

    Hier suche ich einfach das array von vorne bis hinten durch und das so oft, wie mir zu löschende Objekte übergeben wurden (erste for Schleife). In der zweiten wird dann das array durchgegangen und immer geschaut ob die daten übereinstimmen und sie laut dem status noch aktuell sind, wenn ich sie gefunden habe, dann lösche ich indem ich status auf 0 setze und break.

    Das war meine Überlegung, ich versteh nicht wieso das nicht funktioniert.

    *edit* Das mit bool ist mir bewusst, allerdings hatte ich anfangs irgendwann mal Schwierigkeiten (habe vor 2 Wochen damit begonnen) und hatte dann mal int eingeführt um was auszuprobieren und nicht mehr geändert. bool ist sicher eleganter, aber für mein Beispiel sollte es int doch auch tun oder? Ich werde es aber mit Sicherheit noch ändern, wenn ich einmal alles implementiert habe und die Performance Überarbeitung kommt. Danke!



  • EOutOfResources schrieb:

    EDIT: Den DTor solltest du aber schon definieren, siehe "Regel der Grossen Drei".

    Da hast du jetzt selbst was nicht verstanden.



  • naja bisher gabs keine probs beim testen ^^

    ich verzweifel nur langsam an meiner remove funktion, oder der fehler liegt am member
    aaaahh wieviel zeit das kostet ...



  • Warst du schon beim Debugger?



  • was meinst du mit debugger?

    *edit*
    hier noch einmal meine 2 Funktionen

    template <typename E>
    void DHash<E>::remove( const E e[], size_t s ) {
         for (size_t i = 0; i < s; ++i) {
             for (size_t j = 0; j < nmax; ++j) {
                 if (values[j].daten == e[i] && values[j].status == 1 ) {
                    values[j].status = 0;
                    break;
                 }
             }
         }
    }
    
    template <typename E>
    bool DHash<E>::member( const E& e ) const {
      unsigned int hashtemp = hashValue(e) % nmax;   
      unsigned int tmax = nmax; 
      for (size_t j = hashtemp; j < tmax; ++j) {
        if (values[j].daten == e && values[j].status == 1) {
           return true;
        }
        if (j == nmax -1){
           j = 0;
           tmax = hashtemp;
        }
      }
      return false;
    }
    


  • ok ich bin nun soweit zu sagen, dass es an der if bedingung in meiner remove funktion liegt. aber wieso ?!?!?!?

    meine size funktion die für die rückgabe der aktuell enthaltenen zahl gespeicherter daten zuständig ist. returnt immer 0, wie kann das denn funktionieren? ist ja nirgends mit 0 gesetzt.

    virtual size_t size( ) const { return n; }
    


  • Floeee schrieb:

    ok ich bin nun soweit zu sagen, dass es an der if bedingung in meiner remove funktion liegt. aber wieso ?!?!?!?

    Wie äußert sich denn der Fehler?

    meine size funktion die für die rückgabe der aktuell enthaltenen zahl gespeicherter daten zuständig ist. returnt immer 0, wie kann das denn funktionieren? ist ja nirgends mit 0 gesetzt.

    virtual size_t size( ) const { return n; }
    

    Hast du n denn überhaupt auf einen Wert gesetzt?



  • natürlich hab ich nen wert für n
    sieht code erste seite, konstruktor und es erhöht sich auch wenn ich daten adde in meinem testprogramm, nur gibt er immer 0 aus

    bzgl. meiner if bedingung, wenn ich ein item remove, dann seh ich nach ob die stelle ein item enthält (values[j].status == 1) und wenn da was is, schau ich obs das richtige ist (values[j].daten == e[i]) und dann stze ich den status auf 3 um zu signalisieren, dass es gelöscht wurde



  • Floeee schrieb:

    natürlich hab ich nen wert für n
    sieht code erste seite, konstruktor und es erhöht sich auch wenn ich daten adde in meinem testprogramm, nur gibt er immer 0 aus

    In dem Code da oben liefert size() auch noch den Wert 0, also könnte es durchaus sein, daß du (a) noch immer diese Variante verwendest oder (b) noch mehr am Code geändert hast (eventuell in der add()-Methode die Variable überdeckt.

    bzgl. meiner if bedingung, wenn ich ein item remove, dann seh ich nach ob die stelle ein item enthält (values[j].status == 1) und wenn da was is, schau ich obs das richtige ist (values[j].daten == e[i]) und dann stze ich den status auf 3 um zu signalisieren, dass es gelöscht wurde

    Erstens: Und wo liegt jetzt das Problem?
    Zweitens: Wo kommt denn jetzt die 3 her?
    Drittens: Warum verwendest du nicht deine Hash-Funktion, um den vermutlichen Aufenthaltsort des zu löschenden Elements zu bestimmen?



  • ad if bedingung:
    1. das problem liegt daran, dass ich nie in die if bedingung rein komme und er nie die status flag neu setzt und n verkleinert
    2. die 3 ist sehr wichtig, da ich dann für die spätere korrekte implementierung meiner hashfunktion wissen muss, dass es nicht nur leer ist sondern dass da auch mal was gelöscht wurde (0=leer, 1=gesetzt, 3=wurde gelöscht)
    3. ich verwende die nicht, weil ich erst einmal eine ganz primitive schleife testen wollte um mein element zu finden und zu löschen, sprich: es soll nur mal funktionieren

    ad size:
    in dem code von anfangs, habe ich einfach bei der size funktion "return n;" inline dazugefügt, was ja reichen sollte. und ich teste ja die tabelle immer wieder, da funktioniert n hervorragend wenn ich daten adde. ist immer die aktuelle zahl...

    ps: soll ich nochmal den aktuellen code posten?



  • Floeee schrieb:

    ad if bedingung:
    1. das problem liegt daran, dass ich nie in die if bedingung rein komme und er nie die status flag neu setzt und n verkleinert
    2. die 3 ist sehr wichtig, da ich dann für die spätere korrekte implementierung meiner hashfunktion wissen muss, dass es nicht nur leer ist sondern dass da auch mal was gelöscht wurde (0=leer, 1=gesetzt, 3=wurde gelöscht)
    3. ich verwende die nicht, weil ich erst einmal eine ganz primitive schleife testen wollte um mein element zu finden und zu löschen, sprich: es soll nur mal funktionieren

    Vielleicht solltest du erst mal versuchen, ob du ein einzelnes Element finden und löschen kannst. Die Schleife zum Gruppen-Löschen kannst du später daraum bauen.

    1. Hast du dir mal schrittweise im Debugger angesehen, was dort tatsächlich passiert? Vielleicht kommt der Wert ja bloß nicht in der Hash-Tabelle vor.
    2. Dort oben setzt du den Status aber nicht auf 3, sondern auf 0 😉

    ad size:
    in dem code von anfangs, habe ich einfach bei der size funktion "return n;" inline dazugefügt, was ja reichen sollte. und ich teste ja die tabelle immer wieder, da funktioniert n hervorragend wenn ich daten adde. ist immer die aktuelle zahl...

    Bist du ganz sicher, daß du durchgängig das selbe Objekt verwendest?



  • CStoll schrieb:

    Vielleicht solltest du erst mal versuchen, ob du ein einzelnes Element finden und löschen kannst. Die Schleife zum Gruppen-Löschen kannst du später daraum bauen.

    Ich versuceh ja die ganze Zeit nur ein Element zu adden und zu löschen mit meinem testprogramm und gebe mir dabei natürlich das array immer aus.

    1. Hast du dir mal schrittweise im Debugger angesehen, was dort tatsächlich passiert? Vielleicht kommt der Wert ja bloß nicht in der Hash-Tabelle vor.

    Ich habe keinerlei Erfahrung mit dem Debugger, wie muss ich da vorgehen?

    2. Dort oben setzt du den Status aber nicht auf 3, sondern auf 0 😉

    Das ist wie gesagt noch der alte Code.

    Bist du ganz sicher, daß du durchgängig das selbe Objekt verwendest?

    Was meinst du damit? Mein n wird in der Hauptklasse DHash als variable gespeichert und die size Funktion ist ebenfalls in der DHash Klasse. Wenn ich da n return, dann muss doch auch n zurückkommen, warum kommt da auf einmal nur noch 0, aber n ist 1 oder 2 oder je nachdem wieviel geaddet ist. Hier steht ja "return n", ich hab ja nix auf den Augen. Wie geht das?



  • Zum Debugger: Welche IDE verwendest du denn? Bei den meisten modernen Compilern kannst du an irgendeiner Stelle im Programm einen Breakpoint setzen und dann Schritt für Schritt jeder Anweisung ausführen lassen (und dabei auch live beobachten, wie sich die Variablenwerte ändern).

    Ansonsten denke ich, es wäre eine gute Idee, wenn du mal deinen aktuellen Stand präsentierst (inklusive Hauptprogramm).



  • Also ich verwende den Bloodshe dev c++

    Und hier einmal mein momentaner Stand:

    #ifndef DHASH_H
    #define DHASH_H
    
    #include <iostream>
    #include "Container.h"
    
    template <typename E>
    class DHash : public Container<E> {
    
      class HashElem{
        public:
          int status;
          E daten;
          unsigned int hash;
    
          HashElem() : daten( ) { status = 0; hash = 0; }
          ~HashElem() { }
    
          void fill(const E e, unsigned int h) { hash = h; status = 1; daten = e; }
          void erase() { status = 3; }
      };
    
      HashElem * values;
      size_t nmax;
      size_t n;
      void sort() const;
    
    public:
      DHash<E>( ){ values = new HashElem[7]; n = 0; nmax = 7; }
      virtual ~DHash<E>( ) { delete[] values; }
    
      using Container<E>::add;
      virtual void add( const E e[], size_t len );
      void rehash( const E e[], size_t len);
    
      using Container<E>::remove;
      virtual void remove( const E e[], size_t s );
      virtual bool member( const E& e ) const;
      virtual size_t size( ) const { return n; }
    
      virtual size_t apply( const Functor<E>&, Order = dontcare ) const { return 0; } // not implemented
    
      virtual E min( ) const { return E(); } // not implemented
      virtual E max( ) const { return E(); } // not implemented
    
      virtual std::ostream& print( std::ostream& o ) const;
    };
    
    int isprimzahl(int zahl){
         int a = 2;
         while (a < zahl){
               if (zahl % a == 0){
                  return 0;
               }            
                a++;   
         }
         return 1;          
    }
    
    int nextprimzahl(int zahl){
         int a = zahl+1;
         int endzahl = zahl + zahl;
         while (a < endzahl){
               if (isprimzahl(a) == 1){             
                  return a;    
               }  
               else{
                   endzahl++;      
               }   
               a++;
         }
    }
    
    template <typename E>
    void DHash<E>::add( const E e[], size_t len ) {
         unsigned int hashtemp = 0;     
         size_t newnmax = nmax;     
         size_t tmax;
         HashElem *a;
      if ((n + len) > ((newnmax) * 0.7)) {
        HashElem * newvalues;
        do{
        newnmax = nextprimzahl(newnmax);
        }while(newnmax < ((n+len)*10));
        newvalues = new HashElem[newnmax];
        for (size_t i = 0; i < nmax; ++i){
            if(values[i].status == 1){
                hashtemp = values[i].hash % newnmax;
                if (newvalues[hashtemp].status == 0){ 
                   newvalues[hashtemp].fill(values[i].daten,values[i].hash);
                }
                else{
                    tmax = newnmax;
                    for( size_t j = (hashtemp+1); j < tmax; ++j){
                        if(newvalues[j].status == 0){ 
                            newvalues[j].fill(values[i].daten,values[i].hash);
                            j = j + newnmax;
                        }
                        if (j == newnmax -1){
                           j = 0;
                           tmax = hashtemp;
                        }
                    }         
                }
            }
        }
        delete[] values;
        values = newvalues;
        nmax = newnmax;
      }
      for ( size_t i = 0; i < len; ++i ){
        if (!member( e[i] )){
           hashtemp = hashValue(e[i]) % nmax; 
           a = &values[hashtemp];        
           if(a->status == 0){
               values[hashtemp].fill(e[i],hashValue(e[i]));
               n++;
           }else{
                for( size_t j = hashtemp % nmax; j < nmax; ++j){
                    a = &values[j];   
                    if(a->status == 0){ 
                        values[j].fill(e[i],hashValue(e[i]));
                        j = j + nmax;
                        n++;
                    }
                }    
           }       
        }
      } 
    }
    
    template <typename E>
    void DHash<E>::remove( const E e[], size_t s ) {
         for (size_t i = 0; i < s; ++i) {
             for (size_t j = 0; j < nmax; ++j) {
                 if ( values[j].status == 1 && values[j].daten == e[i] ) {
                    values[j].status = 3;
                    --n;
                    break;
                 }
             }
         }
    }
    
    template <typename E>
    bool DHash<E>::member( const E& e ) const {
      unsigned int hashtemp = hashValue(e) % nmax;   
      unsigned int tmax = nmax; 
      for (size_t j = hashtemp; j < tmax; ++j) {
        if (values[j].status == 1 && values[j].daten == e ) {
           return true;
        }
        if (j == nmax -1){
           j = 0;
           tmax = hashtemp;
        }
      }
      return false;
    }
    
    template <typename E>
    std::ostream& DHash<E>::print( std::ostream& o ) const {
      HashElem *p;
      o << "DHash [ n=" << n << " nmax=" << nmax << " values=" ;
      for (size_t i = 0; i < nmax; ++i) {
          p = &values[i];
          o << ' ' << p->daten;
          p = 0;
      }
      o << " ]";
      return o;
    }
    
    #endif //DHASH_H
    

    Das hier ist der vorgegeben Container aus dem meine Klasse abgeleitet werden soll (man sieht, dass noch die Funktionen max(),min() und apply() fehlen):

    #ifndef CONTAINER_H
     #define CONTAINER_H
    
     #include <iostream>
     #include <string>
    
     enum Order { dontcare, ascending, descending };
     template <typename E> class Functor;
    
     template <typename E>
     class Container {
       Container<E>& operator=( const Container<E>& );
       Container<E>( const Container<E>& );
     public:
       class Exception;
    
       Container<E>( ) { }
       virtual ~Container<E>( ) { }
    
       virtual void add( const E& e ) { add( &e, 1 ); }
       virtual void add( const E e[], size_t s ) = 0;
    
       virtual void remove( const E& e ) { remove( &e, 1 ); }
       virtual void remove( const E e[], size_t s ) = 0;
    
       virtual bool member( const E& e ) const = 0;
       virtual size_t size( ) const = 0;
       virtual bool empty( ) const { return size( ) == 0; }
    
       virtual size_t apply( const Functor<E>& f, Order order = dontcare ) const = 0;
    
       virtual E min( ) const = 0;
       virtual E max( ) const = 0;
    
       virtual std::ostream& print( std::ostream& o ) const = 0;
     };
    
     template <typename E>
     inline std::ostream& operator<<( std::ostream& o, const Container<E>& c ) { return c.print( o ); }
    
     template <typename E>
     class Container<E>::Exception : public std::exception {
       std::string msg;
     public:
       explicit Exception( const std::string& msg ) throw() : msg( msg ) {}
       virtual ~Exception() throw() {}
       virtual const char * what() const throw() { return msg.c_str(); }
     };
    
     template <typename E>
     class Functor {
     public:
       virtual bool operator( )( const E& e ) const = 0;
       virtual ~Functor( ) {}
     };
    
     template <typename E> inline unsigned long hashValue( const E& e ) { return (unsigned long) e * 47114711; }
     template <typename E> inline double doubleValue( const E& e ) { return double( e ); }
     template <typename E> inline unsigned long ordinalValue( const E& e ) { return (unsigned long) e; }
    
     #endif //CONTAINER_H
    

    Nun noch mein Testprogramm, das wird auch als Vorgabe bekommen haben, denn es ist eine weitaus simplere Version von dem Programm, mit dem es getestet wird. Kenn mich beim Testprogramm nicht überall aus muss ich gestehen, aber bisher tat es was es sollte.

    // simpletest.C
     // Simples Testprogramm zur Ueberpruefung der Container-Funktionalitaet
     // Die Zeichenfolge CONTAINERTYPE ist in der ganzen Datei durch den Klassennamen 
     // der Datenstruktur zu ersetzen.
     // 
     // Der Elementdatentyp kann mit Compileroption -DETYPE=<typ> festgelegt werden,
     // also zb -DETYPE=std::string
    
     #include <iostream>
     #include <sstream>
     #include <fstream>
     #include <string>
     #include <cstring>
     #include <cstdlib>
     #include <cctype>
     #include "DHash.h"
    
     #ifndef ETYPE
     #define ETYPE int
     #endif
    
     const char helpstr[] = 
       "new ............................... create new Container\n"
       "delete ............................ delete Container\n"
       "add <key> [...] ................... add <key>(s) with Container::add( int )\n"
       "remove <key> [...] ................ remove <key>(s) with Container::remove( int )\n"
       "member <key> ...................... call Container::member( <key> )\n"
       "size .............................. call Container::size()\n"
       "empty ............................. call Container::empty()\n"
       "min ............................... call Container::min()\n"
       "max ............................... call Container::max()\n"
       "print ............................. print container with operator<<()\n"
       "apply [asc|desc|dontcare [<n>]] ... traverse container with PrintN functor\n"
       "trace ............................. toggle tracing on/off\n"
       "fadd <filename> ................... add values read from file <filename>\n"
       "fremove <filename> ................ remove values read from file <filename>\n"
       "radd [<n> [<seed>]] ............... add <n> random values, optionally reset generator to <seed>\n"
       "rremove [<n> [<seed>]] ............ remove <n> random values, optionally reset generator to <seed>\n"
       "quit .............................. quit program\n\n"
       "arguments surrounded by [] are optional\n";
    
     template <typename E>
     class PrintN : public Functor<E> {
       std::ostream& o;
       mutable int n;
     public:
       explicit PrintN( int n = 0, std::ostream& o = std::cout ) : o( o ), n( n ) { }
       explicit PrintN( std::ostream& o ) : o( o ), n( 0 ) { }
       bool operator()( const E& e ) const {
         o << e << ' ';
         return n <= 0 || --n;
       }
     };
    
     void setrandom( int seed ) { srand( seed ); }
     template <typename E> E nextrandom( ) { return E( rand( ) ); }
    
     // Template-Spezialisierungen fuer Klasse std::string
    
     template <> inline double doubleValue( const std::string& e ) { double rc = 0.; for (size_t i = e.length(); i--; ) rc /= 256., rc += e[i]; return rc; }
     template <> inline unsigned long hashValue( const std::string& e ) { unsigned long rc = 0; for (size_t i = 0; i < e.length(); ++i) rc = rc * 13 + e[i]; return rc; }
     template <> inline unsigned long ordinalValue( const std::string& ) { return 0; }
     template <> std::string nextrandom( ) {
       const char* start = helpstr + rand() % sizeof helpstr;
       while (!isalpha( *start )) if (*start) ++start; else start = helpstr;
       const char* end = start + 1;
       while (isalpha( *end )) ++end;
       return std::string( start, end - start );
     }
    
     // Klasse Person mit allen für die Verwendung als Container-Elementdatentyp noetigen Methoden und Funktionen
    
     class Person {
       std::string vorname;
       std::string nachname;
     public:
       Person() { }
       Person( std::string vorname, std::string nachname ) : vorname( vorname ), nachname( nachname ) { }
       bool operator==( const Person& p ) const { return vorname == p.vorname && nachname == p.nachname; }
       bool operator>( const Person& p ) const { return nachname > p.nachname || (nachname == p.nachname && vorname > p.vorname); }
    
       std::ostream& print( std::ostream& o ) const { return o << '[' << nachname << ", " << vorname << ']'; }
       std::istream& read( std::istream& i ) { return i >> vorname >> nachname; }
       friend double doubleValue<Person>( const Person& e );
       friend unsigned long hashValue<Person>( const Person& e );
       friend unsigned long ordinalValue<Person>( const Person& e );
     };
    
     inline std::ostream& operator<<( std::ostream& o, const Person& p ) { return p.print( o ); }
     inline std::istream& operator>>( std::istream& i, Person& p ) { return p.read( i ); }
    
     // Template-Spezialisierungen fuer Klasse Person
    
     template <> inline double doubleValue( const Person& e ) { return doubleValue( e.nachname ); }
     template <> inline unsigned long hashValue( const Person& e ) { return hashValue( e.nachname ); }
     template <> inline unsigned long ordinalValue( const Person& ) { return 0; }
     template <> Person nextrandom( ) { 
       return Person( nextrandom<std::string>(), nextrandom<std::string>() );
     }
    
     bool match( const std::string& s, const char * c ) {
       return c && s.length() <= std::strlen( c ) && s.compare( 0, s.length(), c, s.length() ) == 0;
     }
    
     int main() {
    
       Container<ETYPE>* c = 0;
       bool traceIt = false;
       std::cout.setf( std::ios_base::boolalpha );
    
       while (true) {
         if (traceIt) {
           if (c) {
             std::cout << std::endl << "container: " << *c;
           } else {
             std::cout << std::endl << "no container";
           }
         }
         std::cout << std::endl << "> ";
    
         std::string cmdline;
         if (!std::getline( std::cin, cmdline )) break;
    
         std::istringstream cmdstream( cmdline );
         std::string cmd;
    
         cmdstream >> cmd;
    
         try {
           if (cmd.length() == 0) {
           } else if (match( cmd, "quit" )) {
             break;
           } else if (match( cmd, "new" )) {
             if (c) {
               std::cerr << "container exists, 'delete' it first";
             } else {
               std::string typ;
               cmdstream >> typ;
               if (match( typ, "DHash" ))
                 c = new DHash<ETYPE>;
               else
                 std::cout << "unknown container type " << typ;
             }
           } else if (match( cmd, "help" ) || cmd == "?") {
             std::cout << helpstr;
           } else if (match( cmd, "trace" )) {
             std::cout << "trace " << ((traceIt = !traceIt) ? "on" : "off");
           } else if (!c) {
             std::cout << "no container (use 'new')";
           } else {
             ETYPE key;
             if (match( cmd, "delete" )) {
               delete c;
               c = 0;
             } else if (match( cmd, "add" )) {
               while (cmdstream >> key) { c->add( key ); }
             } else if (match( cmd, "remove" )) {
               while (cmdstream >> key) { c->remove( key ); }
             } else if (match( cmd, "member" )) {
               cmdstream >> key;
               std::cout << "returns " << c->member( key );
             } else if (match( cmd, "size" )) {
               std::cout << "returns " << c->size( );
             } else if (match( cmd, "empty" )) {
               std::cout << "returns " << c->empty( );
             } else if (match( cmd, "min" )) {
               std::cout << "returns " << c->min( );
             } else if (match( cmd, "max" )) {
               std::cout << "returns " << c->max( );
             } else if (match( cmd, "print" )) {
               std::cout << *c;
             } else if (match( cmd, "apply" )) {
               int n = 0;
               std::string order = "dontcare";
               cmdstream >> order >> n;
               size_t rc = c->apply( PrintN<ETYPE>( n ), match( order, "ascending" ) ? ascending : match( order, "descending" ) ? descending : dontcare );
               std::cout << "\nreturns " << rc;
             } else if (match( cmd, "fadd" )) {
               std::string filename;
               cmdstream >> filename;
               std::ifstream keystream( filename.c_str() );
               while (keystream >> key) { c->add( key ); }
             } else if (match( cmd, "fremove" )) {
               std::string filename;
               cmdstream >> filename;
               std::ifstream keystream( filename.c_str() );
               while (keystream >> key) { c->remove( key ); }
             } else if (match( cmd, "radd" )) {
               int seed = -1, count = 1;
               cmdstream >> count >> seed;
               if (seed != -1) setrandom( seed );
               while (count-- > 0) c->add( nextrandom<ETYPE>() );
             } else if (match( cmd, "rremove" )) {
               int seed = -1, count = 1;
               cmdstream >> count >> seed;
               if (seed != -1) setrandom( seed );
               while (count-- > 0) c->remove( nextrandom<ETYPE>() );
             } else {
               std::cout << cmd << "? try 'help'";
             }
           }
         } catch (Container<ETYPE>::Exception& e) {
           std::cout << "Container::Exception " << e.what();
         } catch (std::exception& e) {
           std::cout << "Exception " << e.what();
         } catch (...) {
           std::cout << "OOPS!";
         }
       }
       return 0;
     }
    


  • Erstmal kannst du für ETYPE ein typedef nutzen. Bei typedef wird das Scope beachtet und ob es sich bei dem Bezeichner überhaupt um einen Typ handelt. Dann solltest du statt C-Strings viel lieber einen std::string nutzen. Und statt PrintN implementierst du einen Left-Shift-Operator. Die Sache mit cmdstream kapiere ich nicht so ganz. Was nutzt das? Und ich finde, dass du deinen Einrückungsstil überdenken sollst. Ich finde deinen jetztigen absolut unleserlich.

    PS: Dev-C++ ist die wahrscheinlich schlechteste IDE die es gibt. Nimm lieber ein VC++ Express oder Code::Blocks.



  • Also wie bereits geschrieben ist das Testprogramm nicht von mir und ich habe ehrlich gesagt nicht viel von dem verstanden was du nun wolltest, dass ich ändere. Auch der Container ist eine Vorgabe und ich kann/sollte auch an den Programmen nichts verändern, da sie den "Abgabetest" simulieren.

    Im Moment geht es einzig und allein um meine remove Funktion, besser gesagt um meine if Bedingung darin, in die ich nicht hinein komme. Da dürfte etwas mit meinen Vergleichen nicht stimmen. Die Frage ist nur was.

    template <typename E>
    void DHash<E>::remove( const E e[], size_t s ) {
         for (size_t i = 0; i < s; ++i) {
             for (size_t j = 0; j < nmax; ++j) {
                 if ( values[j].status == 1 && values[j].daten == e[i] ) {
                    values[j].status = 3;
                    --n;
                    break;
                 }
             }
         }
    }
    

    Ich werde mich einmal nach einer andren IDE umsehen. Sollte halt schon Freeware sein.



  • Visual C++ 2010 Express ist kostenlos!



  • Hab mir das nun mal installiert, aber intuitiver find ich den Bloodshed schon ein wenig, ich glaub jedoch, dass der VC++ etwas praktikabler sein wird.
    Für mein jetziges Projekt reicht der Bloodshed mit Sicherheit einmal.

    Das sollte aber auch gar nicht Thema sein, sondern eher meine remove Funktion.

    Hat denn niemand eine Idee was da an meiner if Bedingung nicht stimmt??



  • Visual Studio hat einen guten Debugger. Setz einen Breakpoint und schau was passiert.


Anmelden zum Antworten