我正在尝试实现一个带有头和尾引用的单链表。为了测试我的脚本,我创建了一个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;
}
}
您的问题是在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;
}
}
从您的addToFront()
方法:
[...]
SinglyLinkedListNode<T> newNode = new SinglyLinkedListNode<T>(data);
if (head == null){
head = newNode;
tail = newNode;
}
newNode.setNext(head);
[...]
当您从一个新的链表开始并使用此方法添加第一个元素时,您将创建一个新节点newNode
,将其保存在this.head
和this.tail
中。但是,您还可以更改新创建的SinglyLinkedListNode中的
下一个
字段
也许您需要执行类似于“如果其他”的操作来检查它是新列表还是现有列表,如下所示:
SinglyLinkedListNode<T> newNode = new SinglyLinkedListNode<T>(data);
if (head == null){
head = newNode;
tail = newNode;
} else {
newNode.setNext(head);
head = newNode;
}
请注意,您的代码中存在各种错误;这个问题是关于为什么你的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。
这一点永远不会消失——专家程序员只会在这个过程中变得更好,并能更直观地理解。换句话说,从定义上讲,获得调试经验是成为程序员的一个重要而必要的步骤。
并且(您刚才看到的是演示的一部分,下面是类的部分内容) 我真的不知道为什么它不打印字符串的东西:(所有的类(稍后将删除) }
问题内容: 我有以下代码: 以及其他各种方法,例如@ Before,@ After,@ Test或@AfterClass方法。 测试在启动时不会像看起来的那样失败。有谁可以帮助我吗? 我有JUnit 4.5 该方法无法立即调用注释为@before的setUp()。类def是: 问题答案: 不要扩展TestCase并同时使用注释! 如果需要使用批注创建测试套件,请使用RunWith批注,例如: (按
如标题所示,基本上为什么java-version在我的命令提示符中与where java不一致?
问题内容: 我有一个非常简单的python程序,用于学习pygame,此外,我还使用图像。 当我使用PyCharm运行该程序时,或者当我双击该文件运行该程序时,它运行良好。但是,如果尝试通过命令提示符运行它,则会收到以下错误: 这是我的代码中所引用的行: 图像“ racecar.png”位于与程序完全相同的目录中。令人困惑的是,我的代码似乎很好,因为通过双击运行它时没有错误。 必要时可以发布完整代
我最近在Windows 10机器上下载了截至2020年3月的python(3.8),并检查了我的Pip版本。我使用了pip(版本)和其他几个命令,但它说“pip不能被识别为内部或外部命令、可操作的程序或批处理文件。”我去了Windows中的简单搜索栏,找到了安装在我电脑上的pip。那么我需要使用什么命令来使用pip呢?还是我还遗漏了什么?