【问题标题】:Java LinkedHashSet remove some elements from the endJava LinkedHashSet 从末尾删除一些元素
【发布时间】:2013-04-08 22:36:04
【问题描述】:

我正在解决一个问题,我需要存储具有无重复和维护顺序要求的元素。我选择了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) ??
   }

谁能指导我删除这些元素的逻辑?

我是否使用了错误的数据结构?如果是这样,那么有什么更好的选择?

【问题讨论】:

    标签: java removeall linkedhashset


    【解决方案1】:

    如果您使用 LinkedHashSet,我认为您可能需要使用迭代器进行删除。也就是说找到元素,然后继续删除,直到找到尾部。这将是 O(n),但是即使您编写了自己的 LinkedHashSet(带有双向链表和哈希集),您也可以访问原始链接结构,以便您可以在 O(1) 中剪切链表,但是您仍然需要从 HashSet 中删除您刚刚从链表中删除的所有元素,这是 O(n) 成本再次出现的地方。

    因此,总而言之,删除元素,然后为该元素保留一个迭代器,并继续向下删除元素,直到到达最后。我不确定 LinkedHashSet 是否公开了所需的调用,但您可能会弄清楚。

    【讨论】:

    • +1 - 分析准确。必须单独从哈希表中删除元素,这使得 O(N) ......无论您如何处理“链接”或“排序”要求。
    • 实际上我对 O(n) 没有任何问题,因为我的数据并没有那么大,不用担心。我面临的真正问题是 LinkedHashSet 没有实现 get(index) 函数。它也没有告诉我哪个是最后一个元素。所以,我不能像你所说的那样遍历列表。
    • 编写自己的类来包装哈希集和链表数据结构可能是最简单的方法,这样您就可以准确地公开要在底层数据结构上使用的方法。
    【解决方案2】:

    您可以通过覆盖add()addAll() 来编写自己的不允许重复的ArrayList 版本。据我所知,没有这样的“常见”第 3 方版本,这一直让我感到惊讶。有人知道吗?

    那么删除代码就很简单了(不需要使用ListIterator

    int idx = this.indexOf("D");
    if (idx >= 0) {
      for (int goInReverse = this.size()-1; goInReverse > idx; goInReverse--)
        this.remove(goInReverse);
    }
    

    但是,这仍然是 O(N),因为您要遍历 List 的每个元素。

    【讨论】:

    • 你的意思是说我应该编写自己的逻辑来停止重复?我可以这样做,但是从学习的角度来看,如果不是这样,您能否详细说明在其他哪种情况下使用 LinkedHashSet?
    • 不一定应该,但可以——根据发生的情况,ArrayList 可以更有效。如果您需要维护添加项目的顺序,LinkedHashSet 很有用。我通常使用 HashSet(不关心顺序)或 TreeSet(使用自然顺序,例如元素的字母顺序)。
    【解决方案3】:

    这里的基本问题是你必须维护两个数据结构,一个代表键/值映射的“map”,另一个代表插入顺序的“list”。

    有“地图”和“列表”组织可以在给定点之后快速删除元素;例如各种有序树以及基于数组和链的列表(以定位点的成本为模。)

    但是,从两个数据结构中删除 N 个元素似乎不可能比O(N) 更好。您必须访问所有要删除的元素才能将它们从第二个数据结构中删除。 (事实上​​,我怀疑可以用数学方法证明这一点……)

    简而言之,没有比您当前使用的数据结构更复杂的数据结构了。

    可以提高性能(使用自定义集合类!)的领域是避免显式使用迭代器。使用迭代器和标准迭代器 API,数据结构中元素总数的成本为 O(N)。如果散列条目节点也有序列的下一个/上一个链接,您可以在删除的元素数量上创建 O(N)

    【讨论】:

    • 在这个例子中没有“地图”,只有值。也就是说,我同意你的分析,无论如何这很可能是 O(N)...
    • @user949300 - 真的......有点。然而,概念上还有第二种数据结构。而在标准的 HashSet 实现中,集合是使用 HashMap 实现的。请参阅docjar.com/html/api/java/util/HashSet.java.html ... 第 102 行。
    【解决方案4】:

    所以,在尝试了上面提到的几件事之后,我选择了实现不同的数据结构。因为我对这个问题的 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)
    
    }
    

    我同意 graph DS 不适合这类问题,但在我的条件下,这非常有效……干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-30
      • 1970-01-01
      • 2014-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-02
      相关资源
      最近更新 更多