原则上,从ConcurrentLinkedQueue或类似实现中删除元素很容易。例如,该类的Iterator
支持有效的O(1)删除当前元素:
public void remove() {
Node<E> l = lastRet;
if (l == null) throw new IllegalStateException();
// rely on a future traversal to relink.
l.item = null;
lastRet = null;
}
我想用add()
向队列中添加一个元素,然后从队列中删除该确切元素。我能看到的唯一选择是:
保存对该对象的引用并使用该对象调用ConcurrentLinkedQueue.remove(Object o)
- 但这会在最坏的情况下强制遍历整个队列(平均有一半随机添加和删除模式)。
这还有一个问题,即它不一定会删除我插入的相同的对象。它会删除相等的对象,如果队列中的多个对象相等,则该对象可能是不同的。
使用ConcurrentLinkedDeque
代替addLast()
我的元素,然后立即抓住descendingIterator()
并迭代,直到找到我的元素(通常是第一个元素,但可能因为我正在有效地游走并发潮流。)
这是一个笨拙且可能非常慢的补充,这迫使我使用Deque
类,在这种情况下,对于许多操作来说复杂得多且速度慢一些(查看该类的Iterator.remove()
!)
此外,如果可以插入相同的(即==
标识),此解决方案仍然具有细微的故障模式,因为我可能会发现其他人插入了该对象,但在通常情况下可以忽略该对象可能的。
这两个解决方案看起来都很尴尬,但删除这些结构中的任意元素似乎是一个核心操作。我错过了什么?
在我看来,这是其他并发列表和出列的一般问题,甚至是非LinkedList
等非并发结构。
C ++以insert等方法的形式提供它。
答案 0 :(得分:0)
不,在Java API中没有任何方法可以做到这一点;它并不是真正的核心操作。
对于它的价值而言,首先如何处理它会有一些重大的技术难题。例如,考虑ArrayList
。如果向ArrayList
添加元素,则会为您提供另一个参考对象,告诉您该元素的位置......
add
操作添加分配ArrayList
中插入元素时,都必须为位置偏移的每个其他元素更新指针对象简而言之,虽然这对于基于链表的数据结构来说可能是一个合理的操作,但实际上并没有任何好的方法可以将它拟合到更通用的API中,所以它几乎被省略了。
答案 1 :(得分:0)
如果您特别需要此功能(例如,您将拥有大量集合),那么您可能需要实现自己的集合,该集合返回对添加条目的引用,并且能够在O(1)中删除。
class MyLinkedList<V> {
public class Entry {
private Entry next;
private Entry prev;
private V value;
}
public Entry add(V value) {
...
}
public void remove(Entry entry) {
...
}
}
换句话说,您不是按值删除,而是通过引用集合条目:
MyLinkedList<Integer> intList;
MyLinkedList.Entry entry = intList.add(15);
intList.remove(entry);
这显然需要付出相当多的工作量。