Hashtabelle/Double Hashing



  • Hallo alle zusammen, dies ist mein erster Post in diesem Forum und bestimmt nicht der letzte, da ich nun auch zu den lieben Programmierern gestossen bin. Ich studiere Medieninformatik und aufgrund meiner ersteren größeren Programmierarbeit an der Uni, stellen sich mir nun ein paar Fragen. Vielleicht kann mir ja der ein oder andere weiterhelfen.

    Also wie der Titel schon sagt, erstelle ich eine Hashtabelle mittels Double Hashing Verfahren und allem was dazugehört. Das ganze soll auf einer vorgegebenen Klasse "Container" basieren, die von unserem Professor vorgeschrieben wurde.

    Zuerst poste ich einmal was ich bisher habe. Da ich leider noch keine so große Arbeit programmiert habe, hat sich bei mir das Kommentieren der einzelnen Zeilen noch nicht durchgesetzt. Was ich definitiv bei folgenden Arbeiten anders machen werde.

    #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() { status = 0; hash = 0; const E daten = 0; }
          ~HashElem() { /*delete[] daten;*/ }
    
          void fill(const E e, unsigned int h) { hash = h; status = 1; daten = e; }
          //void erase() { status = 0; }
      };
    
      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 0; } // not implemented
    
      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 < n; ++j) {
                 if (values[j].daten == e[i] && &values[j]->status == 1 ) {
                    &values[j]->status = 0;
                    //values[j].erase();
                    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;
    }
    
    /*
    template <typename E>
    E ContDynArrayV3<E>::min( ) const {
      if (this->empty()) throw typename ContainerV3<E>::Exception( "ContDynArrayV3::min(): empty container" );
      E rc = values[0];
      for (size_t i = 1; i < n; ++i) {
        if (rc > values[i]) rc = values[i];
      }
      return rc;
    }
    
    template <typename E>
    E ContDynArrayV3<E>::max( ) const {
      if (this->empty()) throw typename ContainerV3<E>::Exception( "ContDynArrayV3::max(): empty container" );
      E rc = values[0];
      for (size_t i = 1; i < n; ++i) {
        if (values[i] > rc) rc = values[i];
      }
      return rc;
    }
    */
    
    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;
    }
    
    /*template <typename E>
    std::ostream& DHash<E>::print( std::ostream& o ) const {
      HashElem *p;
      E * q;
      o << "DHash [ n=" << n << " nmax=" << nmax << " values=" << "\n";
      for (size_t i = 0; i < nmax; ++i) {
       p = &values[i];
       o << ' ' << p->daten << " -stat " << p->status << " -hash " << p->hash <<" -pos " << i << "\n";
       p = 0;}
      o << " ]";
      return o;
    
      }*/
    
    #endif //DHASH_H
    

    Folgende Errors bekomme ich:
    In file included from CONTAINERTYPE.h:1,
    from testcfull.C:32:
    DHash.h: In constructor ‘DHash<E>::HashElem::HashElem() [with E = TestKey]’:
    DHash.h:41: instantiated from ‘DHash<E>::DHash() [with E = TestKey]’
    testcfull.C:948: instantiated from here
    DHash.h:28: error: conversion from ‘int’ to non-scalar type ‘const TestKey’ requested
    DHash.h: In member function ‘void DHash<E>::remove(const E*, size_t) [with E = TestKey]’:
    testcfull.C:1206: instantiated from here
    DHash.h:150: error: base operand of ‘->’ has non-pointer type ‘DHash<TestKey>::HashElem’
    DHash.h:151: error: base operand of ‘->’ has non-pointer type ‘DHash<TestKey>::HashElem’
    DHash.h: In member function ‘bool DHash<E>::member(const E&) const [with E = TestKey]’:
    testcfull.C:1206: instantiated from here
    DHash.h:164: error: base operand of ‘->’ has non-pointer type ‘DHash<TestKey>::HashElem’

    Ich weiss, dass ich mit &values[j]->status = 0 nicht einfach die Variable verändern kann, da muss ich wohl erst noch eine Funktion schreiben die das immer 0 setzt. allerdings müsste ich doch mit values[j]->status == 0 die Variable vergleichen können oder nicht?

    Allerdings mein bisher größtes Problem ist der Konstruktor meiner Hilfsklasse HashElem in der ich die Daten dann im Endeffeckt schreibe. Von dieser Klasse werden dann Objekte mit den Daten und Zusatzinformationen in meiner Hashtabelle gespeichert. Wie muss ich denn im Konstruktor

    HashElem() { status = 0; hash = 0; const E daten = 0; }
    

    die Variable daten initialisieren, damit es wegen dem template nicht meckert? Da ich nicht weiss was für ein Datentyp da kommen wird, kann ich es ja nicht einfach 0 setzen. Habt ihr da eine Idee?
    Muss ich dann im Destruktor

    ~HashElem() { delete[] daten; }
    

    überhaupt einen Destruktor definieren, oder kann ich diesen auch einfach mit leerer Funktion stehen lassen?

    Ich hoffe mal ich überforder da niemanden mit diesen Fragen und danke gleich einmal im voraus für jegliche Hilfe.



  • Du kannst ja einfach den Default-Konstruktor für die Member mit Template-Parameter-Abhängigem Typ aufrufen ➡ Initialisierungsliste
    Und wenn du im Konstruktor nicht mit new oder new[] allokierst, musst du im Destruktor auch nicht freigeben, das tut schon RAII für dich.
    EDIT: Den DTor solltest du aber schon definieren, siehe "Regel der Grossen Drei".



  • Erst einmal ein WOW und danke für die schnelle Antwort.
    Leider bin ich wie gesagt noch ziemlich am Anfang mit C++ und habe die Antwort nicht ganz verstanden 😕
    Was ist Initialisierungsliste und wie rufe ich den Default Konstruktor für mein E auf? Was ist DTor und diese Regel ? (sicher einige Fettnäpfchen dabei ^^)
    Das mit dem Destruktor habe ich kapiert danke!

    PS: Eine Frage hat sich noch aufgetan:
    Wieso kann ich in den Zeilen 139, 140, 153 nicht mittels values[j]->status == 1 nicht vergleichen? Das & gehört da weg, aber ich will ja auf den status von dem Objekt das in meinem values array an der Stelle j sitzt einfach vergleichen ob das 1 is oder nicht. Also ob der Platz belegt ist oder nicht. Geht das nur mittels einer extra Funktion in der Klasse HasElem die ich dann einfach getStatus oder so nenne?

    *edit* ich weiss nun, dass ich das vergleichen mit values[j].status == 1 machen muss, aber was war noch einmal der unterschied zwischen dem pfeil und dem punkt?

    pps: Meine vielen Fragen haben den Grund, dass ich das ganze nicht nur zum laufen bekommen will, sondern ich will es auch verstehen, ich hoffe ich gehe niemandem auf den Keks.



  • Floeee schrieb:

    Was ist Initialisierungslist

    struct foo
    {
      int a;
      foo(int val)
      : a(val)  //<- Initialisierungsliste
      {
      }
    };
    

    Floeee schrieb:

    wie rufe ich den Default Konstruktor für mein E auf?

    In der Regel wird der von C++ selbst aufgerufen. Bei eingebauten Typen (z.B. int oder char ) ist das nicht definiert. Du kannst das jedoch erzwingen indem du die Member in der Initialisierungsliste erwähnst (einfach ohne Parameter).

    Floeee schrieb:

    Was ist DTor und diese Regel?

    DTor = Destruktor und die Regel findest du im deutschen Wikipedia: Hier.



  • Floeee schrieb:

    was war noch einmal der unterschied zwischen dem pfeil und dem punkt?

    struct MeineKleineKlasse
    {
      int a;
    };
    MeineKleineKlasse Instanz;
    Instanz.a = 5; //Kein Zeiger also Zugriff auf Member über .-Operator
    MeineKleineKlasse* Zeiger = &Instanz;
    Zeiger->a = 5; //Zeiger also Zugriff auf Member über ->-Operator
    

    Alternativ zum -> -Operator könnte man auch das schreiben:

    (*Zeiger).a = 5;
    


  • Also per Pointer mit Pfeil und ohne dann mit Punkte. Vielen Dank!

    Nach dreimaligem Durchdenken, hab ich das mit der Initialisierungsliste glaub ich verstanden, aber leider nicht ganz die Erklärung wann es nötig ist mit dieser zu arbeiten und wann ich aber das alles auch einfach in die Klammern schreiben kann.

    Macht es dann einen Unterschied ob ich die anderen Variablen auch so initialisiere oder diese dann in die Klammer schreibe?

    Da ich in HashElem weder mit Pointer noch mit dynamischen Daten arbeite, reicht es da nicht aus den DTor nur zu definieren aber nichts reinzuschreiben? Wenn nicht, was muss ich explizit löschen? delete funktioniert doch nur mit new angelegten Daten oder?

    Also wenn ich das ganze so initialisiere
    HashElem() : daten( 0 ) { status = 0; hash = 0; }
    dann bekomme ich nur noch nen Error:

    In file included from CONTAINERTYPE.h:1,
    from testcfull.C:32:
    testcfull.C: In constructor ‘DHash<E>::HashElem::HashElem() [with E = TestKey]’:
    DHash.h:29: instantiated from ‘DHash<E>::DHash() [with E = TestKey]’
    testcfull.C:948: instantiated from here
    testcfull.C:72: error: ‘TestKey::TestKey(long unsigned int)’ is private
    DHash.h:16: error: within this context

    *edit* jetzt habe ich leider noch ein kleines Problem gefunden (wird bestimmt nicht das letzte sein :D), wo ich nicht genau weiss ob es an meiner member oder remove Funktion liegt. Denn wenn ich mit meinem Testprogramm ein Element adde, 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. 😕 😕



  • Floeee schrieb:

    wann es nötig ist mit dieser zu arbeiten und wann ich aber das alles auch einfach in die Klammern schreiben kann

    Mit Klammern meinst du wahrscheinlich den Anweisungsblock. Du weist ja, dass man Konstanten nichts zuweisen kann, sie aber trotzdem initialisieren muss.

    struct foo
    {
      const int a;
      foo(int wert)
      {
        a = wert; //Fehler
      }
      foo(int wert)
      : a(wert)   //Korrekt
      {
      }
    };
    

    Das selbe bei Referenzen.

    Floeee schrieb:

    Macht es dann einen Unterschied ob ich die anderen Variablen auch so initialisiere oder diese dann in die Klammer schreibe?

    Nein.

    Floeee schrieb:

    reicht es da nicht aus den DTor nur zu definieren aber nichts reinzuschreiben?

    Ja.

    Floeee schrieb:

    Also wenn ich das ganze so initialisiere
    HashElem() : daten( 0 ) { status = 0; hash = 0; }
    dann bekomme ich nur noch nen Error:

    Schreibe in die Klammern nach daten nichts hinein. Wenn sie leer sind wird der Default-Konstruktor aufgerufen. Bei deiner Methode wird versucht, ein Konstruktor mit einem Typ, der sich von int konvertieren lässt, aufzurufen.



  • Wahnsinn!!! Ich konnte kompilieren 😃 auch wenn noch bei weitem nicht alles implementiert ist.
    Oben habe ich noch ein edit drangehängt, aber da warst du schon so schnell mit der Antwort

    jetzt habe ich leider noch ein kleines Problem gefunden (wird bestimmt nicht das letzte sein :D), wo ich nicht genau weiss ob es an meiner member oder remove Funktion liegt. Denn wenn ich mit meinem Testprogramm ein Element adde, 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. 😕 😕

    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.

    Ich weiss es ist nicht gerade die schönste Art und Weise auf die nächste Primzahl zu kommen, aber mir fällt grad nichts besseres ein, denn ich will meine Hashtabelle immer um Primzahlengrößen erweitern, damit die Hashfunktion nicht zu oft die gleiche Zahl liefert beim einordnen und das ganze somit bisschen performanter wird.



  • 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?


Anmelden zum Antworten