【发布时间】:2025-12-23 07:15:08
【问题描述】:
是否有一种简单或标准的方法来让多图迭代器遍历多图中的唯一键?
即对于一组看起来像:{1, "a"}, {1, "lemon"}, {2, "peacock"}, {3, "angel"}
一个从{1, "a"}开始然后递增将指向{2, "peacock"}然后再次递增将指向{3, "angel"}的迭代器?
【问题讨论】:
是否有一种简单或标准的方法来让多图迭代器遍历多图中的唯一键?
即对于一组看起来像:{1, "a"}, {1, "lemon"}, {2, "peacock"}, {3, "angel"}
一个从{1, "a"}开始然后递增将指向{2, "peacock"}然后再次递增将指向{3, "angel"}的迭代器?
【问题讨论】:
您可以使用upper_bound 代替++ 来增加迭代器位置:
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
multimap<int,string> mm;
mm.insert(make_pair(1, "a"));
mm.insert(make_pair(1, "lemon"));
mm.insert(make_pair(2, "peacock"));
mm.insert(make_pair(3, "angel"));
for( auto it = mm.begin(), end = mm.end();
it != end;
it = mm.upper_bound(it->first)
)
cout << it->first << ' ' << it->second << endl;
return 0;
}
这个results in:
1 a
2 peacock
3 angel
【讨论】:
使用upper_bound 会导致一个易于阅读的循环,但每次调用都会执行二叉树搜索,结果是 O(n log n) 而不是 O( n) 遍历。如果效率差异很重要,您可以像这样构造遍历:
typedef std::multimap<std::string, int> MapType;
MapType container;
for (MapType::iterator it = container.begin(); it != container.end(); ) {
std::string key = it->first;
doSomething(key);
// Advance to next non-duplicate entry.
do {
++it;
} while (it != container.end() && key == it->first);
}
【讨论】:
while(true) + goto 版本:*.com/a/41523639/895245
如果您必须快速传递所有唯一键,则可以使用 std::map 代替;
typedef std::map< KeyType, std::list< ValueType > > MapKeyToMultiValue;
插入会更困难,但是您可以遍历所有键,而不必担心重复的条目。插入将如下所示:
void insert_m(MapKeyToMultiValue &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< MapKeyToMultiValue::iterator, bool > ret =
map.insert( MapKeyToMultiValue::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
或者你可以把它做成模板:
template<typename KeyType, typename ValueType,
typename MapType = std::map< KeyType, std::list< ValueType > > >
void insert_multi( MapType &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< typename MapType::iterator, bool > ret =
map.insert( typename MapType::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
完整的测试程序如下:
#include <map>
#include <list>
#include <string>
#include <stdio.h>
typedef std::string KeyType;
typedef int ValueType;
typedef std::map< KeyType, std::list< ValueType > > MapKeyToMultiValue;
void insert_m(MapKeyToMultiValue &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< MapKeyToMultiValue::iterator, bool > ret =
map.insert( MapKeyToMultiValue::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
template<typename KeyType, typename ValueType,
typename MapType = std::map< KeyType, std::list< ValueType > > >
void insert_multi( MapType &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< typename MapType::iterator, bool > ret =
map.insert( typename MapType::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
int main()
{
MapKeyToMultiValue map;
insert_m(map, std::string("aaa"), 1 );
insert_m(map, std::string("aaa"), 2 );
insert_m(map, std::string("bb"), 3 );
insert_m(map, std::string("cc"), 4 );
insert_multi(map, std::string("ddd"), 1 );
insert_multi(map, std::string("ddd"), 2 );
insert_multi(map, std::string("ee"), 3 );
insert_multi(map, std::string("ff"), 4 );
for(auto i = map.begin(); i != map.end(); ++i)
{
printf("%s\n", i->first.c_str() );
}
return 0;
}
【讨论】:
std::map<int, std::list<int> > map; 的插入只是 map[1].push_back(2); 。如果operator[]查找没有找到,则默认构造列表,这里很方便。
可运行示例
这是对https://*.com/a/24212648/895245 的轻微改进,带有可运行的单元测试:
#include <cassert>
#include <map>
#include <vector>
int main() {
// For testing.
auto m = std::multimap<int, int>{
{1, 2},
{1, 3},
{2, 4}
};
std::vector<int> out;
// The algorithm.
auto it = m.begin();
auto end = m.end();
while (it != end) {
auto key = it->first;
// Do what you want to do with the keys.
out.push_back(key);
do {
if (++it == end)
break;
} while (it->first == key);
}
// Assert it worked.
assert(out == std::vector<int>({1, 2}));
}
【讨论】:
key 的更新,代码将无法正常工作。请确保编译并运行它;-)
it == end 比较,即使这需要 goto。
如所选答案中所述,重复使用 multimap::upper_bound 会导致 O(n log n) 遍历地图。使用外部 upper_bound 函数可以得到 O(n)。但是,您需要确保只比较地图的键:
std::multimap<int, std::string> myMap = ... ;
const auto compareFirst = [](const std::pair<const int, std::string>& lhs, const std::pair<const int, std::string>& rhs) {
return lhs.first < rhs.first;
};
for(auto it = myMap.begin(); it != myMap.end(); it = std::upper_bound(it, myMap.end(), *it, compareFirst)) {
// Do stuff...
}
基本方法与 user3701170 的解决方案基本相同 - 即线性搜索 - 但我们将增量步骤放在 for 语句中,而不是循环体。除了将增量放在“通常”存在的位置之外,这还意味着循环中的任何 continue 语句都将按预期运行。
【讨论】:
【讨论】:
equal_range 在条目中采用多映射键...所以如果需要检索键则不好...