我正在解决一个问题,我需要存储具有无复制和维护顺序要求的元素。我选择LinkedHashSet
,因为它满足了我的要求。
假设我有这段代码:
LinkedHashSet hs = new LinkedHashSet();
hs.add("B");
hs.add("A");
hs.add("D");
hs.add("E");
hs.add("C");
hs.add("F");
if(hs.contains("D")){
//do something to remove elements added after"D" i-e remove "E", "C" and "F"
//maybe hs.removeAll(Collection<?>c) ??
}
有人可以指导我删除这些元素的逻辑吗?
我使用错误的数据结构吗?如果是这样,那么什么是更好的选择呢?
答案 0 :(得分:3)
如果您使用LinkedHashSet,我认为您可能需要使用迭代器来执行删除操作。也就是说找到元素,然后继续移除直到你到达尾部。这将是O(n),但即使您编写了自己的LinkedHashSet(具有双向链接列表和哈希集),您也可以访问原始链接结构,以便您可以在O(1)中剪切链接列表,但是仍然需要从HashSet中删除刚刚从链表中剪切的所有元素,这是O(n)成本再次出现的地方。
总而言之,删除元素,然后保持该元素的迭代器并继续向下移除元素,直到结束。我不确定LinkedHashSet是否公开了所需的调用,但你可能会想出来。
答案 1 :(得分:0)
这里的基本问题是你必须维护两个数据结构,一个代表键/值映射的“map”和另一个代表插入顺序的“list”。
有“map”和“list”组织可以在给定点之后快速删除元素;例如有序树和各种类型的数组以及基于链的列表(以模块定位点的成本为模。)
但是,似乎不可能从两个数据结构中删除N个元素,而不是O(N)
。您必须访问要删除的所有元素才能从第二个数据结构中删除它们。 (事实上,我怀疑有人可以用数学证明这一点......)
简而言之,没有比目前使用的数据结构更复杂的数据结构。
可以提高性能的区域(使用自定义集合类!)是避免显式使用迭代器。使用迭代器和标准迭代器API,数据结构中元素总数的成本为O(N)
。您可以对删除的元素数量进行此O(N)
...如果散列条目节点还具有该序列的next / prev链接。
答案 2 :(得分:0)
您可以通过覆盖add()
和addAll()
来编写自己的ArrayList版本,该版本不允许重复。据我所知,没有“共同”的第三方版本,这一直让我感到惊讶。谁知道一个?
然后删除代码非常简单(不需要使用ListIterator
)
int idx = this.indexOf("D");
if (idx >= 0) {
for (int goInReverse = this.size()-1; goInReverse > idx; goInReverse--)
this.remove(goInReverse);
}
但是,这仍然是O(N),因为你循环遍历List的每个元素。
答案 3 :(得分:0)
因此,在尝试了上面提到的几件事之后,我选择实现不同的数据结构。因为我对这个问题的O(n)没有任何问题(因为我的数据非常小)
我使用了Graphs,这个库非常方便:http://jgrapht.org/
我正在做的是将所有元素作为顶点添加到DirectedGraph
,同时在它们之间创建边缘(边缘也帮助我解决了另一个非相关问题)。当删除元素的时候,我使用带有以下伪代码的递归函数:
removeElements(element) {
tempEdge = graph.getOutgoingEdgeFrom(element)
if(tempEdge !=null)
return;
tempVertex = graph.getTargetVertex(tempEdge)
removeElements(tempVertex)
graph.remove(tempVertex)
}
我同意图DS对这类问题并不好,但在我的条件下,这完全有效......干杯!