唯一的成员资格 FIFO 容器

Unique membership FIFO container

本文关键字:FIFO 容器 成员 唯一      更新时间:2023-10-16

我需要一个先进先出的队列,该队列包含ID并捕获仅当ID尚未在队列中时才应添加。

我能想到的最好的方法是:

typedef unsigned ID;
struct UniqueFifo
{
private:
   std::set<ID> ids; // keep track of what is already in
   std::queue<ID> fifo; // keep in fifo order
public:
   void push(ID x) {
       // only add to queue if not already in it
       if(ids.find(x) == ids.end()) {
           fifo.push(x);
           ids.insert(x);
       }
   }
   ID pop() {
       // pop from queue
       ID x = fifo.front();
       fifo.pop();
       // and also remove from map
       ids.erase(x);
       return x;
   }
};

有没有更优雅的方法可以使用C++ STL 容器来做到这一点?

使用像这样的第二种数据结构,针对插入和搜索进行了优化,是最具可扩展性的解决方案;但是,如果队列永远不会变得特别大,那么在队列本身中进行线性搜索可能会更有效(当然也更简单)。您需要deque本身,而不是queue适配器才能访问内容。

如果它足够大,可以证明可搜索的"索引"是合理的,那么考虑使用unordered_set(如果可用)或其他一些基于哈希的集合(如果不是);如果你只需要唯一性而不是任何特定的排序,这可能会更快。

代码需要将 ID 插入到集合和队列中。方便的是,您可以将其与唯一性检查相结合,这样只需要一次搜索:

if (ids.insert(x).second) {
    fifo.push(x);
}

您还可以考虑在队列中存储集合迭代器而不是值,以提高擦除效率。

你的解决方案还不错,但你需要使用std::set<ID>,而不是std::map(映射用于将键映射到值,而你只关心这里的值)。如果c++11可用,还可以考虑使用 std::unordered_set

一点也不差。我可以看到其他方法可以做到这一点,主要是使用一个容器(因为我看到的唯一"问题"是你使用 2 个容器,因此必须一直断言它们彼此一致),但它们并不更优雅,可能成本更高。

恕我直言,使用std::unordered_set而不是std::set来控制此设计(至少是此界面),直到您可以对性能进行基准测试。之后,您可能没有问题,或者std::set中的额外查找对您来说太高了。在这种情况下,您可以尝试保留std::queue<std::pair<ID, std::unordered_set<ID>::const_iterator>>以简化擦除(如果删除不在 there元素上,则std::setstd::unordered_set迭代器不会因添加或删除而失效)。

但除非你需要更好的表现,否则不要这样做。您的代码简单易读。