如何从链表Java中删除特定值?
我试图在实现中实现它,但这并不容易。
这就是我想要做的:
//How to do this...;<..
int remove(Item item) {
Node cur = first.next;
Node prev = first;
while (cur !=null) {
if (cur.item.equals(item)) {
item = dequeue();
}
cur = cur.next;
// TODO
}
return 0;
}
这些是预设置:
public class LinkedQueue<Item> implements Iterable<Item> {
private int N; // number of elements on queue
private Node first; // beginning of queue
private Node last; // end of queue
// helper linked list class
private class Node {
private Item item;
private Node next;
}
/**
* Initializes an empty queue.
*/
public LinkedQueue() {
first = null;
last = null;
N = 0;
assert check();
}
public Item dequeue() {
if (isEmpty()) throw new NoSuchElementException("Queue
underflow");
Item item = first.item;
first = first.next;
N--;
if (isEmpty()) last = null; // to avoid loitering
assert check();
return item;
}
主要功能:
public static void main(String[] args) {
LinkedQueue<String> q = new LinkedQueue<String>();
q.enqueue("a");
q.enqueue("b");
q.enqueue("c");
q.enqueue("a");
q.enqueue("b");
q.enqueue("d");
q.enqueue("b");
q.enqueue("abba");
q.enqueue("a");
q.enqueue("z");
q.enqueue("a");
System.out.println(q);
System.out.println("Remove some of elements.");
q.remove("a");
q.remove("f");
q.remove("c");
System.out.println(q);
}
}
我得到这样的结果。完全没有改变。.
a b c a b d b abba a z a Remove some of elements. a b d b abba a z a
仅擦除值c
。我不知道为什么。
答案 0 :(得分:1)
根据问题的详细信息,我假设您在Java中还很陌生。 您的要求和所显示的详细信息完全不同。
LinkedQueue<String> q = new LinkedQueue<String>();
仅当LinkedQueue是流派类而不是Item类型类的特定隐式时才适用。即您不是在创建LinkedQueue<Item>
类的对象。 LinkedQueue<String> and LinkedQueue<Item>
是不同的。
cur.equals(item)
缺乏同等合同知识和== vs equal
中的差异。即您正在比较两个完全不同的对象。一个是节点,另一个是Item类对象。
建议:明确基础知识,请阅读cathy Sierra.Scjp Sun Java 6认证程序员的书
至于答案,您实际上不是在调用main的remove(通过打印进行测试) 删除方法中的语句)。这就是为什么您总是得到相同答案的原因。
注意:即使我们告诉您,您也确实无法消化真正的解决方案。
答案 1 :(得分:1)
以下代码段包含各种remove()
方法,这些方法取自我的LinkedList
实现之一,以Java
编写。
LinkedList.java (部分)
private int size; // node count,
private LinkedListNode<T> head; // first node,
private LinkedListNode<T> end; // last node,
/**
* Remove by index.
*
* @param k index, start from 0,
* @return value of removed node, or null if not removed,
*/
@Override
public T remove(int k) {
checkElementIndex(k);
// find target node, and remember previous node,
LinkedListNode<T> preNode = null;
LinkedListNode<T> node = head;
while (k-- > 0) {
preNode = node;
node = node.next;
}
T result = (T) node.value; // keep return value,
removeNode(node, preNode); // remove
return result;
}
/**
* Remove by value, only remove the first occurrence, if any.
*
* @param v
* @return whether removed,
*/
@Override
public boolean removeValue(T v) {
// find target node, and remember previous node,
LinkedListNode<T> preNode = null;
LinkedListNode<T> node = head;
while (true) {
if (node == null) return false;// not found,
if (node.getValue().compareTo(v) == 0) break; // value found,
preNode = node;
node = node.next;
}
removeNode(node, preNode); // remove
return true;
}
/**
* Remove by value, remove all occurrences.
*
* @param v
* @return count of nodes removed,
*/
@Override
public int removeAllValue(T v) {
int rc = 0;
// find target node, and remember previous node,
LinkedListNode<T> preNode = null;
LinkedListNode<T> node = head;
while (true) {
if (node == null) return rc; // reach end,
if (node.getValue().compareTo(v) == 0) { // value found,
rc++;
if (removeNode(node, preNode)) break; // remove, break if it's end,
continue; // recheck this node, since it become the next node,
}
preNode = node;
node = node.next;
}
return rc;
}
/**
* Remove given node, which guarantee to exists. Also reduce the size by 1.
*
* @param node node to delete,
* @param preNode previous node, could be null,
* @return indicate whether removed node is end,
*/
protected boolean removeNode(LinkedListNode node, LinkedListNode preNode) {
LinkedListNode nextNode = node.next; // next node,
boolean isEnd = (nextNode == null);
if (isEnd) { // target is end,
if (preNode == null) { // target is also head,
head = null;
} else { // target is not head, thus preNode is not null,
preNode.next = null;
}
end = preNode;
} else { // target is not end,
// replace target with next node,
node.next = nextNode.next;
node.value = nextNode.value;
}
size--; // reduce size by 1,
return isEnd;
}
/**
* Remove head node,
*
* @return
*/
@Override
public T removeHead() {
return remove(0);
}
/**
* Remove end node,
*
* @return
*/
@Override
public T removeEnd() {
return remove(size - 1);
}
LinkedListTest.java (部分)
(单元测试,通过TestNG
)
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* LinkedList test.
*
* @author eric
* @date 1/28/19 6:03 PM
*/
public class LinkedListTest {
private int n = 10;
private LinkedList<Integer> llist; // linked list,
private LinkedList<Integer> dupEvenLlist; // linked list, with duplicated even values,
@BeforeMethod
public void init() {
// init llist,
llist = new LinkedList(); // create linked list,
Assert.assertTrue(llist.isEmpty());
LinkedList.appendRangeNum(llist, 0, n); // append range,
// init dupEvenLlist,
dupEvenLlist = new LinkedList(); // create linked list,
LinkedList.appendRangeNum(dupEvenLlist, 0, n); // append range,
LinkedList.appendRangeNum(dupEvenLlist, 0, n, 2); // append range, again, with step as 2 (only even numbers),
Assert.assertEquals(dupEvenLlist.size(), n + n / 2);
}
// non-remove related test cases ... are deleted,
// remove(k) - remove by index,
@Test
public void testRemoveByIndex() {
for (int i = 0; i < n; i++) {
Assert.assertEquals(llist.removeEnd().intValue(), n - 1 - i); // remove by end, in turn it remove by index,
Assert.assertEquals(llist.size(), n - 1 - i);
}
Assert.assertTrue(llist.isEmpty());
}
// remove(v) - remove by value,
@Test
public void testRemoveByValue() {
Assert.assertFalse(llist.removeValue(n)); // not exists,
for (int i = n - 1; i >= 0; i--) {
Assert.assertTrue(llist.removeValue(i)); // remove by value,
Assert.assertEquals(llist.size(), i);
}
Assert.assertTrue(llist.isEmpty());
Assert.assertFalse(llist.removeValue(0)); // empty,
// remove from list with duplicated value,
for (int i = 0; i < n; i++) {
Assert.assertTrue(dupEvenLlist.removeValue(i));
}
Assert.assertFalse(dupEvenLlist.isEmpty());
Assert.assertEquals(dupEvenLlist.size(), n / 2);
}
// removeAll(v) - remove all occurrences by value,
@Test
public void testRemoveAllByValue() {
Assert.assertEquals(dupEvenLlist.removeAllValue(n), 0); // not exists,
int remainSize = dupEvenLlist.size();
for (int i = 0; i < n; i++) {
int rc = dupEvenLlist.removeAllValue(i); // remove all by value,
Assert.assertEquals(rc, i % 2 == 0 ? 2 : 1);
remainSize -= rc;
Assert.assertEquals(dupEvenLlist.size(), remainSize);
}
Assert.assertTrue(dupEvenLlist.isEmpty());
Assert.assertEquals(dupEvenLlist.removeAllValue(0), 0); // empty,
}
}
所有测试用例都会通过。
方法:
T remove(int k)
,按索引删除。Steps: * loop to target node, * for each step, record: * previous node, * this node, * get next node, of target node, * get value of target node, as return value later, * if target is end, * if also head, head = null; * if not head, preNode.next = null; * end = preNode; * if targe is not end, replace it with its next node, logic: * node.value = nextNode.value; * node.next = nextNode.next; * return previously tracked value of target node,
boolean removeValue(T v)
,按值删除,仅删除第一个匹配项。
逻辑类似于按索引删除。
区别在于:
int removeAllValue(T v)
,按值删除所有内容,删除所有出现的内容。
这类似于按值删除。
差异:
removeNode()
的返回值。 boolean removeNode(LinkedListNode node, LinkedListNode preNode)
,按节点删除,并指定preNode。
删除给定的节点(保证存在),并给定先前的节点(该节点可能为null)。
返回值指示删除的节点是否为末端,主要用于支持removeAllValue()
。
T removeHead()
,T removeEnd()
,卸下头/端。
只需调用通过索引删除,并传递相应的索引0
和size - 1
。
提示:
LinkedList
代表链表,具有字段size
,head
,end
和通用类型T
(用于节点中的值类型),它不是线程-安全。checkElementIndex()
方法,检查给定的索引,如果超出范围则抛出异常。LinkedListNode
,代表链表中的节点。字段为value
,next
。O(k)
O(n)
位置:
k
是目标的索引。n
是链表的大小。答案 2 :(得分:1)
自Java 8开始,您可以使用removeIf(Predicate<? super E> filter)
方法来设置自己的条件。
list.removeIf(cur -> cur.item.equals(item));
答案 3 :(得分:0)
在if语句中,您正在检查cur
Node
是否等于传递的Item
中的if (cur.equals(item))
。
我认为您应该检查Item
cur
中存储的Node
是否等于传递给函数Item
的{{1}}。 / p>