Doppelt verkettete Liste implementieren

breezy

Mitglied
Hallo zusammen,

ich habe die Aufgabe bekommen eine doppelt verkettete Liste zu implementieren.

Wir haben folgenden Code als Vorlage bekommen:

Java:
/**
 * Class representing a list of int values based on double linking
 */
public class MyDoubleLinkedList {
    /**
     * the header element of this list linking to the first and last element *
     */
    private final DEntry header;

    /** the number of elements in the list */
    private int size;

    public MyDoubleLinkedList() {
        header = new DEntry(0, null, null);
        header.next = header;
        header.previous = header;
        size = 0;
    }

    /**
     * Returns the number of elements in this list
     *
     * @return the number of elements in this list
     */
    public int size() {
        return size;
    }

    /**
     * Returns the value at the position specified
     *
     * @param position the 0 based position of the value to return
     * @return the value at the passed position, -1 if unsuccessful. This means that
     *         this implementation is not working properly if -1 is stored in the
     *         list
     */
    public int get(int position) {
        // TODO: please put your code here

        return 0;
    }

    /**
     * Returns object of type DEntry at the position specified
     *
     * @param position the 0 based position of the value to return
     * @return the object at the passed position, -1 if unsuccessful. This means
     *         that this implementation is not working properly if -1 is stored in
     *         the list
     */
    public DEntry getEntry(int position) {
        // TODO: please put your code here
        return null;
    }

    /**
     * Adds a new element into the list at the position specified
     *
     * @param position the 0 based position at which to add the passed value
     * @param value    the value to add
     * @return 0 if adding was successful, -1 if not
     */
    public int add(int position, int value) {
        // TODO: please put your code here

        if (position < 0) {
            return -1;
        }

        DEntry temp = header;

        int i = 0;

        if (position == 0) {
            temp = header;
        } else {
            while (i < position) {

                temp = temp.next;
                i++;

            }
        }

        DEntry listEntry = new DEntry(value, null, null);
        listEntry.next = temp;
        listEntry.previous = temp.previous;

        temp.previous.next = listEntry;
        temp.previous = listEntry;

        return 0;
    }

    /**
     * Removes an element at the position specified from the list
     *
     * @param position the 0 based position of the value to remove
     * @return value of the removed entry if removing was successful, -1 if not
     */
    public int remove(int position) {
        // TODO: please put your code here
        size--;
        return 0;
    }

    /**
     * Searches for the first occurrence of the passed value in the list
     *
     * @param value the value to search
     * @return the position of the value in the list, -1 if not found
     */
    public int indexOf(int value) {
        // TODO: please put your code here
        return 0;
    }

    /**
     * Prints the numbers in the list to console
     */
    public void print() {
        System.out.print("List: ");
        DEntry result = header.next;
        while (result != header) {
            System.out.print(result.data + ", ");
            result = result.next;
        }
        System.out.println();
    }

    /**
     * A single list entry for double linking.
     */
    @SuppressWarnings("unused")
    class DEntry {
        /** the data element represented by this entry */
        private final int data;

        /** reference to the previous element in the list */
        private DEntry previous;

        /** reference to the next element in the list */
        private DEntry next;

        /**
         * @param data     the data object this entry represents
         * @param previous reference to the previous element in the list
         * @param next     reference to the next element in the list
         */
        public DEntry(int data, DEntry previous, DEntry next) {
            this.data = data;
            this.previous = previous;
            this.next = next;
        }
    }
}

Ich habe bereits versucht die "add" methode zu schreiben, jedoch fügt er das Element immer ganz hinten an die Liste, nicht an Position 0, falls diese übergeben wird.

Wo liegt bei "add" mein Fehler?
 
Ich kann spontan nicht erkennen warum add den Entry am Ende anfügen sollte, aber die Zeile schmeißt sicher eine NullPointerException:
temp.previous.next = listEntry;
Im Fall temp == header, dann ist previous null und du kannst nicht auf next von null zugreifen.

Bist du dir außerdem sicher, dass while in print() nicht auf Ungleichheit mit null prüfen sollte?

Und fange um himmels Willen nicht mit add an. Erstmal brauchst du get, das kannst du dir für add auch zu Nutzen machen.

Edit: Ich sehe gerade du hast einen circle implementiert, das ist nicht der Zweck einer "normalen" doppelt verketteten Liste.
 
Zuletzt bearbeitet:
Danke für deine Antwort!

Alles, ausser was ich in add() schon verbrochen habe, war vorgegeben und soll nicht verändert werden, auch print().

Dann werde ich mich erstmal mit get() versuchen. Leider gabs nicht viel Erklärung zu der doppelt verketteten Liste, ich werde mich mit Sicherheit nochmal melden..
 
Wenn der Konstruktor auch schon vorgegeben war, dann wirst du mit der Suche mit DV-Liste nicht so viel Freude haben.
Die eigentliche DV-Liste sieht so aus:

Code:
    head    next    next    next
    ---->xxx---->xxx---->xxx---->null
null<----xxx<----xxx<----xxx<----
    prev    prev    prev    tail

Dein Konstruktor indiziert aber sowas:

Code:
         head
xx---->xx<----
xx<----xx
^|     ^|
||     ||
|v     |v
xx---->xx
xx<----xx

Das wirst du mit dem Begriff RingBuffer vermutlich eher fündig.
 
Ansonsten kann ich dir die Frage beantworten warum dein Element ans Ende gestellt wird. Überleg mal...

Angenommen du hast bereits A, B und C in die Liste eingefügt. D ist das neue Element für Stelle 0.

listEntry.next = temp;
listEntry.previous = temp.previous;

temp.previous.next = listEntry;
temp.previous = listEntry;

Das ist das was du mit den 4 Zeilen tust:

breezy.png

Wie du siehst ist D am Ende der Kette. Du musst einfach nur den head noch auf D zeigen lassen.
 
Danke für deine tolle Erklärung!!

Deshalb tuts mir umso mehr leid, dass ich die Verknüpfung einfach nicht hinbekomme...

Den header auf D zeigen lassen heisst für mich in meinem code dann soviel wie:

Java:
header.previous = listEntry;

Zumindest so oder so ähnlich...aber egal was ich mit wem Verknüpfe, wenn ich das teste mit:
list.add(0, 10);
list.add(1, 20);
list.add(0, 30);
list.print();

Ist das Ergebnis immer 10, 20, 30.
 
So, ich bins wieder. Deine Veranschaulichung hat mir sehr geholfen.

Ich bin nun soweit fast durch und alles funktioniert so wie es soll. Allein das Entfernen eines Elements an einer bestimmten Position will nicht klappen, zwar entferne ich ein Element, jedoch verliere ich immer das davor mit.

Bsp.:
Liste -> A / B / C
remove(Element 2);
Liste -> C

Ich sehe einfach nicht das Problem.

Hier jedenfalls mein Code:

Java:
public class MyDoubleLinkedList {
    /**
     * the header element of this list linking to the first and last element *
     */
    private final DEntry header;

    /** the number of elements in the list */
    private int size;

    public MyDoubleLinkedList() {
        header = new DEntry(0, null, null);
        header.next = header;
        header.previous = header;
        size = 0;
    }

    /**
     * Returns the number of elements in this list
     *
     * @return the number of elements in this list
     */
    public int size() {
        return size;
    }

    /**
     * Returns the value at the position specified
     *
     * @param position the 0 based position of the value to return
     * @return the value at the passed position, -1 if unsuccessful. This means that
     *         this implementation is not working properly if -1 is stored in the
     *         list
     */
    public int get(int position) {
        // TODO: please put your code here
        DEntry temp;
        int i = 0;

        if (position < 0 || position >= size) {
            return -1;
        } else {
            temp = header;
            while (i < position) {
                temp = temp.next;
                i++;
            }
            temp = temp.next;

        }
        return temp.data;
    }

    /**
     * Returns object of type DEntry at the position specified
     *
     * @param position the 0 based position of the value to return
     * @return the object at the passed position, -1 if unsuccessful. This means
     *         that this implementation is not working properly if -1 is stored in
     *         the list
     */
    public DEntry getEntry(int position) {
        // TODO: please put your code here
        DEntry temp;
        int i = 0;

        if (position < 0 || position >= size) {
            return null;
        } else {
            temp = header;
            while (i < position) {
                temp = temp.next;
                i++;
            }
            temp = temp.next;
        }
        return temp;
    }

    /**
     * Adds a new element into the list at the position specified
     *
     * @param position the 0 based position at which to add the passed value
     * @param value    the value to add
     * @return 0 if adding was successful, -1 if not
     */
    public int add(int position, int value) {
        // TODO: please put your code here
        DEntry listEntry = new DEntry(value, null, null);

        DEntry temp = header;
        int i = 0;

        if (position < 0 || position > size) {
            return -1;
        }

        if (position == 0) {
            temp = header;

        } else {
            while (i < position) {
                temp = temp.next;
                i++;
            }
        }

        listEntry.next = temp.next;
        listEntry.previous = temp.next;
        temp.next = listEntry;
        temp.next.previous = listEntry.next;
        size++;

        return 0;
    }

    /**
     * Removes an element at the position specified from the list
     *
     * @param position the 0 based position of the value to remove
     * @return value of the removed entry if removing was successful, -1 if not
     */
    public int remove(int position) {
        // TODO: please put your code here
        
        if(position < 0 || position >= size) {
            return -1;
        }
        
        DEntry toBeDeleted = getEntry(position);
        int dataOfDeletedNode = toBeDeleted.data;
        
        toBeDeleted.next.previous = toBeDeleted.previous;
        toBeDeleted.previous.next = toBeDeleted.next;
        
        
        size--;
        System.out.println(dataOfDeletedNode);
        return dataOfDeletedNode;
    }

    /**
     * Searches for the first occurrence of the passed value in the list
     *
     * @param value the value to search
     * @return the position of the value in the list, -1 if not found
     */
    public int indexOf(int value) {
        // TODO: please put your code here
        DEntry temp = header;
        int position = 0;
        boolean notFound = false;

        do {
            position++;
            temp = temp.next;
            if (position-1 >= size) {
                notFound = true;
                break;
            }
        } while (temp.data != value);

        if (notFound) {
            return -1;
        } else {
            return position -1;
        }
    }

    /**
     * Prints the numbers in the list to console
     */
    public void print() {
        System.out.print("List: ");
        DEntry result = header.next;
        while (result != header) {
            System.out.print(result.data + ", ");
            result = result.next;
        }
        System.out.println();
    }

    /**
     * A single list entry for double linking.
     */
    @SuppressWarnings("unused")
    class DEntry {
        /** the data element represented by this entry */
        private final int data;

        /** reference to the previous element in the list */
        private DEntry previous;

        /** reference to the next element in the list */
        private DEntry next;

        /**
         * @param data     the data object this entry represents
         * @param previous reference to the previous element in the list
         * @param next     reference to the next element in the list
         */
        public DEntry(int data, DEntry previous, DEntry next) {
            this.data = data;
            this.previous = previous;
            this.next = next;
        }
    }
}
 
Allein das Entfernen eines Elements an einer bestimmten Position will nicht klappen, zwar entferne ich ein Element, jedoch verliere ich immer das davor mit.

Bsp.:
Liste -> A / B / C
remove(Element 2);
Liste -> C

Kann ich nicht nachvollziehen, das scheint doch richtig. Bei A-B-C ist C an Position 2 und das gibst du doch aus oder nicht?
 

Zurück
Oben