【问题标题】:Find and return an element from a TreeSet in Java从 Java 中的 TreeSet 中查找并返回一个元素
【发布时间】:2013-07-22 07:22:57
【问题描述】:

我有以下节点类

Class Node {
    private int id;

    public int getId() {
        return this.id;
    }
}

然后用节点创建一个 TreeSet。接下来我想根据 id 匹配找到并返回一个 Node 对象。但是,每次 findNode() 函数都返回下一个节点而不是下一个节点。我知道这是因为调用了 iterator.next() 两次。如何只调用一次以检查 id 值并返回对象引用。我也尝试过创建一个临时对象引用,但结果还是一样。

Class NodeSet {
    Set<Node> set = new TreeSet<Node>();

    public Node findNode(int id) {  
        Iterator<Node> iterator = set.iterator();
        while(iterator.hasNext()) {
            if(iterator.next().getId() == id)               
                return iterator.next();
        }

        return null;                
    }
}

【问题讨论】:

  • 为什么不使用 Map 而不是迭代?
  • @JBNizet: 可以举个例子多解释一下吗?
  • 创建一个Map&lt;Integer, Node&gt;,其中包含 ID 作为键,对应的节点作为值。当您需要具有给定 ID 的节点时,请致电 Node theNode = map.get(id)
  • @JBNizet,您的建议与 TreeSet 的使用无关。 Map 和 Set 是两个完全不同的集合。
  • @Reddy:你不认为我知道吗? OP 希望通过 ID 获取节点。这就是我建议使用 Map 的原因:它是这个用例的正确数据结构。

标签: java


【解决方案1】:
Class NodeSet {
    Set<Node> set = new TreeSet<Node>();

    public Node findNode(int id) {  
        Iterator<Node> iterator = set.iterator();
        while(iterator.hasNext()) {
            Node node = iterator.next();
            if(node.getId() == id)             
                return node;
        }

        return null;                
    }
}

【讨论】:

  • 我已经提到“我也尝试过创建一个临时对象引用,但结果还是一样。”
  • 我会说,再次检查您的期望。这是正确的,并且非常适合您的要求。如果你没有得到你想要的意思,那是你的设计或逻辑缺陷。
  • 感谢您告诉我再次检查。我用来调试的 print() 函数中有一个小错误!实际代码有点乱,第一时间抓不到错误。再次感谢。
  • 这个查找算法使用线性搜索——使用TreeSet 的优点是搜索可以在对数时间内完成!您可能想使用TreeMap
【解决方案2】:

问题发生在这里:

        while(iterator.hasNext()) {
            if(iterator.next().getId() == id)               
                return iterator.next();
        }

您在同一个循环中调用了两次 iterator.next,解释了“下一个到下一个”问题。

使局部变量仍能到达相同或更好的元素:如果您有 jdk >= 5,请使用 for 循环:

for(Node node: set) {
   if(node.getId() == id) 
     return node;
}

正如@JB Nizet 在上面的评论中所建议的那样,简单的Map 已经从本质上实现了您的代码逻辑,因此比TreeSet 和手动检查更适合。
更准确地说,TreeMapsorted on Nodes 将是相关的。 (因为听起来你需要订单方面)

【讨论】:

  • > 我知道这是因为调用了 iterator.next() 两次
  • 我已经提到“我也尝试过创建一个临时对象引用,但结果还是一样。”
  • 使用 for 循环 joarder,使用 foooorr 循环。
  • @mopheus 感谢您的建议。实际上,我将 TreeSet 用于其他特定目的。我只是在这里展示了一个与这个特定问题相关的非常简化的代码快照。再次感谢。
【解决方案3】:

编辑:这里提出的解决方案是对数(与公认的答案不同),因此当树集中的节点数量很大时会快得多。

TreeSet 类实现的Set 接口中没有get 方法。请记住,树集的元素之间存在完整的排序,三行 hack 如下:

Object search(TreeSet treeset, Object key) {
    Object ceil  = treeset.ceiling(key); // least elt >= key
    Object floor = treeset.floor(key);   // highest elt <= key
    return ceil == floor? ceil : null; 
}

【讨论】:

  • 我觉得第二个treeset.ceiling(key)应该换成treeset.floor(key)
  • 是的,我认为这是正确的。我还想说只使用floorcompareTo 实际上会更好,以节省进行两次搜索。除此之外,这是建议对数时间解决方案的唯一答案,所以它得到了我的投票。
  • 这绝对是最好的答案,与上面提出的线性解决方案不同,复杂度为 O(log(n))。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-26
  • 2021-06-26
  • 2011-12-16
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多