提问人:Alexander Soare 提问时间:3/15/2022 更新时间:3/15/2022 访问量:362
如何使用具有unordered_set的队列作为基础容器
How should I use a queue with an unordered_set as the underlying container
问:
我有一个包含一组 .对于此数据结构,我需要两个重要属性:std::pair<int, int>
- 我可以快速检查设置成员资格。
- 先进先出
因此,作为一名拥有 cppreference.com 的C++初学者,我选择了我所拥有的,并在下面的附录中包括了 的实现。std::queue<std::unordered_set<PointUV, pointUVHash>> frontierPointsUV{};
typedef std::pair<int, int> PointUV;
PointUVHash
我的问题是
- 这是满足上述 2 个要求的明智方法吗?
- 如何查看集合成员资格?我尝试了设置成员资格,但收到“没有成员”错误。
frontierPointsUV.c.contains
- 如何推和弹出(或插入和擦除)?我尝试在任何一个容器上调用这些修饰符都没有成功。
附录 - 哈希实现
struct pointUVHash final
{
// This is a safe hashing function for pointUV because we only ever expect it to have 0 or positive ints
// in ranges well under 2**16
int operator()(const PointUV &p) const
{
return int(p.first) + (int(p.second) << 16);
}
};
答:
2赞
Homer512
3/15/2022
#1
队列适配器需要有序的容器(如 deque 或 list)才能工作。在我看来,它也已经过时了,因为它只从底层容器中删除了功能,并没有添加任何实质内容。
您想要的是两个保持同步的数据结构,例如 one 和 one 。看到如何是一个非常简单的类型,这种组合效果最好。如果开始处理更复杂的类型,并且可能希望避免重复的对象和查找,则可以选择将指针存储在其中一个容器中。unordered_set<pair<int, int> >
deque<pair<int, int> >
pair<int, int>
无论如何,这样的事情应该可以解决问题:
class unique_queue
{
public:
using value_type = std::pair<int, int>;
private:
struct hash: private std::hash<int>
{
std::size_t operator()(const value_type& value) const noexcept
{
if(sizeof(int) >= sizeof(std::size_t)) {
const std::hash<int>& inthash = *this;
return inthash(value.first) * 31 + inthash(value.second);
}
return static_cast<std::size_t>(value.first)
<< ((sizeof(std::size_t) - sizeof(int)) * CHAR_BIT)
+ static_cast<std::size_t>(value.second);
}
};
using set_type = std::unordered_set<value_type, hash>;
using queue_type = std::deque<value_type>;
set_type set;
queue_type queue;
public:
bool push(const value_type& value)
{
std::pair<set_type::iterator, bool> inserted = set.insert(value);
if(! inserted.second) // equal value already contained
return false;
try {
queue.push_back(value);
} catch(...) { // provide exception safety
set.erase(inserted.first);
throw;
}
return true;
}
bool empty() const noexcept
{ return queue.empty(); }
const value_type& front() const noexcept
{ return queue.front(); }
void pop() noexcept
{
set.erase(front());
queue.pop_front();
}
bool contained(const value_type& value) const noexcept
{ return set.count(value) != 0; }
};
我使函数语义在某种程度上接近队列或 deque 提供的内容,例如,如果在空队列上调用,则未定义的行为。front()
如果希望队列中有多个相等的键,最简单的方法是替换为以跟踪队列中有多少个相等的键。像这样的东西:unordered_set<pair<int, int> >
unordered_map<pair<int, int>, size_t>
class set_queue
{
public:
using value_type = std::pair<int, int>;
private:
struct hash: private std::hash<int>
{
std::size_t operator()(const value_type& value) const noexcept
{
if(sizeof(int) >= sizeof(std::size_t)) {
const std::hash<int>& inthash = *this;
return inthash(value.first) * 31 + inthash(value.second);
}
return static_cast<std::size_t>(value.first)
<< ((sizeof(std::size_t) - sizeof(int)) * CHAR_BIT)
+ static_cast<std::size_t>(value.second);
}
};
using map_type = std::unordered_map<value_type, std::size_t, hash>;
using queue_type = std::deque<value_type>;
map_type map;
queue_type queue;
public:
bool push(const value_type& value)
{
std::pair<map_type::iterator, bool> inserted = map.emplace(value, 0);
try {
queue.push_back(value);
} catch(...) { // provide exception safety
if(inserted.second)
map.erase(inserted.first);
throw;
}
inserted.first->second += 1;
return true;
}
bool empty() const noexcept
{ return queue.empty(); }
const value_type& front() const noexcept
{ return queue.front(); }
void pop() noexcept
{
map_type::iterator refcount = map.find(front());
assert(refcount != map.end());
queue.pop_front();
refcount->second -= 1;
if(! refcount->second) // last element of same value
map.erase(refcount);
}
std::size_t count(const value_type& value) const noexcept
{
map_type::const_iterator found = map.find(value);
return found == map.end() ? 0 : found->second;
}
};
评论
0赞
user4581301
3/16/2022
关于队列过时的说明:访问限制使队列有用......当您需要队列时。如果这些限制没有用,您可能不需要队列。
0赞
Homer512
3/16/2022
@user4581301,然后你用队列编写程序,直到你添加一个 queue.clear() 有用的地方。然后,使用 deque 的方法名称略有不同来重写所有内容。耸耸肩。无论什么漂浮着你的船
0赞
user4581301
3/16/2022
这说明您不需要排队。你只是不知道,直到为时已晚。
评论
std::queue
要求用于存储的容器是序列容器,该容器不是其成员。std::unordered_set