简体   繁体   中英

Reversing a Doubly-Linked-List

Hey I'm currently stuck on the reverse method of my DoublyLinkedList. Everything is working fine (somehow) except for the reverse method. I'm not receiving any errors - System.out.println(list.reverse()) simply has no output.

Any suggestions? Thank you very much in advance. :)

Okay: I have edited my code now. So far everyhing is working correctly. However, the recursive method simply prints the list in the same order, instead of actually reversing it.

Updated Code:

public class DoublyLinkedStringList {

private String content;
private DoublyLinkedStringList prev;
private DoublyLinkedStringList next;

public DoublyLinkedStringList(String info) {
    content = info;
    prev = null;
    next = null;
}

private DoublyLinkedStringList(String content, DoublyLinkedStringList prev, DoublyLinkedStringList next) {
    this.content = content;
    this.prev = prev;
    this.next = next;
}

public DoublyLinkedStringList prepend(String info) {
    DoublyLinkedStringList newNode = new DoublyLinkedStringList(info);
    prev = newNode;
    newNode.next = this;

    return newNode;
}

public DoublyLinkedStringList delete(int index) {
    DoublyLinkedStringList curr = this;

    if (index == 0) {
        next.prev = null;
        return next;
    }

    for (int i = 0; i < index; i++) {
        curr = curr.next;
    }

    curr.prev.next = curr.next;
    if (curr.prev.next != null) {              
        curr.prev.next.prev = curr.prev;
    }
    return this;
}

public DoublyLinkedStringList reverse() {
    DoublyLinkedStringList currNode = this;

    while (currNode != null) {
        DoublyLinkedStringList temp = currNode.next;
        currNode.next = currNode.prev;
        currNode.prev = temp;

        if (currNode.prev != null) {
            currNode = currNode.prev;
        }
    }

    return this;
}

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();

    for (DoublyLinkedStringList currNode = this; currNode != null; currNode = currNode.next) {
        sb.append(currNode.content);
        if (currNode.next != null) {
            sb.append(", ");
        }
    }
    return sb.toString();
}

public static void main(String argv[]) {
    DoublyLinkedStringList list = new DoublyLinkedStringList("Testliste");
    list = list.prepend("6");
    list = list.prepend("5");
    list = list.prepend("4");
    list = list.prepend("3");
    list = list.prepend("2");
    list = list.prepend("1");
    list = list.prepend("0");

    list = list.delete(1);
    System.out.println(list);

    list = list.reverse();
    System.out.println(list);
}

}

One of the problems you are going to have with your design is when you reverse the list the head becomes the tail and the tail becomes the head. But the client is pointing to the head, and not the tail. Even if you did this operation 100% correct, you can't change the reference the client has. What you'll want to do is separate the concepts of the List as an object, and the Nodes that make up that object (currently you have combined these two concepts together because the nodes are the list and vice versa). By separating them the reference to the list is always the same regardless of what's in it, order, etc. The List contains the head and tail references, and the nodes only contain the next/prev. Right now you have head and tail in every node in your list which can make nasty bugs pop up if you don't replace every reference whenever head/tail changes (ie prepend, delete, or reverse). If you moved those two instances out of each node then you don't have to do as much maintenance to the list on changes. I think if you do that then you'll find it much easier to implement reverse.

Your error is exactly the problem I'm saying. At the end you return this, well the reference the client has was the head (ie this). However, after iterating over and reversing everything what was the head is now the tail so you've returned the new tail by returning this. And toString() on tail is NOTHING.

Normally I would implement the interface Iteratable and use an Iterator to reverse the list but I kept my revision in line with your current model. I changed the return types of the Node 's getNext() and getPrev() methods to be dependent on the forward variable. Now the list never changes linkage when "reversed" but it is traversed in reverse order via the variable getNext() and getPrev() behavior.

IDEONE link to code

Consider this edit:

class DoublyLinkedStringList {

private Node head, tail;
boolean forward;

/**
 * Diese Klasse repraesentiert einen Knoten in der Doubly Linked List der
 * Klasse
 * <code>DoublyLinkedStringList</code>
 *
 */
private class Node {
    private String content;
    private Node next;
    private Node prev;

    public Node(String content) { this.content = content; }

    public Node(String content, Node next) {
        this.content = content;
        if(forward) { this.next = next; }                     //EDITED
        else        { this.prev = next; }                     //EDITED
    }

    public Node getNext() { return (forward) ? next : prev; } //EDITED
    public Node getPrev() { return (forward) ? prev : next; } //EDITED

    public void setNext(Node next) {
        if(forward) { this.next = next; }                     //EDITED
        else        { this.prev = next; }                     //EDITED
    }

    public void setPrev(Node prev) {
        if(forward) { this.prev = prev; }                     //EDITED
        else        { this.next = prev; }                     //EDITED
    }
}

public DoublyLinkedStringList() {
    this.head = null;
    this.tail = null;
}

public Node prepend(String info) {
    Node newNode = new Node(info);
    newNode.setPrev(null);
    newNode.setNext(getHead());
    if(newNode.getNext()!=null) { 
      newNode.getNext().setPrev(newNode);                     //EDITED
    } 
    if(forward) { head = newNode; }                           //EDITED
    else        { tail = newNode; }                           //EDITED
    if(getTail() == null) {                                   //EDITED
      if(forward) { tail = newNode; }                         //EDITED
      else        { head = newNode; }                         //EDITED
    }
    return head;
}

public Node delete(int index) {
    Node currNode = getHead();
    int count = 0;

    if (index == 0) {
        if(forward) { head = head.next; }                     //EDITED
        else        { tail = tail.prev; }                     //EDITED
        return head;
    }

    while (currNode != null) {
        if (count + 1 == index) {
            currNode.next.prev = currNode.prev; 
            currNode.prev.next = currNode.next;               //EDITED
            break;
        }
        currNode = currNode.getNext();                        //EDITED
        count++;
    }
    return currNode;
}

private Node next() {
    Node currNode = head;

    if (forward) {
        return currNode.getNext();
    } else {
        return currNode.getPrev();
    }
}

public Node getHead() { return (forward) ? head : tail; }     //EDITED
public Node getTail() { return (forward) ? tail : head; }     //EDITED
public DoublyLinkedStringList reverse() { forward = !forward; return this; }

@Override
public String toString() {
    StringBuilder sb = new StringBuilder();
    //EDITED LOOP STRUCTURE
    for (Node currNode = getHead(); currNode != null; currNode = currNode.getNext()) {
        sb.append(currNode.content);
        if (currNode.getNext() != null) {
            sb.append(", ");
        }
    }
    return sb.toString();
}

public static void main(String argv[]) {
    DoublyLinkedStringList list = new DoublyLinkedStringList();
    list.prepend("6");
    list.prepend("5");
    list.prepend("4");
    list.prepend("3");
    list.prepend("2");
    list.prepend("1");
    list.prepend("0");
    list.delete(3);
    System.out.println(list);
    System.out.println(list.reverse());
}
}

you simply have to set head and tail too. then it should work. but see chubbsondubs answer for further improvement!

Since you have a DoublyLinkedStringList as return type, I think you want to return a new object. In this case I suggest you to cycle over your object and build a new List using the prepend method you already implemented (that anycase has some other error). You can start with a empty list, and, as you scan the original object, prepend current element.

Otherwise, if you want to reverse the list "in place" you should return void , change the head with the last element, and, since is double linked, your should do anything else, since there are pointers to nodes in both directions.

try this for the reverse method:

public class DoublyLinkedList {
  Node first, current;
  boolean forward;
      //constructors... methods...

  private Node next() {
        if(forward) return current.next();
        else return current.previous();
  }

  public void reverse() {
    while(true) {
          if(next() == null) {
        first = current;
        forward = !forward;
        return;
      }
      current = next(); 
    }
  }
}

Here is just my solution. I unfortunately do not have more time for explanatory notes.

public class DoublyLinkedStringList {
    private String info;
    private DoublyLinkedStringList prev;
    private DoublyLinkedStringList next;

public DoublyLinkedStringList(String pInfo)
{
    info = pInfo;
    prev = null;
    next = null;
}

private DoublyLinkedStringList(String pInfo, DoublyLinkedStringList pPrev, DoublyLinkedStringList pNext)
{
    info = pInfo;
    prev = pPrev;
    next = pNext;
}

public DoublyLinkedStringList prepend(String info)
{
    DoublyLinkedStringList n = new DoublyLinkedStringList(info);
    prev = n;
    n.next = this;

    return n;
}

public DoublyLinkedStringList delete(int index)
{   
    if (index == 0)
    {
        next.prev = null;
        return next;
    }

    DoublyLinkedStringList d = this;

    for (int i = 0; i<index; i++)
        d = d.next;

    // d is now the node which should be deleted

    // after delete(x) "next" schould be on pos x

    d.prev.next = d.next;   // take the next of the prev and set the new next to the next of d

    if (d.prev.next != null)    // if the next of d was not set to null, it must get to know his new prev (d's prev)
        d.prev.next.prev = d.prev;

    return this;
}


public DoublyLinkedStringList reverse() // moe or less less similar to my implementation in IntList.java
{
    DoublyLinkedStringList oldLast = getLast();
    next.reverse(this);
    prev = next;
    next = null;
    return oldLast;
}

public void reverse(DoublyLinkedStringList last)
{
    if (next != null)
        next.reverse(this);
    prev = next;
    next = last;
}

public DoublyLinkedStringList getLast()
{
    if (next == null)
        return this;
    return next.getLast();
}

@Override
public String toString()
{
    String r = "";

    for (DoublyLinkedStringList i = this; i != null; i = i.next)
    {
        r += i.info;
        if (i.next != null)
            r += ", ";
    }
    return r;
}

public String reverseToString() // uses prev; just for testing issues :)
{
    String r = "";

    for (DoublyLinkedStringList i = getLast(); i != null; i = i.prev)
    {
        r += i.info;
        if (i.prev != null)
            r += ", ";
    }
    return r;
}

public static void main(String argv[])
{
    DoublyLinkedStringList list = new DoublyLinkedStringList("Test");
    list = list.prepend("6");
    list = list.prepend("5");
    list = list.prepend("4");
    list = list.prepend("3");
    list = list.prepend("2");
    list = list.prepend("1");
    list = list.prepend("0");
    list = list.delete(1);
    System.out.println(list);
    System.out.println(list.reverseToString()+"\n");

    list = list.reverse();
    System.out.println(list);
    System.out.println(list.reverseToString());

    list = list.delete(6);
    list = list.delete(0);
    System.out.println(list);
    list = list.reverse();
    list = list.prepend("1");
    System.out.println(list);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM