【问题标题】:Remove nodes with given key in linked list删除链表中给定键的节点
【发布时间】:2015-09-29 05:20:39
【问题描述】:

我很难弄清楚我的代码有什么问题。我想删除包含特定项目的所有节点。在我的代码下面的测试代码中,它要求我删除句子“to be or not to be”中的所有“to”项,然后返回头部,在本例中为“be”。有人可以指出我的代码的问题吗?谢谢。

package edu.csc130.assignment;
import java.util.LinkedList;

public class ListStackQueue {
/**
 * @param head the head of the input linked list
 * @param item the given value
 * @return the head of the linked list with nodes contains the given value removed
 * Assume for any node in the  linked list, node.item cannot be null
 */
  public static Node<String> removeNodes(Node<String> head, String item) {
    Node<String> curr = head;
    Node<String> prev = null;

    if (head == null) {
        System.out.println("list is empty");
    } else {
        while (curr != null) {
            if (curr.data != item) {
                prev = curr; 
                curr = curr.next; 
            } else if (curr == head && curr.data == item) {
                head = head.next; 
                curr = curr.next; 
            } else if (curr != head && curr.next != null && curr.data == item) {
                prev.next = curr.next; 
                curr = curr.next; 
            } else {
                curr.next = null; 
            }
        }   
    }

    return head;
  }
}

BuildList Part of Code

/**
 * @param items input array
 * @return the first node of the linked list build from the input array
 */
public static <E> Node<E>  buildList(E[] items) {
    Node<E> head = null;
    if (items!=null && items.length>0) {
        head = new Node<E> (items[0], null);
        Node<E> tail = head;
        for (int i=1; i<items.length; i++) {
            tail.next = new Node<E>(items[i], null);
            tail = tail.next;
        }
    }
    return head;
}

/**
 * @param head the first node of the linked list
 * @return the length of the linked list
 */
public static <E> int getLength(Node<E> head) {
    int length = 0;
    Node<E> node = head;
    while (node!=null) {
        length++;
        node = node.next;
    }
    return length;
}

public static <E> E get(Node<E> head, int index) {
    E item = null;
    Node<E> node = head;
    for (int i=0; i<index; i++) {
        if (node != null) {
            node = node.next;
        } else {
            break;
        }
    }
    if (node!=null) {
        item = node.item;
    }
    return item;
}

public static class Node<E> {
    public Object data;

    public String data();
    E item;
    Node<E> next;

    public Node(E item) {
        this.item = item;
        this.next = null;
    }

    public Node(E item, Node<E> next) {
        this.item = item;
        this.next = next;
    }
}

测试代码:

package edu.csc130.assignment;
import org.junit.Assert;
import org.junit.Test;

import edu.csc130.assignment.ListStackQueue.Node;

public class ListStackQueueTest {

  @Test
  public void testRemoveNodes1() {
    Node<String> head = ListStackQueue.buildList(null);
    ListStackQueue.removeNodes(head, "to");
    Assert.assertNull(head);
  }

  @Test
  public void testRemoveNodes2() {
    String[] sentence = {"to", "be", "or", "not", "to", "be"};
    Node<String> head = ListStackQueue.buildList(sentence);
    head = ListStackQueue.removeNodes(head, "to");
    Assert.assertEquals(4, ListStackQueue.getLength(head));
    Assert.assertEquals("be", ListStackQueue.get(head, 0));
    Assert.assertEquals("or", ListStackQueue.get(head, 1));
    Assert.assertEquals("not", ListStackQueue.get(head, 2));
    Assert.assertEquals("be", ListStackQueue.get(head, 3));
  } 

  @Test
  public void testRemoveNodes3() {
    String[] sentence = {"to", "be", "or", "not", "to", "be"};
    Node<String> head = ListStackQueue.buildList(sentence);
    head = ListStackQueue.removeNodes(head, "be");
    Assert.assertEquals(4, ListStackQueue.getLength(head));
    Assert.assertEquals("to", ListStackQueue.get(head, 0));
    Assert.assertEquals("or", ListStackQueue.get(head, 1));
    Assert.assertEquals("not", ListStackQueue.get(head, 2));
    Assert.assertEquals("to", ListStackQueue.get(head, 3));
  }     

  @Test
  public void testRemoveNodes4() {
        String[] sentence = {"to", "be", "or", "not", "to", "be"};
        Node<String> head = ListStackQueue.buildList(sentence);
        head = ListStackQueue.removeNodes(head, "or");
        Assert.assertEquals(5, ListStackQueue.getLength(head));
        Assert.assertEquals("to", ListStackQueue.get(head, 0));
        Assert.assertEquals("be", ListStackQueue.get(head, 1));
        Assert.assertEquals("not", ListStackQueue.get(head, 2));
        Assert.assertEquals("to", ListStackQueue.get(head, 3));
        Assert.assertEquals("be", ListStackQueue.get(head, 4));
      }
}

这是我在 Eclipse 中使用 JUnit 测试运行代码时遇到的错误。这是 testRemoveNodes2 测试的错误。 testRemoveNodes1 测试没有错误。

java.lang.AssertionError: expected:<4> but was:<6>

【问题讨论】:

  • 先生。兔子,你的错误输出在哪里?
  • @TimBiegeleisen 我正在使用 JUnit 在 Eclipse 中运行它,它给了我这个错误:java.lang.AssertionError: expected: but was:
  • removeNodes() 方法中的逻辑似乎 是正确的。您能否包含使用此方法的完整代码,以便我们了解它是如何使用的?
  • 必须使用equals 字符串比较必须使用equals 字符串比较必须使用equals 字符串比较...
  • 当然,我已经用我的整个代码和给定的测试代码进行了编辑。

标签: java linked-list nodes


【解决方案1】:

我看到您的程序不起作用的唯一方法是,如果使用 ==!= 比较 curr.dataitem 没有按预期工作。这是完全可能的,因为不建议使用这些运算符比较字符串,这不是一种常见做法,除非您真的知道自己在做什么(优化),否则它们不会达到您的预期。

例如,如果在您的ListStackQueue.buildList 实现中,您使用new String(...) 创建节点的data 字段的值。如果您以这种方式创建值,那么 s1 == s2 将永远不会对两个字符串为真,即使它们的值相同。

底线是,不要使用==!= 比较字符串, 改写你的实现以使用.equals, 然后它应该工作。 当然,当你这样做的时候,在对一个对象调用.equals之前,你需要先验证它不为空,否则你会得到一个NullPointerException

假设没有data 字段为null 的节点,这应该可以工作:

if (head == null) {
    System.out.println("list is empty");
} else {
    while (curr != null) {
        if (!curr.data.equals(item)) {
            prev = curr; 
            curr = curr.next; 
        } else if (curr == head) {
            head = head.next; 
            curr = curr.next; 
        } else if (curr != head && curr.next != null) {
            prev.next = curr.next; 
            curr = curr.next; 
        } else {
            curr.next = null; 
        }
    }   
}

return head;

我还删除了一些多余的条件。

如果您想允许 null 值用于 Node.data, 那么上面的!curr.data.equals(item)会复杂一些, 替换为:

        if (curr.data == null && item != null || curr.data != null && !curr.data.equals(item)) {

【讨论】:

  • 您无法编写 buildList 以便在测试中的调用中显示的 removeNodes 可以与 == 和 != 一起使用。 (是的,我知道 String.intern。)
  • 所以即使与 null 比较,我也应该使用 .equals 更改所有 == 和 !=?是的,我相信 ListStackQueue.buildList 使用 String 创建新的节点值。
  • 是的,您应该使用 equals 进行字符串比较。如果您调用它的字符串可能为空,那么您需要先进行空检查
  • 这在很大程度上取决于 buildList 的数组是如何组合在一起的,而不是方法的编写方式。
  • @MrRabbit 谢谢。看着它,在我看来,与== 的比较应该有效。不过这并不重要,因为在这个特定的谈话中,一般来说,这不是比较字符串的正确方法。我在回答中进行了解释,并提供了解决方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-23
  • 2021-03-10
  • 1970-01-01
  • 2020-11-12
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多