【问题标题】:Getting biggest element in TreeSet O(1) time?在 TreeSet O(1) 时间内获取最大元素?
【发布时间】:2016-10-04 15:08:22
【问题描述】:

调用 last() 会给我带来最大的元素,但它是 O(logN) 时间,我知道在 C++ 中我可以利用迭代器并且调用 rbegin() 是恒定时间,我可以用 Java 实现这个恒定时间吗TreeSet 什么时候获取最大元素?

C++ 示例代码:

set<int> s;

s.insert(5);
s.insert(3);
s.insert(7);
... // say I inserted a total of n elements.
s.insert(0);
s.insert(9999);

cout<<*s.begin()<<endl;  //0
cout<<*s.rbegin()<<endl; //9999

【问题讨论】:

  • 我认为您稍微误解了 rbegin() 是“恒定时间”的含义。我认为文档暗示实际获取迭代器本身是常数时间,但我的猜测是实际上 iterating 仍然是对数的。或者,可以通过分别存储/更新指向底层树最左边和最右边元素的额外指针来优化获取第一个/最后一个元素。 set 作者有可能这样做了,尽管我不相信 TreeSet 作者有。也就是说,如果你愿意,这是一个微不足道的增强。
  • 要获得最大元素我只需要调用*s.rbegin() 所以我真的不需要迭代。对了,我自己跟踪最大值就可以解决了,就是想问问TreeSet作者是不是已经搞定了。
  • 返回的迭代器对象可能重载了 * 运算符,因此在不了解其实现的情况下,我认为这不能证明获取最后一个元素实际上是 O(1) 整体。也就是说,这并不重要,因为TreeSet 绝对不是。以某种方式跟踪最大/最小的自己仍然是您的最佳选择。
  • 您可以实现一个扩充的平衡树,并在每次删除和插入操作时对其进行维护。如果您在每个节点中都有一个最大属性更改它只会影响它们的祖先,因此删除和插入应该保持 O(lg(n))。

标签: java c++ iterator binary-search-tree hashset


【解决方案1】:

TreeSet 不跟踪提供对最大元素的恒定时间访问所需的额外数据。这不太可能影响使用 TreeSet 的任何算法的时间复杂度,因为您必须执行更多的 last() 调用而不是 add() 或 remove() 调用才能更改时间复杂度。

如果您确实执行了如此多的last() 调用,这很重要,您可以自己缓存last() 结果,并且仅当您在上次调用后修改了集合时才重新计算它。或者,PriorityQueue 可能更适合您的用例。

(std::set确实跟踪此数据的事实意味着它必须对重组集合的操作执行额外的工作,即使您不需要它。)

【讨论】:

  • 我有大约相同数量的插入/擦除随机元素并获得最大操作数,而 PriorityQueue 对擦除操作不利。 TreeSet 要好得多,如果我真的想要 O(1),我似乎必须自己跟踪 max 。谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-10-07
  • 2012-08-16
  • 1970-01-01
  • 1970-01-01
  • 2012-10-24
  • 1970-01-01
  • 2018-05-23
  • 1970-01-01
相关资源
最近更新 更多