在c+中具有唯一条目的队列+; 我需要在C或C++中实现包含唯一条目(没有重复)的队列。我正在考虑维护队列中已有元素的引用,但这似乎效率很低
请告诉我您对此的建议。排队:在c+中具有唯一条目的队列+; 我需要在C或C++中实现包含唯一条目(没有重复)的队列。我正在考虑维护队列中已有元素的引用,但这似乎效率很低,c++,c,data-structures,C++,C,Data Structures,请告诉我您对此的建议。排队: 使用std::set维护您的唯一元素集 将能够添加到std::set的任何元素添加到std::queue 退出队列: 从std::queue和std::set中删除元素 跟踪唯一性的辅助数据结构如何: std::queue<Foo> q; std::set<std::reference_wrapper<Foo>> s; // to add: void add(Foo const & x) { if (s.
- 使用std::set维护您的唯一元素集
- 将能够添加到std::set的任何元素添加到std::queue
- 从std::queue和std::set中删除元素
std::queue<Foo> q;
std::set<std::reference_wrapper<Foo>> s;
// to add:
void add(Foo const & x)
{
if (s.find(x) == s.end())
{
q.push_back(x);
s.insert(std::ref(q.back())); // or "s.emplace(q.back());"
}
}
std::队列q;
std::集s;
//加上:
无效添加(Foo const&x)
{
如果(s.find(x)=s.end())
{
q、 推回(x);
s、 插入(std::ref(q.back());//或“s.emplace(q.back());”
}
}
或者,颠倒队列和集合的角色:
std::set<Foo> s;
std::queue<std::reference_wrapper<Foo>> q;
void add(Foo const & x)
{
auto p = s.insert(x); // std::pair<std::set<Foo>::iterator, bool>
if (s.second)
{
q.push_back(std::ref(*s.first)); // or "q.emplace_back(*s.first);"
}
}
std::set s;
std::队列q;
无效添加(Foo const&x)
{
自动p=s.insert(x);//std::pair
如果(秒)
{
q、 向后推(std::ref(*s.first));//或“q.emplace_back(*s.first);”
}
}
std::queue
是一个容器适配器,使用的底层容器的成员相对较少。您可以轻松地实现一个自定义容器,该容器包含两个部分:一个reference\u包装的unordered\u map
和一个deque
。它至少需要成员front
和push_back
。当调用容器的push_back
时,检查内部的hash_映射
,并相应地拒绝(可能抛出)。要给出完整的示例,请执行以下操作:
#include <iostream>
#include <set>
#include <deque>
#include <queue>
#include <unordered_set>
#include <functional>
namespace std {
// partial specialization for reference_wrapper
// is this really necessary?
template<typename T>
class hash<std::reference_wrapper<T>> {
public:
std::size_t operator()(std::reference_wrapper<T> x) const
{ return std::hash<T>()(x.get()); }
};
}
template <typename T>
class my_container {
// important: this really needs to be a deque and only front
// insertion/deletion is allowed to not get dangling references
typedef std::deque<T> storage;
typedef std::reference_wrapper<const T> c_ref_w;
typedef std::reference_wrapper<T> ref_w;
public:
typedef typename storage::value_type value_type;
typedef typename storage::reference reference;
typedef typename storage::const_reference const_reference;
typedef typename storage::size_type size_type;
// no move semantics
void push_back(const T& t) {
auto it = lookup_.find(std::cref(t));
if(it != end(lookup_)) {
// is already inserted report error
return;
}
store_.push_back(t);
// this is important to not have dangling references
lookup_.insert(store_.back());
}
// trivial functions
bool empty() const { return store_.empty(); }
const T& front() const { return store_.front(); }
T& front() { return store_.front(); }
void pop_front() { lookup_.erase(store_.front()); store_.pop_front(); }
private:
// look-up mechanism
std::unordered_set<c_ref_w> lookup_;
// underlying storage
storage store_;
};
int main()
{
// reference wrapper for int ends up being silly
// but good for larger objects
std::queue<int, my_container<int>> q;
q.push(2);
q.push(3);
q.push(2);
q.push(4);
while(!q.empty()) {
std::cout << q.front() << std::endl;
q.pop();
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
名称空间标准{
//引用包装器的部分专门化
//这真的有必要吗?
模板
类散列{
公众:
std::size\u t运算符()(std::reference\u wrapper x)常量
{return std::hash()(x.get());}
};
}
模板
类我的容器{
//重要提示:这真的需要一个deque,并且只需要一个front
//允许插入/删除以不获取悬挂引用
typedef std::deque存储;
typedef std::reference_wrapper c_ref_w;
typedef std::reference_wrapper ref_w;
公众:
typedef typename存储::值\类型值\类型;
typedef typename存储::引用引用;
typedef typename存储::const_reference const_reference;
typedef typename存储::大小\类型大小\类型;
//不动语义
无效推回(施工T&T){
autoit=lookup.find(std::cref(t));
if(it!=结束(查找){
//已插入报告错误
返回;
}
存储。推回(t);
//这一点很重要,不要有悬空的引用
查找\插入(存储\返回());
}
//平凡函数
bool empty()常量{return store_uu.empty();}
const T&front()const{return store_uu.front();}
T&front(){return store_uu.front();}
void pop_front(){lookup_.erase(store_.front());store_.pop_front()}
私人:
//查找机制
std::无序集查找;
//底层存储
储藏室;
};
int main()
{
//int的引用包装器最终是愚蠢的
//但对更大的物体有好处
std::队列q;
q、 推(2);
q、 推(3);
q、 推(2);
q、 推(4);
而(!q.empty()){
std::cout有一点您在问题中没有提到,那就是您的项目队列是排序的,还是具有某种排序的(称为a),还是未排序的(称为普通FIFO)。您选择的解决方案将仅取决于此问题的答案
如果您的队列未排序,则在队列之外维护一个额外的数据结构将更有效。使用以某种方式排序的第二个结构来维护队列的内容将允许您检查队列中是否已存在项目,或者检查项目是否比扫描队列本身快得多。添加到末尾对未排序队列的排序需要固定的时间,并且可以非常高效地完成
如果必须对队列进行排序,则将项目放入队列需要知道项目在队列中的位置,这就需要对队列进行扫描。一旦知道项目的位置,就可以知道项目是否是重复的,因为如果项目是重复的,那么项目将已经存在于队列中的该位置在这种情况下,所有工作都可以在队列本身上以最佳方式执行,并且不需要维护任何辅助数据结构
数据结构的选择取决于您。但是,对于(1)二级数据结构不应是任何类型的列表或数组,否则扫描二级索引的效率将不如扫描原始队列本身的效率高。您尝试了什么?您是否会保留对已存在成员的引用?为什么效率低下?如果您真的需要队列的FIFO行为以及唯一性,请ps一个Boost multi_index容器是一个合适的选择。队列维护的项目是排序的还是未排序的?如果要对队列中的项目进行排序,那么维护任何类型的辅助引用都不是绝对必要的。为什么不使用自定义容器进行自适应?您没有询问OP是否必须对队列进行排序。如果队列sn未排序则索引是无用的,因为在添加项目之前,必须扫描队列以找到项目的插入位置。@aps2012:排序队列的意义是什么?队列的定义就是FIFO容器。你错了。队列不是严格的FIFO。任何类型的(每个项目都有一个优先级的队列)按照分配给每个项目的优先级执行一个顺序进行排序。在你否决其他人的答案之前,请检查事实。@aps2012我假设OP需要一个priority\u队列
。它不也需要pop\u front
(或者更确切地说,push
和pop
)?@KerrekSB啊,是的,只是