簡體   English   中英

編譯器不會在單鏈表的遞歸逆轉中前進

[英]compiler won't advance in recursive reversal of singly linked list

我在SinglyLinkedList類中有一個遞歸靜態方法,由於不確定的原因,該方法永遠運行。 此類是通用的,其聲明如下所示:

public class SinglyLinkedList<E>{

該類具有一個內部通用類Node ,它看起來像這樣:

private static class Node<E> {
    private E element;
    private Node<E> next;

    public Node(E e, Node<E> n) {
        this.element = e;
        this.next = n;
    }

    public E getElement() {
        return this.element;
    }

    public Node<E> getNext() {
        return this.next;
    }

    public void setNext(Node<E> n) {
        this.next = n;
    }
}

此外, SinglyLinkedList類具有以下字段:

private Node<E> head = null;

private Node<E> tail = null;

private int size = 0;

我遇到麻煩的方法稱為reverse ,其目的是以遞歸的方式反向單鏈表的順序。 這是此方法的代碼:

public static SinglyLinkedList reverse(SinglyLinkedList l) {
    if (l.size < 2) return l;
    Node first = l.removeFirstNode();
    SinglyLinkedList reversed = reverse(l);
    reversed.addLast(first);
    return reversed;
}

reverse方法使用一種稱為removeFirstNode的非靜態方法,其目的是刪除單鏈列表中的第一個Node並返回它:

private Node<E> removeFirstNode() {
    if (isEmpty()) return null;
    //Node<E> answer = new Node<>(this.head.getElement(), null);
    Node<E> answer = this.head;
    this.head = this.head.getNext();
    this.size--;
    if (this.size == 0) this.tail = null;
    return answer;
}

reverse方法還使用稱為addLast的非靜態方法,其目的是將給定的Node添加到單鏈表的末尾:

private void addLast(Node<E> n) {
    if (isEmpty()) this.head = n;
    else this.tail.setNext(n);
    this.tail = n;
    this.size++;
}

問題是,當我嘗試在size等於2的SinglyLinkedList上運行reverse方法時,編譯器進入該行

reversed.addLast(first);

然后在addLast方法中,它在行上停止

this.tail = n;

並且永遠運行而不會終止。 如果size等於或大於3,則編譯器進入該行

reversed.addLast(first);

甚至不輸入addLast方法就停在那里。 現在如果我更換線

Node<E> answer = this.head;

與當前已注釋掉的行

Node<E> answer = new Node<>(this.head.getElement(), null);

reverse方法將終止,沒有任何問題。 誰能解釋這是怎么回事?

編輯:我剛剛意識到size 3或更大的不同行為僅僅是遞歸的產物。 真正的問題在於size等於2且方法莫名其妙地在行終止的情況

this.tail = n;

編輯2:

最小代碼:

public class SinglyLinkedList<E>{

private static class Node<E> {
    private E element;
    private Node<E> next;

    public Node(E e, Node<E> n) {
        this.element = e;
        this.next = n;
    }

    public E getElement() {
        return this.element;
    }

    public Node<E> getNext() {
        return this.next;
    }

    public void setNext(Node<E> n) {
        this.next = n;
    }
}

private Node<E> head = null;

private Node<E> tail = null;

private int size = 0;

public SinglyLinkedList() {}

public int size() { return this.size; }

public boolean isEmpty() {
    return this.size == 0;
}

public void addLast(E e) {
    Node<E> newest = new Node<>(e, null);
    if (isEmpty())
        this.head = newest;
    else
        this.tail.setNext(newest);
    this.tail = newest;
    this.size++;
}

@Override
public String toString() {
    String output = "";
    if (this.size > 0) {
        Node<E> current_node = head;
        while (current_node != null) {
            output += current_node.getElement();
            if (current_node != tail) output += ", ";
            else output += "\n";
            current_node = current_node.getNext();
        }
    }
    return output;
}

private void addLast(Node<E> n) {
    if (isEmpty()) this.head = n;
    else this.tail.setNext(n);
    this.tail = n;
    this.size++;
}

private Node<E> removeFirstNode() {
    if (isEmpty()) return null;
    //Node<E> answer = new Node<>(this.head.getElement(), null);
    Node<E> answer = this.head;
    this.head = this.head.getNext();
    this.size--;
    if (this.size == 0) this.tail = null;
    return answer;
}

public static SinglyLinkedList reverse(SinglyLinkedList l) {
    if (l.size < 2) return l;
    Node first = l.removeFirstNode();
    SinglyLinkedList reversed = reverse(l);
    reversed.addLast(first);
    return reversed;
}}

測試類別:

public static void main(String[] args) {
    int n = 4;
    SinglyLinkedList<Integer> list = new SinglyLinkedList<>();
    for (int i = 1; i <= n; i++) list.addLast(i);
    System.out.print(list);
    System.out.print(SinglyLinkedList.reverse(list));
}

removeFirstNode()實現不會取消鏈接該節點的下一個指針。

在原始鏈表中,第一個節點的下一個點指向第二個節點,第二個節點的下一個指針為null。

在新列表中,第一個節點的下一個指針將指向第二個節點,但是第二個節點的下一個指針將指向第一個節點(以前是第二個節點)。

這樣的東西(原始列表):

+---+    +---+
| A |--->| B |--->null
+---+    +---+

由於A的下一個指針仍然指向B,因此重新排序成為了這種情況:

+---+    +---+
| B |--->| A |---+
+---+    +---+   |
  ^              |
  |              |
  +--------------+

您可以將removeFirstNode()實現更改為以下形式:

    private Node<E> removeFirstNode() {
        if (isEmpty()) return null;
        Node<E> answer = this.head;
        this.head = this.head.getNext();
        answer.next = null; // Set next ptr to null
        this.size--;
        if (this.size == 0) {
            this.tail = null;
        }
        return answer;
    }

該代碼可能看起來像“停止”,因為調試器嘗試使用toString()來打印出列表,我想它會遍歷列表並且由於循環而無法完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM