当前位置: 首页 > 知识库问答 >
问题:

为什么我的toString()方法没有在命令提示符下打印我的LinkedList?

勾通
2023-03-14

我正在尝试实现一个带有头和尾引用的单链表。为了测试我的脚本,我创建了一个toString()方法,它能够打印出列表中的每个节点。但是,每次调用该方法时,我似乎都进入了一个无限循环,我似乎无法弄清楚为什么。有人能给我一些关于这一点的见解吗?请参阅下面的SinglyLinkedList.java文件。

import java.util.NoSuchElementException;
import java.util.*;

/**
 * Your implementation of a Singly-Linked List.
 */
public class SinglyLinkedList<T> {
    
    /*
     * Do not add new instance variables or modify existing ones.
     */
    private SinglyLinkedListNode<T> head;
        private SinglyLinkedListNode<T> tail;
        private int size;
    
    /*
     * Do not add a constructor.
     */

    /**
     * Adds the element to the front of the list.
     *
     * Method should run in O(1) time.
     *
     * @param data the data to add to the front of the list
     * @throws java.lang.IllegalArgumentException if data is null
     */
        public void addToFront(T data) {
        if (data == null){
            throw new IllegalArgumentException("Data cannot be null");
        }
            SinglyLinkedListNode<T> newNode = new SinglyLinkedListNode<T>(data);
        if (head == null){
            head = newNode;
            tail = newNode;
        }
        newNode.setNext(head);
        head = newNode;
        size++;
        }

    /**
     * Adds the element to the back of the list.
     *
     * Method should run in O(1) time.
     *
     * @param data the data to add to the back of the list
     * @throws java.lang.IllegalArgumentException if data is null
     */
    public void addToBack(T data) {
        if (data == null){
            throw new IllegalArgumentException("Data cannot be null");
        }
            if (head == null){
            head = new SinglyLinkedListNode<T>(data);
        }
        else {
            SinglyLinkedListNode<T> current = head;
            while (current.getNext() != null){
                current = current.getNext();
            }
            current.setNext(new SinglyLinkedListNode<T>(data));
        }
        size++;
        }

    /**
     * Removes and returns the first data of the list.
     *
     * Method should run in O(1) time.
     *
     * @return the data formerly located at the front of the list
     * @throws java.util.NoSuchElementException if the list is empty
     */
        public T removeFromFront() {
        if (head == null){
            throw new NoSuchElementException("You cannot remove elements from the front of an empty list");
        }
        SinglyLinkedListNode<T> var = head;
            head = head.getNext();
        size--; 
        return var.getData();
        }

    /**
     * Removes and returns the last data of the list.
     *
     * Method should run in O(n) time.
     *
     * @return the data formerly located at the back of the list
     * @throws java.util.NoSuchElementException if the list is empty
     */
        public T removeFromBack() {
            if (head == null){
            throw new NoSuchElementException("You cannot remove an element from the back of an empty list");
        }
        else if (head.getNext() == null){
            SinglyLinkedListNode<T> var = head;
            head = null;
        }
        SinglyLinkedListNode<T> current = head;
        while (current.getNext().getNext() != null){
            current = current.getNext();
        }
        SinglyLinkedListNode<T> var = current.getNext();
        current.setNext(null);
        size--;
        return var.getData();
    }

    /**
     * Returns the head node of the list.
     *
     * For grading purposes only. You shouldn't need to use this method since
     * you have direct access to the variable.
     *
     * @return the node at the head of the list
     */
        public SinglyLinkedListNode<T> getHead() {
        // DO NOT MODIFY THIS METHOD!
            return head;
        }

    /**
     * Returns the tail node of the list.
     *
     * For grading purposes only. You shouldn't need to use this method since
     * you have direct access to the variable.
     *
     * @return the node at the tail of the list
     */
        public SinglyLinkedListNode<T> getTail() {
        // DO NOT MODIFY THIS METHOD!
            return tail;
        }

    /**
     * Returns the size of the list.
     *
     * For grading purposes only. You shouldn't need to use this method since
     * you have direct access to the variable.
     *
     * @return the size of the list
     */
        public int size() {
        // DO NOT MODIFY THIS METHOD!
            return size;
        }
    
    public String toString() {
        String answer = "";
        SinglyLinkedListNode<T> current = head;
        while (current != null){
            answer += current + "";
            current = current.getNext();
        }
        return answer;
    }

    public static void main(String[] args){
        SinglyLinkedList<Integer> list = new SinglyLinkedList<>();
        list.addToFront(1);
        System.out.println(list.toString());
    }
}

这是我的SingleLinkedListNode。java文件。

/**
 * Node class used for implementing the SinglyLinkedList.
 *
 * DO NOT MODIFY THIS FILE!!
 *
public class SinglyLinkedListNode<T> {

        private T data;
        private SinglyLinkedListNode<T> next;

    /**
     * Constructs a new SinglyLinkedListNode with the given data and next node
     * reference.
     *
     * @param data the data stored in the new node
     * @param next the next node in the list
     */
        SinglyLinkedListNode(T data, SinglyLinkedListNode<T> next) {
            this.data = data;
            this.next = next;
        }

    /**
     * Creates a new SinglyLinkedListNode with only the given data.
     *
     * @param data the data stored in the new node
     */
        SinglyLinkedListNode(T data) {
            this(data, null);
        }

    /**
     * Gets the data.
     *
     * @return the data
     */
        T getData() {
            return data;
        }

    /**
     * Gets the next node.
     *
     * @return the next node
     */
        SinglyLinkedListNode<T> getNext() {
            return next;
        }

    /**
     * Sets the next node.
     *
     * @param next the new next node
     */
        void setNext(SinglyLinkedListNode<T> next) {
            this.next = next;
        }
}

共有3个答案

柳轶
2023-03-14

您的问题是在toString中循环,直到next()返回null,但它从不返回null。

以下是一些有效的代码:

import org.junit.jupiter.api.Test;

import java.util.NoSuchElementException;

import static java.sql.DriverManager.println;

class LinkedListTest {

@Test
void testCanShowList() {
    System.out.println("hi there");
}

@Test
void testCanShowLinkedList() {
    SinglyLinkedList<Integer> list = new SinglyLinkedList<>();
    list.addToFront(1);
    System.out.println(list.toString());

}


}


class SinglyLinkedList<T> {

/*
 * Do not add new instance variables or modify existing ones.
 */
private SinglyLinkedListNode<T> head;
private SinglyLinkedListNode<T> tail;
private int size;

/*
 * Do not add a constructor.
 */

/**
 * Adds the element to the front of the list.
 *
 * Method should run in O(1) time.
 *
 * @param data the data to add to the front of the list
 * @throws java.lang.IllegalArgumentException if data is null
 */
public void addToFront(T data) {
    if (data == null){
        throw new IllegalArgumentException("Data cannot be null");
    }
    SinglyLinkedListNode<T> newNode = new SinglyLinkedListNode<T>(data);
    if (head == null){
        head = newNode;
        tail = newNode;
    }
    //newNode.setNext(head);
    head = newNode;
    size++;
}

/**
 * Adds the element to the back of the list.
 *
 * Method should run in O(1) time.
 *
 * @param data the data to add to the back of the list
 * @throws java.lang.IllegalArgumentException if data is null
 */
public void addToBack(T data) {
    if (data == null){
        throw new IllegalArgumentException("Data cannot be null");
    }
    if (head == null){
        head = new SinglyLinkedListNode<T>(data);
    }
    else {
        SinglyLinkedListNode<T> current = head;
        while (current.getNext() != null){
            current = current.getNext();
        }
        current.setNext(new SinglyLinkedListNode<T>(data));
    }
    size++;
}

/**
 * Removes and returns the first data of the list.
 *
 * Method should run in O(1) time.
 *
 * @return the data formerly located at the front of the list
 * @throws java.util.NoSuchElementException if the list is empty
 */
public T removeFromFront() {
    if (head == null){
        throw new NoSuchElementException("You cannot remove elements from the front of an empty list");
    }
    SinglyLinkedListNode<T> var = head;
    head = head.getNext();
    size--;
    return var.getData();
}

/**
 * Removes and returns the last data of the list.
 *
 * Method should run in O(n) time.
 *
 * @return the data formerly located at the back of the list
 * @throws java.util.NoSuchElementException if the list is empty
 */
public T removeFromBack() {
    if (head == null){
        throw new NoSuchElementException("You cannot remove an element from the back of an empty list");
    }
    else if (head.getNext() == null){
        SinglyLinkedListNode<T> var = head;
        head = null;
    }
    SinglyLinkedListNode<T> current = head;
    while (current.getNext().getNext() != null){
        current = current.getNext();
    }
    SinglyLinkedListNode<T> var = current.getNext();
    current.setNext(null);
    size--;
    return var.getData();
}

/**
 * Returns the head node of the list.
 *
 * For grading purposes only. You shouldn't need to use this method since
 * you have direct access to the variable.
 *
 * @return the node at the head of the list
 */
public SinglyLinkedListNode<T> getHead() {
    // DO NOT MODIFY THIS METHOD!
    return head;
}

/**
 * Returns the tail node of the list.
 *
 * For grading purposes only. You shouldn't need to use this method since
 * you have direct access to the variable.
 *
 * @return the node at the tail of the list
 */
public SinglyLinkedListNode<T> getTail() {
    // DO NOT MODIFY THIS METHOD!
    return tail;
}

/**
 * Returns the size of the list.
 *
 * For grading purposes only. You shouldn't need to use this method since
 * you have direct access to the variable.
 *
 * @return the size of the list
 */
public int size() {
    // DO NOT MODIFY THIS METHOD!
    return size;
}

public boolean hasNext() {
    return head != null;
}

public String toString() {
    String answer = "";
    while (hasNext()){
        T current = removeFromFront();
        answer += current + "";
    }
    return answer;
}

}

/**
 * Node class used for implementing the      SinglyLinkedList.
 * <p>
 * DO NOT MODIFY THIS FILE!!
 */
class SinglyLinkedListNode<T> {

private T data;
private SinglyLinkedListNode<T> next;

/**
 * Constructs a new SinglyLinkedListNode with the given data and next node
 * reference.
 *
 * @param data the data stored in the new node
 * @param next the next node in the list
 */
SinglyLinkedListNode(T data, SinglyLinkedListNode<T> next) {
    this.data = data;
    this.next = next;
}

/**
 * Creates a new SinglyLinkedListNode with only the given data.
 *
 * @param data the data stored in the new node
 */
SinglyLinkedListNode(T data) {
    this(data, null);
}

/**
 * Gets the data.
 *
 * @return the data
 */
T getData() {
    return data;
}

/**
 * Gets the next node.
 *
 * @return the next node
 */
SinglyLinkedListNode<T> getNext() {
    return next;
}

/**
 * Sets the next node.
 *
 * @param next the new next node
 */
void setNext(SinglyLinkedListNode<T> next) {
    this.next = next;
}
}
寇甫
2023-03-14

从您的addToFront()方法:

[...]
SinglyLinkedListNode<T> newNode = new SinglyLinkedListNode<T>(data);
if (head == null){
    head = newNode;
    tail = newNode;
}
newNode.setNext(head);
[...]

当您从一个新的链表开始并使用此方法添加第一个元素时,您将创建一个新节点newNode,将其保存在this.headthis.tail中。但是,您还可以更改新创建的SinglyLinkedListNode中的下一个字段

也许您需要执行类似于“如果其他”的操作来检查它是新列表还是现有列表,如下所示:

SinglyLinkedListNode<T> newNode = new SinglyLinkedListNode<T>(data);
if (head == null){
    head = newNode;
    tail = newNode;
} else {
    newNode.setNext(head);
    head = newNode;
}

易修洁
2023-03-14

请注意,您的代码中存在各种错误;这个问题是关于为什么你的toString看起来“挂起”,所以我在这里只回答这个问题。但是,举个例子,您的toString只是“打印”当前对象,因此是当前对象的缩写。toString(),但SLLN没有toString方法,因此不会产生有用的信息。您可能想要当前。getData()。改为toString()。

它与您的toString方法没有特别关系。这是你的addToFront方法,它以一种导致无休止循环的方式被破坏。

学习调试。这很简单!你想出一些示例输入,然后“在脑海中运行代码”——你一行一行地浏览代码,你就变成了电脑:如果必须的话,你可以拿出一个草稿,但要写下每个变量的每一个变化,每一个效果。然后,使用调试器,或者如果您现在不想学习如何使用调试器,可以通过添加大量的系统来伪造调试器。出来println语句,打印各种表达式/变量的值,并将您认为应该发生的事情与实际发生的事情进行比较。每次你发现分歧时,你都会发现一个bug。

例如,假设您的SinglyLinkedList为空,然后通过调用addToFront向其添加一个元素:

if (data == null){
           throw new IllegalArgumentException("Data cannot be null");
       }

它不是空的,所以这部分做了我们所期望的:“跳过”if块,这里什么都没有发生。您可以通过简单地见证IAEx没有发生来调试它。

  SinglyLinkedListNode<T> newNode = new SinglyLinkedListNode<T>(data);
  if (head == null){
      head = newNode;
      tail = newNode;
  }

这是一个全新的列表,因此应输入if块。如果您不能百分之百确定,那么应该在其中添加一些sysout语句,以便知道会发生这种情况。关键是,头、尾和新节点现在都是指向同一个对象的变量,即您刚才创建的用于表示添加数据的节点。

newNode.setNext(head);
head = newNode;
size++;

也许您错过了这一点,但是,这段代码也会运行!为什么不呢?

newNode指向您刚刚创建的对象。head也是如此。所以现在你告诉你的新节点它的下一个节点是...本身。这意味着任何遍历这个节点的尝试都是无限的——它只是一个指向自身的东西。也许您打算将这部分放在ore块中。

另一种调试方法是调试toString进程。使用调试器,或者向toString本身添加一些sysout语句(这有点危险,请确保只打印字符串和原语,否则可能会导致无限递归;不过,这至少会导致StackOverflower错误,从而泄露正在发生的事情),而且您会注意到它一直在反复调用自己。然后使用一些常识,可以得出这样的结论:节点必须指向自身,否则节点的<代码>中现在会有一个“循环”。下一步,从那里你可以重新找到答案,或者至少在得出结论后,你可以看看addToFront。

这一点永远不会消失——专家程序员只会在这个过程中变得更好,并能更直观地理解。换句话说,从定义上讲,获得调试经验是成为程序员的一个重要而必要的步骤。

 类似资料: