有没有办法在地图中找到一个不存在的密钥?
我正在使用std::map<int,myclass>
,我想自动生成新项目的密钥。可以从插图中以不同的顺序从地图中删除项目。
myclass项目可能或可能不相同,因此它们不能作为自己的密钥。
在程序运行期间,生成和删除的项目数量没有限制,因此我不能使用计数器作为密钥。
具有相同功能和性能的替代数据结构可以。
修改
我尝试为我的项目构建一个容器 - 这样我就可以根据他们的键删除/修改项目,我可以迭代这些项目。键值本身对我没有任何意义,但是,其他对象将存储这些键以供其内部使用。
我不能使用增量计数器的原因是,在程序的生命周期中它们可能超过2 ^ 32(或理论上为2 ^ 64)项,但是物理0理论上可能仍然存在项目已删除。
向std :: map询问最低值的未使用密钥会很好,所以我可以将它用于新项目,而不是使用向量或其他外部存储用于未使用的密钥。
答案 0 :(得分:4)
我建议使用计数器和队列的组合。从地图中删除项目时,将其键添加到队列中。然后,队列会跟踪已从地图中删除的密钥,以便可以再次使用它们。要获取新密钥,首先要检查队列是否为空。如果不是,请关闭顶部索引并使用它,否则使用计数器获取下一个可用密钥。
答案 1 :(得分:3)
让我看看我是否理解。你想要做的是
寻找钥匙。 如果不存在,请插入元素。
可能会删除项目。
保持一个计数器(等待等待)和一个向量。向量将保留已删除项目的ID。 当您要插入新元素时,请在向量中查找键。如果vector不为空,请移除该键并使用它。如果它是空的,从柜台拿一个(计数器++)。 但是,如果您从地图中删除项目,则只会停留在计数器上。
替代: 如何使用元素的内存地址作为键?
答案 2 :(得分:2)
有没有找到不存在的方法 键入地图?
我不确定你的意思。你怎么能找到不存在的东西?你的意思是,有没有办法判断地图是否包含密钥?
如果这就是你的意思,你只需使用find
函数,如果该键不存在,它将返回一个指向end()
的迭代器。
if (my_map.find(555) == my_map.end()) { /* do something */ }
你继续说...
我正在使用std :: map,和 我想自动生成一个密钥 对于新项目。项目可能会被删除 来自地图的顺序不同 他们的插入。 myclass项目可能或可能不相同,因此它们不能作为自己的密钥。
我有点不清楚你要在这里完成什么。您的问题似乎是您希望在地图中存储myclass
的实例,但由于您可能有myclass
的重复值,因此需要某种方法来生成唯一键。为什么不使用std::multiset<myclass>
而只是存储重复项,而不是这样做?当您查找myclass
的特定值时,multiset将向所有具有该值的myclass
实例返回一个迭代器。您只需要为myclass
实现比较仿函数。
答案 3 :(得分:2)
我想说的是,对于一般情况,当key可以具有map允许的任何类型时,这是不可能的。甚至能够说出是否存在一些未使用的密钥需要一些关于类型的知识。
如果我们考虑使用int的情况,你可以存储未使用的密钥的std ::连续段的集合(因为这些段不重叠,可以使用自然排序 - 只需比较它们的起点)。当需要新密钥时,您将获取第一个段,切断第一个索引并将其余部分放在集合中(如果其余部分不为空)。当释放某个键时,您会发现集合中是否存在邻居段(由于设置性质,可能具有O(log n)复杂度)并在需要时执行合并,否则只需将[n,n]段放入集合中。
通过这种方式,您肯定会有相同的时间复杂度和内存消耗顺序,因为映射在请求历史记录中是独立的(因为段数不能超过map.size()+ 1)
类似的东西:
class TKeyManager
{
public:
TKeyManager()
{
FreeKeys.insert(
std::make_pair(
std::numeric_limits<int>::min(),
std::numeric_limits<int>::max());
}
int AlocateKey()
{
if(FreeKeys.empty())
throw something bad;
const std::pair<int,int> freeSegment=*FreeKeys.begin();
if(freeSegment.second>freeSegment.first)
FreeKeys.insert(std::make_pair(freeSegment.first+1,freeSegment.second));
return freeSegment.first;
}
void ReleaseKey(int key)
{
std:set<std::pair<int,int>>::iterator position=FreeKeys.insert(std::make_pair(key,key)).first;
if(position!=FreeKeys.begin())
{//try to merge with left neighbour
std::set<std::pair<int,int>>::iterator left=position;
--left;
if(left->second+1==key)
{
left->second=key;
FreeKeys.erase(position);
position=left;
}
}
if(position!=--FreeKeys.end())
{//try to merge with right neighbour
std::set<std::pair<int,int>>::iterator right=position;
++right;
if(right->first==key+1)
{
position->second=right->second;
FreeKeys.erase(right);
}
}
}
private:
std::set<std::pair<int,int>> FreeKeys;
};
答案 4 :(得分:0)
请您说明为什么不能使用简单的增量计数器作为自动生成的密钥? (插入时增加)?这似乎没有问题。
答案 5 :(得分:0)
实际发布的问题仍然存在“如何基于非计数器制作高效的发电机”。您可能希望再次查看“无穷大”要求,并检查64位或128位计数器是否仍能在1000年的有限时间内满足您的算法。
答案 6 :(得分:0)
使用uint64_t
作为关键类型的序列,或者即使您认为它还不够
struct sequence_key_t {
uint64_t upper;
uint64_t lower;
operator++();
bool operator<()
};
像:
sequence_key_t global_counter;
std::map<sequence_key_t,myclass> my_map;
my_map.insert(std::make_pair(++global_counter, myclass()));
你不会有任何问题。
答案 7 :(得分:0)
和其他人一样,我很难搞清楚你想要什么。听起来你想要创建一个项目,如果找不到它。 sdt :: map :: operator [](const key_type&amp; x)将为您完成此任务。
std::map<int, myclass> Map;
myclass instance1, instance2;
Map[instance1] = 5;
Map[instance2] = 6;
这是你在想什么?
答案 8 :(得分:0)
与其他答案一起,我建议使用一个简单的计数器来生成id。如果您担心完全正确,可以使用计数器的任意精度整数,而不是内置类型。或类似以下内容,它将遍历所有可能的字符串。
void string_increment(std::string& counter)
{
bool carry=true;
for (size_t i=0;i<counter.size();++i)
{
unsigned char original=static_cast<unsigned char>(counter[i]);
if (carry)
{
++counter[i];
}
if (original>static_cast<unsigned char>(counter[i]))
{
carry=true;
}
else
{
carry=false;
}
}
if (carry)
{
counter.push_back(0);
}
}
e.g。所以你有:
std::string counter; // empty string
string_increment(counter); // now counter=="\x00"
string_increment(counter); // now counter=="\x01"
...
string_increment(counter); // now counter=="\xFF"
string_increment(counter); // now counter=="\x00\x00"
string_increment(counter); // now counter=="\x01\x00"
...
string_increment(counter); // now counter=="\xFF\x00"
string_increment(counter); // now counter=="\x00\x01"
string_increment(counter); // now counter=="\x01\x01"
...
string_increment(counter); // now counter=="\xFF\xFF"
string_increment(counter); // now counter=="\x00\x00\x00"
string_increment(counter); // now counter=="\x01\x00\x00"
// etc..
答案 9 :(得分:0)
另一种选择,如果地图中实际工作集足够小,则使用递增键,然后在计数器即将换行时重新生成键。该解决方案仅需要临时额外存储。哈希表的性能将保持不变,密钥生成只是一个if和一个增量。
当前工作集中的项目数确实可以确定这种方法是否可行。