唯一成员资格FIFO容器

时间:2013-12-30 12:58:30

标签: c++ containers std

我需要一个先进先出队列,该队列保存带有catch的ID,如果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容器有更优雅的方法吗?

3 个答案:

答案 0 :(得分:4)

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

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

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

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

您还可以考虑在队列中存储set迭代器而不是值,以使擦除更有效。

答案 1 :(得分:3)

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

答案 2 :(得分:2)

一点也不差。我可以看到其他方法来做到这一点,主要是使用一个容器(因为我看到的唯一“问题”是你正在使用2个容器,所以必须断言它们彼此一致),但是它们不是更优雅,可能会花费更多。

IMHO使用std::unordered_set代替std::set来设计此设计(至少此界面),直到您可以对您的表演进行基准测试。在那之后你可能没有问题,或者std::set中的额外查找可能对你来说太高了。在这种情况下,您可以尝试保留std::queue<std::pair<ID, std::unordered_set<ID>::const_iterator>>以简化擦除(如果std::setstd::unordered_set迭代器未通过添加或删除而无效,则可以获益元素)。

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