C++ multimap(STL multimap)的使用详解
multimap 大部分成员函数的使用方式和 map 相同。因为重复键的原因,multimap 有一些函数的使用方式和 map 有一些区别。接下来介绍 multimap 和 map 容器不同的那些成员函数的用法。
multimap 容器的成员函数 insert() 可以插入一个或多个元素,而且插入总是成功。这个函数有很多的版本都可以插入单个元素,它们都会返回一个指向插入元素的迭代器。下面有一个示例,假设我们已经使用了声明 using std::string:
- std::multimap<string, string〉 pets; // Element is pair{pet_type, pet_name}
- auto iter = pets.insert (std::pair<string, string>{string{"dog"}, string{"Fang"}});
- iter = pets.insert(iter, std::make_pair("dog", "Spot")); // Insert Spot before Fang
- pets.insert(std::make_pair("dog", "Rover"));// Inserts Rover after Fang
- pets.insert (std::make_pair ("cat", "Korky"));// Inserts Korky before all dogs
- pets.insert ({{ "rat", "Roland"}, {"pig", "Pinky" }, {"pig", "Perky"}});//Inserts list elements
和 map —样,multimap 的成员函数 emplace() 可以在容器的适当位置构造元素。在插入具有相同键的元素时,可以使用 multimap 的成员函数 emplace_hint(),可以通过为这个函数提供一个迭代器形式的提示符来控制元素的生成位置:
- auto iter = pets.emplace("rabbit”,"Flopsy");
- iter = pets.emplace_hint (iter, "rabbit", "Mopsy");// Create preceding Flopsy
multimap 不支持下标运算符,因为键并不能确定一个唯一元素。和 map 相似,multimap 也不能使用 at() 函数。multimap 的成员函数 fmd() 可以返回一个键和参数匹配的元素的迭代器。例如:
- std::multimap<std::string, size_t> people {{"Ann",25},{"Bill", 46}, {"Jack", 77}, {"Jack", 32},{"Jill", 32}, {"Ann", 35} };
- std::string name {"Bill"};
- auto iter = people.find(name);
- if (iter ! = std::end (people))
- std::cout << name << " is " << iter->second << std::endl;
- iter = people.find ("Ann");
- if (iter != std::end(people))
- std::cout << iter->first << " is " << iter->second <<std::endl;
如果使用 multimap 容器,几乎可以肯定它会包含键重复的元素;否则,就应该使用 map。一般来说,我们想访问给定键对应的所有元素。成员函数 equal_range() 就可以做到这一点。它会返回一个封装了两个迭代器的 pair 对象,这两个迭代器所确定范围内的元素的键和参数值相等。例如:
- auto pr = people.equal_range("Ann");
- if(pr.first != std::end(people))
- {
- for (auto iter = pr.first ; iter != pr.second; ++iter)
- std:cout << iter->first << " is " << iter->second << std::endl;
- }
pair 的成员变量 second 也是一个迭代器,它指向键值大于参数的第一个参数;如果没有这样的元素,它会是一个结束迭代器。这段代码会输出容器中键值为”Ann”的元素的一些信息。
multimap 的成员函数 lower_bound() 会返回一个迭代器,它指向键值和参数相等或大于参数的第一个元素,或者指向结束迭代器。upper_bound() 也返回一个迭代器,它指向键值大于函数参数的第一个元素,如果这样的元素不出现的话,它就是一个结束迭代器。所以,当存在一个或多个相等键时,这些函数会返回一个开始迭代器和一个结束迭代器,它们指定了和参数匹配的元素的范围,这和 equal_range() 返回的迭代器是相同的。因而前面的代码段可以这样重写:
- auto iter1 = people.lower_bound("Ann");
- auto iter2 = people.lower_bound("Ann");
- if(iter1 != std::end(people))
- {
- for(auto iter = iterl ; iter != iter2; ++iter)
- std::cout << iter->first << " is " << iter->second << std::endl;
- }
- auto n = people.count("Jack"); // Returns 2
- std::string key{"Jack"};
- auto n = std::distance( people.lower_bound(key),people.upper_bound(key)); // No. of elements matching key
multimap 的成员函数 erase() 有 3 个版本:
- 以待删除兀素的迭代器作为参数,这个函数没有返回值;
- 以一个键作为参数,它会删除容器中所有含这个键的元素,返回容器中被移除元素的个数;
- 接受两个迭代器参数,它们指定了容器中的一段元素,这个范围内的所有元素都会被删除,这个函数返回的迭代器指向最后一个被删除元素的后一个位置。
下面在示例中尝试一些multimap操作:
- // Using a multimap
- #include <iostream> // For standard streams
- #include <string> // For string class
- #include <map> // For multimap container
- #include <cctype> // For toupper()
- using std::string;
- using Pet_type = string;
- using Pet_name = string;
- int main()
- {
- std::multimap<Pet_type, Pet_name> pets;
- Pet_type type {};
- Pet_name name {};
- char more {'Y'};
- while(std::toupper(more) == 'Y')
- {
- std::cout << "Enter the type of your pet and its name: ";
- std::cin >> std::ws >> type >> name;
- // Add element - duplicates will be LIFO
- auto iter = pets.lower_bound(type);
- if(iter != std::end(pets))
- pets.emplace_hint(iter, type, name);
- else
- pets.emplace(type, name);
- std::cout << "Do you want to enter another(Y or N)? ";
- std::cin >> more;
- }
- // Output all the pets
- std::cout << "\nPet list by type:\n";
- auto iter = std::begin(pets);
- while(iter != std::end(pets))
- {
- auto pr = pets.equal_range(iter->first);
- std::cout << "\nPets of type " << iter->first << " are:\n";
- for(auto p = pr.first; p != pr.second; ++p)
- std::cout << " " << p->second;
- std::cout << std::endl;
- iter = pr.second;
- }
- }
代码中的第一个循环,将给定键的第二个以及随后的元素插入到这个键序列的前面。这里使用 emplace_hint() 来插入元素。如果它是给定类型的第一个元素,就调用 emplace() 在适当的位置创建元素。
在第二个 while 循环中,按照 pet 的类型分组输出元素。首先找到 iter 指向的 pet 的第一个类型,然后用 equal_range() 返回的迭代器列出这种 pet 类型的全部序列。最后将 iter 设为这个序列的结束迭代器,它也是一个指向下一个 pet 类型的迭代器,或是容器的结束迭代器。后者会结束循环。下面是一些示例输出:
Enter the type of your pet and its name: rabbit Flopsy
Do you want to enter another(Y or N)? y
Enter the type of your pet and its name: rabbit Mopsy
Do you want to enter another(Y or N)? y
Enter the type of your pet and its name: rabbit Cottontail
Do you want to enter another(Y or N)? y
Enter the type of your pet and its name: dog Rover
Do you want to enter another(Y or N)? y
Enter the type of your pet and its name: dog Spot
Do you want to enter another(Y or N)? y
Enter the type of your pet and its name: snake Slither
Do you want to enter another(Y or N)? y
Enter the type of your pet and its name: snake Sammy
Do you want to enter another(Y or N)? n
Pet list by type:
Pets of type dog are:
Spot Rover
Pets of type rabbit are:
Cottontail Mopsy Flopsy
Pets of type snake are:
Sammy Slither