Verständnisproblem verkettete Listen



  • Hallo Leute,

    ich hab echt ein Problem!
    Hab mir grad Volkards tut durchgearbeitet!

    Und ich hab echt ein Problem, verkettete Listen zu verstehen!

    Kann das hier vielleicht mal jemand GANZ genau und auch für DAUs erklären??

    Mit guten Beispieln und so?? Blick das irgendwie echt nicht!



  • Was GENAU verstehst du nicht? Stell konkrete Fragen!

    Ansonsten: STFW und du findest z.B. http://de.wikipedia.org/wiki/Verkettete_Liste



  • Na zum Beispiel, wie die Klassen aufgebaut sein müssen!

    Ich weiß net, hab mir das schon durchgelesen, und das prinzip versteh ich auch, aber bei der praktischen anwendung haperts!

    Vielleicht könnt ihr mal ein erklärtes beispiel geben?



  • zum beispil interessiert mich auch wie ich auf spezielle elemente zugreifen kann!
    Daten ausgeben etc...



  • boahnee schrieb:

    zum beispil interessiert mich auch wie ich auf spezielle elemente zugreifen kann!
    Daten ausgeben etc...

    Indem du dich stückweise durch die Liste durchhangelst (vom Start weg immer dem next-Zeiger folgen, bis du bei deinem Ziel angekommen bist).



  • Listen läuft man normalerweise komplett durch und macht für jedes Element etwas.



  • ok, wie gesagt, das theoretische prinzip hab ich verstanden, aber die praxis garnicht!

    Könnt ihr mir mal ein gutes beispiel geben?? 😕



  • Also, ich zeig dir jetzt einen eher simplen Ansatz, wie man eine doppelt-verkettete Liste implementieren kann:

    Das hier stellt ein Element in der Liste dar, wir machen's mal ohne Templates und nehmen eine Liste für ints. Ein Zeiger auf das nächste, einer auf das vorherige Element und natürlich die Daten:

    struct ListElement {
      ListElement(int val) : next(0), prev(0), value(val) {}
      //Copy Ctor, Dtor, Zuweisung usw.
    
      ListElement *next;  //Zeiger auf das nächste Element
      ListElement *prev;  //Zeiger auf das vorherige Element
    
      int value;
    };
    

    Jetzt kommen wir zur Liste, die ListElemente verwaltet, der Zeiger first zeigt immer auf das erste Element und der last Zeiger zeigt auf das letzte Element. Diese Zeiger allokieren keinen dynamischen Speicher, sie verweisen nur auf Elemente, um die Liste abzugrenzen. Bei dieser Liste ist das Einfügen des ersten Elements ein Spezialfall, deshalb die Bedingung in der append und prepend Methode, gleiches gilt für die removeFirst Methode. Hier ist das Löschen des letzten verbleibenden Elements ein Spezialfall. Schau's dir einfach mal an.

    class List {
      ListElement *first, *last;
      size_t size_;
    
      //Löscht alle Elemente
      void cleanup() {
        ListElement *toDie=last, *prev=0;
        while(size_) {
            prev = toDie->prev;
            delete toDie;
            toDie = prev;
            --size_;
        }
      }
    
      public:
        List() : first(0), last(0), size_(0) { }
        ~List() {
          cleanup();
        }
        //Copy Ctor und Zuweisung usw. ...
    
        const ListElement * getFirst() const { return first; };
        const ListElement * getLast() const { return last; };
    
        size_t size() const { return size_; }  //Anzahl der Elemente
        bool empty() const { return (size_) ? false : true; }  //Ist Liste leer?
        void clear() { cleanup(); }  //Alle Elemente löschen
    
        //Element anhägen
        void append(int val) {
            ListElement *elem = new ListElement(val);  //Neues Element erstellen
            if (last == 0) {  //Liste ist noch leer, d.h. wir fügen erstes Element ein
              first = last = elem;  //first und last zeigen beide auf elem
    
              //Damit klar ist, wo's losgeht und wo's aufhört ;-)
              first->prev = 0;
              last->next = 0;
            }
            else  {  //Liste nicht leer, diesmal hängen wir wirklich an
              last->next = elem;  //Altes letztes Element auf neues letztes zeigen lassen
              elem->prev = last;  //Rückwärts genauso
    
              last = elem;  //last zeigt auf neues letztes Element
            }
            ++size_;
        }
    
        //Element am Anfang einfügen
        void prepend(int val) {
            ListElement *elem = new ListElement(val);  //Neues Element erstellen
            if (first == 0) {  //Liste ist noch leer, d.h. wir fügen erstes Element ein
              first = last = elem;  //first und last zeigen beide auf elem
    
              //Damit klar ist, wo's losgeht und wo's aufhört ;-)
              first->prev = 0;
              last->next = 0;
            }
            else  {  //Liste nicht leer,
              first->prev = elem;  //Altes erstes Element auf neues erstes zeigen lassen
              elem->next = first;  //Vorwärts genauso
    
              first = elem;        //first zeigt jetzt auf neues erstes Element
            }
            ++size_;
        }
    
        //Löscht das erste Element
        void removeFirst() {
            ListElement *toDie = first;  //Erstes Element sichern
            first = first->next;  //Auf neues erstes Element zeigen
            if (first)
              first->prev = 0;
            else  //Wenn wir das einzige Element löschen --> Spezialfall
              first = last = 0;
    
            delete toDie;
            --size_;
        }
    
        //Gibt Liste auf os aus
        void print(ostream& os) {
          if(!size_)
            return;
    
          ListElement *it = first;
          for (int i=0;i<size_;++i) {
            os<<it->value<<'\n';
            it = it->next;
          }
        }
    };
    
    int main() {
      List l;
    
      //3 Elemente anhängen
      l.append(1);
      l.append(2);
      l.append(3);
    
      l.removeFirst();  //1 rausholen
    
      //1 am Anfang einfügen
      l.prepend(-1);
      l.print(cout);
      return 0;
    };
    

    Wie gesagt, ein eher spartanischer Ansatz (und ich hab mir auch nicht wirklich Mühe gegeben), aber vllt. hilft's dir ja...



  • boahnee schrieb:

    Hallo Leute,
    ich hab echt ein Problem!
    Hab mir grad Volkards tut durchgearbeitet!
    Kann das hier vielleicht mal jemand GANZ genau und auch für DAUs erklären??
    Mit guten Beispieln und so?? Blick das irgendwie echt nicht!

    Schau dir mal cbItemList aus cbccl an. Ist eine verkettete Liste
    mit Cache: http://www.sf.net/projects/cbccl .

    Du kannst Dir eine verkettete Liste wie eine Menge Briefkasten
    vorstellen, wo Dir nur der erste Briefkasten bekannt ist und Du
    den jeweils in einem Briefkasten findest, wo der nächste ist.



  • Du kannst Dir eine verkettete Liste wie eine Menge Briefkasten
    vorstellen, wo Dir nur der erste Briefkasten bekannt ist und Du
    den jeweils in einem Briefkasten findest, wo der nächste ist.

    Oder als Wurstkette. Das geht auch.


Anmelden zum Antworten