Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Doppelt verkettete Liste

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
07.09.2006, 13:02 Uhr
WindDancer1



Hallo,

Vorab erst mal, ich weiss dass es zig Möglichkeiten gibt verkettete Listen zu bauen, selbstverständlich auch nur mit Klassen als Container usw. mir geht es aber hier ums Verständnis der hier benutzten Art von verketteten Listen.
Das Problem ist wahrscheinlich sehr gering aber ich dreh mich schon seit Tagen um mich selbst und find den Bug nicht!

Was Funktioniert:
1. Die Liste wird korrekt angelegt und ausgegeben auch die Anzahl der Elemente.
2. Das neue erste Element wird korrekt angelegt und die Liste wird ebenso korrekt ausgegeben auch die Anzahl der Elemente.


Was nicht funktioniert:
Das neue letzte Element wird wahrscheinlich nicht richtig angelegt und deshalb wird das letzte Element nicht ausgegeben wenn die Liste ausgegeben wird.

Wird jedoch der obere Teil in der Funktion addNewLastElement(int wert) einkommentiert,
in diesem Teil füge ich das letzte Element wie bei einer einfach verketteten Liste ein dann funktioniert alles.

Ich gehe übrigens davon aus dass sich schon ein Element in der Liste befindet (keine Plausibilitätsprüfung) da ich die Liste ja zuvor erstellt habe.
Ich hab versucht alles so gut und verständlich wie möglich zu kommentieren.

Hier der Code für die main():


C++:
#include "List.h"


void main()
{
    mvList mvListe;
    int i;
    int j = 1;
    

    cout << "Liste ist leer !!! ==> Liste mit 3 Elementen bauen" << endl;
    
    for (i = 0; i < 3; i++)
    {
        mvListe.addElement(j++);
    }
    mvListe.showElements();
    

    cout << "Neues Erstes Element einfuegen" << endl;
    mvListe.addElement(5, FIRST);
    mvListe.showElements();
    
    
    cout << "Neues letztes Element einfuegen" << endl;
    mvListe.addElement(10, LAST);
    mvListe.showElements();
    
}




Hier der Code für die List.h:


C++:
#include <iostream>
using namespace std;

enum { NONE = 0,FIRST, LAST, MIDDLE };

class mvList
{
private:

//*************************************** SRTUCT ERSTELLEN *************************************
    struct Listenknoten
    {
        int data;
        Listenknoten *next;
        Listenknoten *prev;
    };

public:
//******************************* ZEIGER AUF STRUCT ERSTELLLEN *********************************
    Listenknoten *neu;
    Listenknoten *head;
    Listenknoten *tail;
    Listenknoten *current1;
    Listenknoten *current2;
    int              counterElements;

//********************************** KONSTRUKTOR / DESTRUKTOR **********************************
    mvList()
    {
        neu                =    NULL; // Zeiger mit Null initialisieren
        head            =    NULL; // Zeiger mit Null initialisieren
        tail            =    NULL; // Zeiger mit Null initialisieren
        current1        =    NULL; // Zeiger mit Null initialisieren
        current2        =    NULL; // Zeiger mit Null initialisieren
        counterElements =    0;
    }

    ~mvList()
    {
        neu                =    NULL; // Zeiger mit Null initialisieren
        head            =    NULL; // Zeiger mit Null initialisieren
        tail            =    NULL; // Zeiger mit Null initialisieren
        current1        =    NULL; // Zeiger mit Null initialisieren
        current2        =    NULL; // Zeiger mit Null initialisieren

        delete neu;            
        delete head;            
        delete tail;            
        delete current1;        
        delete current2;            
    }


//******************************* PROTOS DER MEMBERFUNKTIONEN **********************************
    void showElements();
    
    void addElement(int wert, int , int);
    void addNewFirstElement(int wert);
    void addNewLastElement(int wert);
    void addNewMiddleElement(int wert, int atPosition);
};


//**********************************************************************************************
//******************************* ENTSCHEIDUNG FUNKTIONAUFRUFE *********************************

void mvList::addElement(int wert, int atPos = NONE, int pos = 0)
{
    if (atPos != NONE)
    {
        switch(atPos)
        {
        case FIRST:    addNewFirstElement(wert);
            break;
        case LAST:    addNewLastElement(wert);
            break;
        default:
            break;
        }
    }else
    {
        addNewFirstElement(wert);
    }
}
//**********************************************************************************************
//****************************** NEUES ERSTES ELEMENT EINFÜGEN *********************************

void mvList::addNewFirstElement(int wert)
{
    neu = new Listenknoten;

    neu->prev = NULL;
    neu->next = head;
    head = neu;

    neu->data = wert;

    counterElements++;
    cout << "Elemente: "  << counterElements;
}


//**********************************************************************************************
//************************* NEUES LETZTES ELEMENT EINFUEGEN INSERT AFTER ***********************

void mvList::addNewLastElement(int wert)
{

    neu = new Listenknoten;            
//
//
//     current1 = head;                    // einkommentieren
//     while (current1->next != NULL)        // einkommentieren
//     {                                    // einkommentieren
//         current1 = current1->next;        // einkommentieren
//     }                                    // einkommentieren
//     neu->next = NULL;                    // einkommentieren
//                                         // einkommentieren
//     current1->next = neu;                // einkommentieren
//                                        // einkommentieren
//     neu->data = wert;                    // einkommentieren    
    
    

    neu->next = NULL;                    // auskommentieren    
    neu->prev = tail;                    // auskommentieren
    
    tail = neu;                            // auskommentieren

    neu->data = wert;                    // auskommentieren
    
    counterElements++;
    cout << "Elemente: " << counterElements;
}


//**********************************************************************************************
//************************************** ELEMENTE ANZEIGEN *************************************

void mvList::showElements()
{
    int counter = 1;
    current1 = head;
    while (current1 != NULL )
    {
        cout << "\nWert an Position " << counter++ << " = " << current1->data;
        current1 = current1->next;
    }
    cout << endl << endl << endl;
    if(head == NULL)
    {
        cout << "\nKeine Elemente in der Liste !!!" << endl << endl;
    }
    
}




vielen vielen Dank für eure Mühe
WinDDancer
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
07.09.2006, 13:37 Uhr
ao

(Operator)


Der Fehler ist:
Du lässt zwar tail auf den neuen Knoten zeigen, hängst diesen aber nicht in die Next-Verkettung der Liste ein. Das heißt: Die verkettete Liste, also das Gebilde, was an head dranhängt, wird nicht verändert, und der Pointer tail zeigt danach auf ein Objekt, das nur halb in der Liste hängt (sein prev-Zeiger zeigt zwar auf den Vorgänger, aber prev->next zeigt nicht auf das Objekt selber.

C++:
    neu->next = NULL;  // Ende-Zeichen, OK
    neu->prev = tail;    // Rückwärtsverkettung zum Vorgänger, OK
    
    neu->prev->next = neu; // das hier fehlt: Vorwärtsverkettung vom Vorgänger!

    tail = neu;

    neu->data = wert;



Übrigens ist da noch ein Speicherleck; die Liste wird nicht wieder abgeräumt.

Und "neu" sollte kein Member der Klasse sein, sondern eine lokale Variable in den Add-Funktionen, weil es nur hier gebraucht wird. Dasselbe gilt für die "current"-Member; Laufvariablen deklariert man lokal, wenn sie gebraucht werden. Ich sehe keinen Grund, warum die Klasse sich diese Werte dauerhaft merken sollte.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
07.09.2006, 14:07 Uhr
WindDancer1



Danke ao für die schnelle Hilfe,

aber wenn ich neu->prev->next = neu; in meinen Source einfüge bekomme ich folgene Fehlermeldung:

Die Anweisung in "0x00403219" verweist auf Speicher in "0x00000004". Der Vorgang
"written" konnte nicht auf dem Speicher durchgeführt werden.


ShadowEater
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
07.09.2006, 15:03 Uhr
ao

(Operator)


Kann es sein, dass tail zuvor auf NULL zeigt? Ich war davon ausgegangen, dass die Liste schon Elemente enthält und dass tail auf das letzte zeigt.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
07.09.2006, 15:10 Uhr
WindDancer1



Hi ao,

nö eigentlich nicht, ich erstell ja die Lisze , dann füge ich ein neues Element ein und dann erst kommt das Einfügen des neuen letzeten Elementes.

ShadowEater
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
07.09.2006, 16:04 Uhr
Blubber2063



Überleg dir mal was du da machst, du erzeugst ein neues Element, gehst dann auf den Vorgänger der noch nicht existiert, weil noch nicht zugewiesen und greifst dann auf ein nicht existierendes Element next zu.

Du solltest das so machen.

neues Element kriegt als Vorgänger das Endelement zugewiesen und dann weist du dem Endelement als Nachfolger das neu zu und jetzt überschreibst du Endelemtzeiger mit Neuelementzeiger.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
07.09.2006, 16:07 Uhr
ao

(Operator)



Zitat von Blubber2063:
neues Element kriegt als Vorgänger das Endelement zugewiesen und dann weist du dem Endelement als Nachfolger das neu zu und jetzt überschreibst du Endelemtzeiger mit Neuelementzeiger.

So hab ichs doch vorgeschlagen. Vorausgesetzt, tail hat vorher auf was Gültiges gezeigt, müsste das so gehen. Oder doch nicht?

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
07.09.2006, 16:08 Uhr
Blubber2063



Ups hab ich nicht gesehen, das du das schon geschrieben hast . Wüsste nicht wie man es anders besser lösen sollte.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
08.09.2006, 11:14 Uhr
0xdeadbeef
Gott
(Operator)



C++:
void main()


main ist immer int.


C++:
    ~mvList()
    {
        neu                =    NULL; // Zeiger mit Null initialisieren
        head            =    NULL; // Zeiger mit Null initialisieren
        tail            =    NULL; // Zeiger mit Null initialisieren
        current1        =    NULL; // Zeiger mit Null initialisieren
        current2        =    NULL; // Zeiger mit Null initialisieren

        delete neu;            
        delete head;            
        delete tail;            
        delete current1;        
        delete current2;            
    }


Das gibt Speicherlecks. Davon ab sollten die current-Zeiger keine Klassenvariablen sein, sondern lokal in den Funktionen, die sie benutzen, deklariert werden. So wies jetzt aussieht, hast du ein paar mal delete NULL;, was nichts tut, und selbst wenn du die "Initialisierungen" da weg nimmst, löschst du mit current1 zumindest, wenn showElements einmal aufgerufen wurde, tail zweimal.

Ansonsten musst du ein bisschen aufpassen, dass du nicht irgendwelche Pointer vernachlässigst, zum Beispiel

C++:
void mvList::addNewFirstElement(int wert)
{
    neu = new Listenknoten;

    neu->prev = NULL;
    neu->next = head;
    head->prev = neu;
    head = neu;

    neu->data = wert;

    counterElements++;
    cout << "Elemente: "  << counterElements;
}


bzw.

C++:
void mvList::addNewLastElement(int wert)
{

    neu = new Listenknoten;            

    neu->next = NULL;
    neu->prev = tail;
    tail->next = neu;
    tail = neu;

    neu->data = wert;
    
    counterElements++;
    cout << "Elemente: " << counterElements;
}


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: