在 c++ stl 映射中,删除具有重复值的条目

In c++ stl map, delete entries with duplicate values

本文关键字:stl c++ 映射 删除      更新时间:2023-10-16

考虑地图mymap有条目

<'a', 111>  
<'b', 567>  
<'c', 956>  
<'d', 222>  
<'e', 111>  
<'f', 222>  
<'h', 222>  
<'i', 492> 

等等...
如何删除映射中值重复的条目。
例如,键"a"和"e"的值为 111。因此,保留"a"的映射条目并删除"e"的条目
对于值 222,保留条目"d"并删除条目"f"和"h"。
我正在寻找具有最佳空间和时间复杂性的解决方案

这是一个有趣的问题,如果有点跑题的话。

由于映射的值是可哈希的且相等可比的,因此我们可以在线性时间内执行此操作,使用unordered_set来确定该值之前是否见过:

这段代码是 c++17:

void comb(std::map<char, int>& themap)
{
std::unordered_set<int> seen;
seen.reserve(themap.size());
// iterate through the map in key order...
auto current = begin(themap);
const auto last = end(themap);
while(current != last)
{
auto&&[key, value] = *current;
// try to insert the value into the 'seen' set.
if (seen.insert(value).second)
// if we succeeded, then we're the first ocurrence of the
// value so move to next node
++current;
else
// otherwise, erase this node and move to the next
// (idiomatic method)
current = themap.erase(current);
}
}

你可能想要这样的东西:

#include <iostream>
#include <map>
#include <set>
int main() {
std::map<char, int> mymap
{
{'a', 111}, {'b', 567}, {'c', 956}, {'d', 222}, 
{'e', 111}, {'f', 222}, {'h', 222}, {'i', 492},
};
std::set<int> existingvalues;
for (auto it = mymap.begin(); it != mymap.end(); it++)
{
if (existingvalues.find(it->second) != existingvalues.end())
mymap.erase(it--);                  // value already encountered => remove entry
else
existingvalues.insert(it->second);  // value not yet encountered => remeber it
}
for (auto it = mymap.begin(); it != mymap.end(); it++)
std::cout << "<'" << it->first << "', " << it->second << ">n";
}

这是另一种可能的解决方案,涉及遍历 map 容器 2 次,如果有重复值,第二次迭代的元素将更少:

#include <iostream> 
#include <algorithm>
#include <map>
template <typename T, typename U>
void RemoveDuplicateValues(std::map<T, U> &m)
{
std::map<U, T> tmp;
std::for_each(m.rbegin(), m.rend(), [&tmp](auto const &p)
{
tmp[p.second] = p.first;
});
m.clear();
for (auto const &p : tmp)
m[p.second] = p.first;
}
int main()
{
std::map<char, int> m
{
{ 'a', 111 },{ 'b', 567 },{ 'c', 956 },{ 'd', 222 },
{ 'e', 111 },{ 'f', 222 },{ 'h', 222 },{ 'i', 492 }
};
RemoveDuplicateValues(m);
// test
for (auto const &p : m)
std::cout << p.first << " " << p.second << std::endl;
return 0;
}

演示:https://ideone.com/oThy17

a 111
b 567
c 956
d 222
i 492