C++ C++;-修改所有地图元素的关键点 让我们考虑这个代码: std::map< int, char > charMap; for( auto& i : charMap ) { charMap[ i.first + 1 ] = charMap[ i.first ]; charMap.erase( i.first ); } std::mapcharMap; 用于(自动和输入:字符映射) { charMap[i.first+1]=charMap[i.first]; 字符映射。擦除(i.首先); }

C++ C++;-修改所有地图元素的关键点 让我们考虑这个代码: std::map< int, char > charMap; for( auto& i : charMap ) { charMap[ i.first + 1 ] = charMap[ i.first ]; charMap.erase( i.first ); } std::mapcharMap; 用于(自动和输入:字符映射) { charMap[i.first+1]=charMap[i.first]; 字符映射。擦除(i.首先); },c++,stdmap,C++,Stdmap,假设贴图有一些带有随机键的值。我正试着把钥匙拨1。 这是行不通的,因为循环会永远持续下去。 有没有一种快速的方法可以让它工作?由于两个基本原因,您不能使用这种范围迭代: 第一个原因是,映射的一个基本属性是,对映射的迭代按键顺序进行 您正在地图上迭代。因此,如果映射中的第一个键是键0,则将该值复制到键1。然后,迭代到映射中的下一个键,即刚才创建的键1,然后将其复制到键2。起泡,冲洗,重复 有几种方法可以解决这个问题,但都不重要,因为地图的第二个基本方面: charMap[1]=charMap[0]

假设贴图有一些带有随机键的值。我正试着把钥匙拨1。 这是行不通的,因为循环会永远持续下去。
有没有一种快速的方法可以让它工作?

由于两个基本原因,您不能使用这种范围迭代:

第一个原因是,映射的一个基本属性是,对映射的迭代按键顺序进行

您正在地图上迭代。因此,如果映射中的第一个键是键0,则将该值复制到键1。然后,迭代到映射中的下一个键,即刚才创建的键1,然后将其复制到键2。起泡,冲洗,重复

有几种方法可以解决这个问题,但都不重要,因为地图的第二个基本方面:

charMap[1]=charMap[0];
这将
charMap[0]
处理为
charMap[1]
。它对
charMap[0]
没有任何作用。它还在那里。没发生什么事。因此,假设贴图中最低的关键点是0,并且正确地移动了关键点,那么贴图中仍然会有一个关键点为0的值。地图上的其他一切也一样

但是假设你用几种可以解决的方法之一解决了第一个问题。然后,假设您的贴图具有键0、5和7的值

将0号键复制到1号键、5号键复制到6号键、7号键复制到8号键后,拿一张纸和一支铅笔,找出地图上现在有什么

答:不会是键1、6和8。它将是键0、1、5、6、7和8

您所做的只是将每个值复制到下一个键。这是因为计算机完全按照你的命令去做,不多不少。计算机不会做你想让它做的事

最简单的方法是创建一个新映射,并使用更新的键值将旧映射的内容复制到新映射。您仍然可以使用范围迭代来实现这一点。然后,用新地图替换旧地图

当然,如果地图非常大,这将变得不切实际。在这种情况下,仍然可以在不使用第二个贴图的情况下执行此操作,但算法将有点复杂。总结如下:

1) 按相反的顺序迭代键。无法在此处使用范围迭代


2) 将键复制到映射中的下一个值后,显式删除其原始键中的值。

在C++17中,可以使用节点提取和拼接(请参见P0083R3):

不过,这需要为节点分配内存,因此新的基于拼接的解决方案更有效

在任何一种情况下,我们都可以使用暗示插入,因为我们正在以相同的顺序重建元素,因此最新的元素总是插入到末尾。

使用已知顺序影响的特殊解决方案 您可以简单地选择从最后一个元素开始的反向迭代:

for( auto pi = charMap.end(); pi-- != charMap.begin(); pi=charMap.erase( pi ))
    charMap[ pi->first + 1 ] = charMap[ pi->first ];

这不会在这里永远循环,因为插入的新元素将始终位于当前元素之后,因此不会一次又一次地重新处理


更一般的解决方案 对于更一般的转换,您无法确定对元素顺序的影响,我宁愿选择:

std::map-tmp;
std::transform(charMap.begin(),charMap.end(),std::inserter(tmp,tmp.begin()),
[](自动e){return std::make_pair(e.first+1,e.second);});
std::swap(tmp,charMap);//当tmp超出范围时,旧映射将被丢弃

使用第二个贴图是一个选项吗?这可能会降低复杂性。什么是
std::map::extract
?我找不到它。。。
std::map<int, char> tmpMap;

for (auto & p : charMap)
    tmpMap.emplace_hint(tmpMap.end(), p.first + 1, std::move(p.second));

tmpMap.swap(charMap);
for( auto pi = charMap.end(); pi-- != charMap.begin(); pi=charMap.erase( pi ))
    charMap[ pi->first + 1 ] = charMap[ pi->first ];
std::map<int, char> tmp; 
std::transform(charMap.begin(), charMap.end(), std::inserter(tmp,tmp.begin()), 
                          [](auto e) { return std::make_pair(e.first+1, e.second); });
std::swap(tmp, charMap);    // the old map will be discarded when tmp goes out of scope