我需要一个先进先出队列,该队列保存带有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容器有更优雅的方法吗?
答案 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::set
和std::unordered_set
迭代器未通过添加或删除而无效,则可以获益元素)。
但除非你需要更高的表现,否则不要这样做。您的代码简单易读。