简体   繁体   English

扭转双重链接列表

[英]Reversing a Doubly-Linked-List

Hey I'm currently stuck on the reverse method of my DoublyLinkedList. 嘿,我目前停留在我的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. 我没有收到任何错误 - System.out.println(list.reverse())根本没有输出。

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. 即使您执行此操作100%更正,也无法更改客户端的引用。 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). 你要做的是将List的概念分离为一个对象,以及构成该对象的节点(目前你已将这两个概念结合在一起,因为节点是列表,反之亦然)。 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. 通过分离它们,列表的引用始终是相同的,无论其中包含什么,顺序等。列表包含头部和尾部引用,并且节点仅包含下一个/ 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. 并且尾部的toString()是没有的。

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. 通常我会实现Iteratable接口并使用Iterator来反转列表,但我保持我的修订符合您当前的模型。 I changed the return types of the Node 's getNext() and getPrev() methods to be dependent on the forward variable. 我将NodegetNext()getPrev()方法的返回类型更改为依赖于forward变量。 Now the list never changes linkage when "reversed" but it is traversed in reverse order via the variable getNext() and getPrev() behavior. 现在,列表在“反转”时永远不会更改链接,但是通过变量getNext()getPrev()行为以相反的顺序遍历。

IDEONE link to code IDEONE链接到代码

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! 但看到chubbsondubs答案进一步改进!

Since you have a DoublyLinkedStringList as return type, I think you want to return a new object. 由于你有一个DoublyLinkedStringList作为返回类型,我想你想要返回一个对象。 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). 在这种情况下,我建议你使用你已经实现的prepend方法遍历你的对象并构建一个新的List(任何一个都有一些其他的错误)。 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. 否则,如果你想“反转”列表,你应该返回void ,用最后一个元素改变头部,并且,由于是双链接的,你应该做任何其他事情,因为在两个方向都有指向节点的指针。

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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