【问题标题】:Getting the rightmost element in an unordered_set (or print the contents in reverse)获取 unordered_set 中最右边的元素(或反向打印内容)
【发布时间】:2011-12-03 05:27:33
【问题描述】:

我有一个 unordered_set 如下:

unordered_set <long> valueSet;

/*the following insertion is done in order (from 1 to 10000), 
 *unordered_set will keep the elements based on the insertion order, right, 
 *just like in a vector ?
**/

for(long i = 1; i <= 10000;++i)
{
        valueSet->insert(i);
}

然后我执行了另一个函数,删除了 unordered_set 中大约 85% 的元素。 (要擦除的元素取决于该函数的逻辑,但并不重要,因为所有元素最初都是按顺序插入的。

现在,在删除 unordered_set 中的一些元素之后,我想打印仍然保留在 unordered_set 中的最后一个元素。例如,元素 9997、9998、9999 和 10000 已被擦除,因此该集合中剩余的最大元素是 9996。 如何做到这一点?
如果使用基本套装,我可以执行以下操作:

set <long>::reverse_iterator it = valueSet.rbegin();
cout << *it << endl;

在一个集合中,我们有 reverse_iterator 和 rbegin(),但这在 unordered_set 中不存在。我之所以没有基本设置是因为我需要将元素大小放大到 10^8。使用常规集(基于红黑树)确实会降低性能(尤其是在处理插入和删除时)。 我怎样才能做到这一点?将最后剩余的 unordered_set 复制到向量中会起作用,但这当然需要时间。我怎样才能通过使用更智能的方式来实现这一目标?我注意到我也不能做类似的事情:

unordered_set <long>::iterator it = valueSet.end();
//operator -- does not exist here in the unordered_set
it--;

【问题讨论】:

  • 你想吃你的蛋糕。当您从 set 切换到 unordered_set 时,您放弃了某些好处,您无法收回这些好处。
  • 还有其他替代数据结构可以让我这样做吗?我只想得到最后一个元素,而不是按顺序打印所有元素(如集合)。例如来自 Boost 或 Google 的其他数据结构实现?
  • 最后一个元素是指“最近添加的”吗?这很简单,只需包装现有的数据结构,但缓存最近添加的元素。如果你还有别的意思,你需要一棵树。
  • 我刚刚在您的代码中注意到这条注释:“unordered_set 将根据插入顺序保留元素,对吧,就像在向量中一样?” 不,它不会.
  • @all_by_grace:它证明了它在特定情况下保留了顺序,它不证明它作为一般规则这样做。例如:ideone.com/LNwDn

标签: c++ set unordered-set


【解决方案1】:

根据我从您的 cmets 收集到的信息,在这里使用 std::bitset 或其动态对应物 boost::dynamic_bitset 应该是合适的。你得到 O(1) 插入和删除和 O(N) 来确定最大元素(通过线性搜索)。甚至有人可能会争辩说,找到最大值是摊销 O(1),因为您最多必须执行与删除操作一样多的搜索步骤。

【讨论】:

  • 我喜欢使用bitset的想法,它大大提高了性能。谢谢!!
【解决方案2】:

无序集旨在无序。您应该假设您在使用它的迭代器时看到它的元素的顺序是任意/不确定的。这意味着任何关于订单的特定行为根据定义都是不可移植的并且完全是特定于实现的。它现在可能恰好是有序的,但经过足够的操作后,它可能是另一个顺序。他们给你一个迭代器的唯一原因是允许你以任意顺序逐个元素地处理它。

为什么不从一开始就使用 std::vector?

【讨论】:

  • 是的,没错。问题是我不做任何会改变元素顺序的操作。因为我只需要在开头插入(比方说:从 1 到 1000000 的有序元素),然后我将只进行删除操作,不再进行插入。 std::vector 移除元素的速度很慢(尤其是在中间或开头移除)。 Unordered_set 允许我在 O(1) 中插入和删除,因为它是使用哈希表实现的。
  • 当你说“一开始”时,你仍然在想“有序”。听起来你想要某种树,也许是 B+ 树。
  • 我说的是“一开始”,意思是我只插入了所有元素一次(并且我不会违反这个规则),并且不会在这个集合中插入任何其他值,但我只会删除一些现有值(这不会改变顺序,因为不再进行插入)。我正在寻找一种更智能的方法,例如通过使用指针获取对最后一个值的内存位置的引用,然后打印该元素。呼……
【解决方案3】:

你不能吃掉你的蛋糕。

无序容器以无序的方式存储它们的元素(通常在 hash table 中),因此您无法以可预测的方式迭代它们。特别是,它们不会按照插入的顺序存储元素

如果您不关心顺序,那么您最好使用std::dequestd::vector(如果您必须在前面插入,请选择前者)。

【讨论】:

  • 是的,没错!在一般情况下,它不会按插入顺序存储元素。但它确实如此,当所有值也按顺序插入时(1、2、3、4、5、......、10000)。 Deque 或向量不允许在 O(1) 中删除 :-) 我只是受到 Java LinkedHashSet 的启发,它与常规 HashSet 区分开来,因为它保留了顺序。无论如何,谢谢!!
  • 但是向量和双端队列可以让你在恒定时间内清除一个项目,这会让你达到同样的目的。
【解决方案4】:

将删除的项目存储在向量中。完成后,转换为堆。 (O(n),其中 n 是已删除项的数量)然后重复从堆中删除最大值,直到找到未删除的最高元素。这是 O(m log n),其中 m 是您的最大值与答案之间的差。

【讨论】:

    猜你喜欢
    • 2020-09-29
    • 2018-07-27
    • 2013-06-05
    • 2020-09-05
    • 2023-01-12
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    相关资源
    最近更新 更多