简体   繁体   English

如何从Java中的链表中删除特定值?

[英]How to remove a specific value from linked list in Java?

How to remove a specific value from a linked list java? 如何从链表java中删除特定值?
I tried to make it in my implementation, but it wasn't easy.. 我试图在我的实现中实现它,但这并不容易..

Here is what I'm trying to make: 这是我想要做的:

//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;

}

These are the pre-setup: 这些是预先设置:

 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;
   }

And the main function: 主要功能:

 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);
   }
  } 

And I have a result like this. 我有这样的结果。 It doesn't change at all.. 它根本不会改变..

a b c a b d b abba a z a 
 Remove some of elements.
 a b d b abba a z a

It only erase value c . 它只消除了值c I don't know why. 我不知道为什么。

As per the details of question,i assume you are fairly new in Java. 根据问题的细节,我假设你是Java的新手。 What you are asking and the details you are showing are totally different. 你问的问题和你展示的细节是完全不同的。

  1. LinkedQueue<String> q = new LinkedQueue<String>(); is only applicable if LinkedQueue is a genreic class not a specific impl for Item type class. 仅当LinkedQueue是一个genreic类而不是Item类的特定impl时才适用。 ie you are not creating object of LinkedQueue<Item> class. 即你没有创建LinkedQueue<Item>类的对象。 LinkedQueue<String> and LinkedQueue<Item> is different. LinkedQueue<String> and LinkedQueue<Item>是不同的。

  2. cur.equals(item) lack of knowledge of equal contract and difference in == vs equal . cur.equals(item)缺乏对平等合同和== vs equal差异的知识。 ie you are comparing a two totally different object. 即你正在比较两个完全不同的对象。 One is a Node and other is Item class object. 一个是Node,另一个是Item类对象。

Suggestion: clear basics, Read book by cathy Sierra.Scjp Sun Certified Programmer for Java 6 建议:明确的基础知识,阅读由cathy Sierra.Scjp Sun认证的Java 6程序员

As for answer, you are literally not calling remove from main (test it via a print statement in remove method). 至于答案,你实际上不是从main调用remove(在remove方法中通过print语句测试它)。 That is why you keep getting same answer. 这就是为什么你一直得到相同的答案。

Note: Your really not can't digest real solution even if we tell. 注意:即使我们告诉你,你真的不能消化真正的解决方案。

Following code snippet contains various remove() methods, taken from one of my LinkedList implementation, written in Java . 以下代码片段包含各种remove()方法,这些方法取自我用Java编写的LinkedList实现之一。


Code

LinkedList.java (partly) 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 (partly) LinkedListTest.java (部分)
(unit test, via TestNG ) (单元测试,通过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,
    }
}

All test cases would pass. 所有测试用例都会通过。


Explanation 说明

Methods: 方法:

  • T remove(int k) , remove by index. 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) , remove by value, only remove first occurrence, if any. boolean removeValue(T v) ,按值删除,仅删除第一个匹配项(如果有)。
    The logic is similar as remove by index. 逻辑类似于按索引删除。
    The differences are: 不同之处是:

    • At initial search, compare element instead of loop to index, to find target. 在初始搜索时,比较元素而不是循环到索引,以找到目标。
    • Return boolean that indicate whether removed, instead of removed value, 返回布尔值,指示是否删除,而不是删除值,
  • int removeAllValue(T v) , remove all by value, remove all occurrences. int removeAllValue(T v) ,删除所有值,删除所有匹配项。
    This is similar as remove by value. 这类似于按值删除。

    Differences: 区别:

    • [ inside while() ] [ 里面的同时() ]
    • It will search all occurrence till end. 它将搜索所有事件直到结束。
    • After removing an occurrence, it "continue" to recheck the current node. 删除事件后,它“继续”以重新检查当前节点。 Because the current node has actual replaced by it's next. 因为当前节点已被实际替换为下一个节点。
    • If removed node is end, then return. 如果删除的节点结束,则返回。
      This relay on the return value of removeNode() . 这个relay对removeNode()的返回值。
    • It record count of removed occurrence. 它记录删除发生的次数。
    • [ return value ] [ 返回值 ]
    • It return count of removed occurrence, instead of boolean. 它返回删除事件的计数,而不是布尔值。
  • boolean removeNode(LinkedListNode node, LinkedListNode preNode) , remove by node, with preNode given. boolean removeNode(LinkedListNode node, LinkedListNode preNode) ,逐节点删除,给定preNode。
    Remove given node, which is guaranteed to exists, with previous node given, which might be null. 删除给定节点,该节点保证存在,给定前一个节点,该节点可能为null。
    Return value indicate whether removed node is end, it's mainly used to support removeAllValue() . 返回值表示删除的节点是否结束,它主要用于支持removeAllValue()

  • T removeHead() , T removeEnd() , remove head / end. T removeHead()T removeEnd() ,删除头/尾。
    Simply calls remove by index, with corresponding index 0 and size - 1 passed. 只需通过索引调用remove,并传递相应的索引0size - 1

Tips: 提示:

  • LinkedList represent linkedlist, with fields size , head , end , and generic type T (for value type in node), it's not thread-safe. LinkedList表示链表,包括字段sizeheadend和泛型类型T (对于节点中的值类型),它不是线程安全的。
  • checkElementIndex() method, check given index, and throw exception if out of range. checkElementIndex()方法,检查给定索引,如果超出范围则抛出异常。
  • LinkedListNode , represent the node in linked list. LinkedListNode表示LinkedListNode的节点。 with fields value , next . 有字段valuenext

Complexity 复杂

  • Remove single: O(k) 删除单个: O(k)
  • Remove all by value: O(n) 全部删除值: O(n)

Where: 哪里:

  • k , is the index of target. k ,是目标的索引。
  • n , is size of linkedlist. n ,是链表的大小。

从Java 8开始,有removeIf(Predicate<? super E> filter)方法可以放置自己的条件。

list.removeIf(cur -> cur.item.equals(item));

In your if statement you are checking if the cur Node is equal to the Item passed in: if (cur.equals(item)) . 在if语句中,您正在检查cur Node是否等于传入的Itemif (cur.equals(item))

I think you should be checking if the Item stored in the cur Node is equal to the Item passed into your function: if (cur.item.equals(item)) . 我想你应该检查,如果Item存储在cur Node等于Item传递到你的函数: if (cur.item.equals(item))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM