【问题标题】:Returning an element from a TreeSet using binary search使用二分搜索从 TreeSet 中返回一个元素
【发布时间】:2012-04-07 04:11:17
【问题描述】:

在 TreeSet 中有一个名为 contains 的方法,如果元素在集合中,则该方法返回 true。我假设此方法使用二进制搜索并且不会按升序遍历所有元素。我对吗?

我有一个 TreeSet,它包含一个类的对象,该类使用两个 String 实例变量来将其与同一类的其他对象区分开来。我希望能够通过将对象的两个实例变量(当然使用 get 方法)与其他两个 String 变量进行比较来创建一个搜索 TreeSet 的方法,如果它们相等,则返回元素。如果实例变量小于转到右子树中的第一个元素,或者如果它们在左子树中进行更大的搜索等。有没有办法做到这一点?

我知道我可以将对象存储在 ArrayList 中并使用二进制搜索来查找对象,但这不会像搜索 TreeSet 一样快。

【问题讨论】:

  • 你怎么知道ArrayList 中的二分查找没有那么快?你试过了吗?
  • 我的意思是每次我需要搜索一个元素并返回它时将元素从 TreeSet 传递到一个新的 ArrayList 很慢。
  • 啊,是的,那肯定会很慢。但是,如果您首先构建集合,然后多次搜索,那么对ArrayList 进行排序和二进制搜索可能会非常快。
  • 如果一个实例变量大于其对应变量而另一个实例变量小于其对应变量怎么办?那应该怎么排序呢?
  • @Carl Manaster:对象首先按其中一个字符串排序,然后是另一个。就像姓名列表会先按姓氏排序,然后按名字排序。

标签: java arraylist binary-search treeset


【解决方案1】:
set.tailSet(obj).first();

做你想做的。

【讨论】:

    【解决方案2】:

    您可以将对象存储在TreeMap<Foo, Foo>TreeMap<FooKey, Foo> 中,而不是使用TreeSet(如果您无法在每次要搜索时轻松创建一个新的实际Foo)。 Sets 并非真正用于查找。

    对于FooKey 示例,FooKey 将是一个简单的不可变类,它只包含两个Strings 和Comparable。为两个Strings 找到Foo 的值将是treeMap.get(new FooKey(firstString, secondString)) 的简单问题。这当然会使用您要查找值的树遍历。

    【讨论】:

    • 这看起来是个好方法。谢谢。
    【解决方案3】:

    您应该在对象上实现 Comparable 或创建一个单独的 Comparator 类,在构造 TreeSet 时传入该类。这允许您插入自定义条目比较逻辑并让 TreeSet 进行优化的存储/搜索。

    【讨论】:

    • 当然我要在对象上实现 Comparable。这就是我使用排序集的全部原因。但是这将如何返回我正在搜索的元素?
    • 试试 TreeMap 而不是 TreeSet。
    【解决方案4】:

    我想知道的一件事是您为什么要搜索排序集?如果您希望能够按顺序进行迭代以及快速查找,您可能会受益于将对象存储在两个单独的数据结构中。一个像你的SortedSet<Foo>,然后还有一个HashMap<FooKey,Foo>,类似于ColinD 提到的。然后,您将在 TreeMap 上获得恒定时间查找而不是 log(n)。您必须写入这两个结构的写入惩罚,以及拥有两个数据结构的内存资源惩罚,但您已经完全优化了对数据的访问。

    此外,如果内存资源受到限制,并且您的字符串确实是区分对象的原因,那么您可以在对象 Foo 上实现 hashcode()equals(),然后将它们用作键和值(比如HashMap<Foo,Foo>。需要注意的是,你必须构造一个Foo 来调用getter。

    【讨论】:

    • 如果可能的话,我会避免维护两个包含相同数据的结构,这不是因为写入两者的内存或性能成本,而是因为有必要在您的代码中确保这两个结构始终保持同步。也就是说,使用HashMap 进行查找当然是更可取的。 OP 没有说明为什么他们需要排序结构,所以也许他们实际上不需要,只是认为这将是最有效的。
    【解决方案5】:

    你得到了关于使用可比较/比较器的答案,但我想我会补充一点,你是对的,contains() 进行二进制搜索,尽管你不需要知道这些细节

    【讨论】:

    • 我需要知道这些细节,因为我想尽可能选择最有效的方法。
    • 您通常不应该知道 JDK 中某个接口的特定实现是如何实现的细节。你不能保证它会一直这样。这就是为什么它在接口后面。
    • 但在这种情况下,我不知道是使用二分搜索还是顺序搜索。这是一个很大的不同。
    • @exent:您应该查看 JDK 集合所做的性能保证。例如,TreeMap 声明“此实现为 containsKeygetputremove 操作提供有保证的 log(n) 时间成本”。这是您想要的 log(n) 时间,而不是二进制搜索(二进制搜索特别适用于排序的基于索引的结构,如数组和列表,而不是树)。
    • @ColinD 我以为我描述的树搜索方法也叫二分查找。
    猜你喜欢
    • 2014-03-31
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多