C++ STL: Associative Containers

Overview of Associative Containers

Sequential containers store all C++ basic data types, while associative containers are quite different. While storing element values, this type of container will also provide an additional value (also called "key" for each element, its essence is also A C++ basic data type or an element of a custom type), its function is that in the process of using an associative container, if the value of the key of the target element is known, the target element can be found directly through the key without having to go through The way to traverse the entire container.

Abandoning sequential containers and using associative containers to store elements is often because associative containers can quickly find, read or delete stored elements, and this type of container inserts elements more efficiently than sequential containers.

That is to say, the elements stored in the associative container are all "key-value pairs" ( <key,value> ), which is the biggest difference from the sequential container. In addition, the elements stored in the sequence container are not sorted by default, while the elements stored in the associative container are sorted in ascending order by default according to the size of the key value of each element.

These characteristics of associative containers are attributed to the fact that when the STL standard library implements this type of container, the bottom layer uses the "red-black tree" data structure to organize and store each key-value pair.

associative container type

The C++ STL standard library provides four types of associative containers, namely map, set, multimap, and multiset, and their respective characteristics are shown in the following table:

associative container name features
map Defined in the <map> header file, the key of each element of the data stored in this container must be unique (that is, cannot be repeated), and the container will be sorted in ascending order by default according to the size of each element key (call std:: less<T>).
set Defined in the <set> header file, using the data stored in this container, each element key and value are exactly the same, and the value of each element cannot be repeated (the uniqueness of each element key is guaranteed). The container is automatically sorted in ascending order according to the size of the key (actually, the element value) of each element (call std::less<T>).
multimap Defined in the <map> header file, the only difference from the map container is that the keys of elements stored in the multimap container can be repeated.
multiset Defined in the <set> header file, the only difference from the set container is that the value of the stored element in the multiset container can be repeated (once the value is repeated, it means that the key is also repeated).

In addition, C++ 11 has added 4 new hash containers, namely unordered_map, unordered_multimap and unordered_set, unordered_multiset. Strictly speaking, they are also associative containers, but the underlying hash container uses a hash table instead of a red-black tree.

Detailed usage of pair

We know that associative containers store data in the form of "key-value pairs", such as:

<"C语言教程", "http://c.biancheng.net/c/">
<"Python教程", "http://c.biancheng.net/python/">
<"Java教程", "http://c.biancheng.net/java/">

As shown above, each row represents a key-value pair, where the first element acts as the key and the second element acts as the value.

Note that based on the characteristics of data stored in each associative container, set and multiset associative container storage can be used only when the keys and values ​​in each key-value pair are all correspondingly equal, otherwise map or multimap associative containers must be used.

Considering that "key-value pair" is not an ordinary type of data, the C++ STL standard library provides a pair class template, which is specially used to convert two ordinary elements first and second (which can be C++ basic data types, structures, and class-defined type) is created as a new element <first, second>. It is not difficult to see from the format of its elements that using the pair class template to create elements in the form of "key-value pairs" is perfect.

Note that the pair class template is defined in the <utility> header file, so this header file needs to be imported before using this class template.

  1. Before the C++11 standard, the following three constructors were provided in the pair class template:
// 1) 默认构造函数,即创建空的 pair 对象
pair();
// 2) 直接使用 2 个元素初始化成 pair 对象
pair (const first_type& a, const second_type& b);
// 3) 拷贝(复制)构造函数,即借助另一个 pair 对象,创建新的 pair 对象
template<class U, class V> pair (const pair<U,V>& pr);

In the C++11 standard, on the basis of the introduction of rvalue references, the following two constructors are added to the pair class template:

// 4) 移动构造函数
template<class U, class V> pair (pair<U,V>&& pr);
// 5) 使用右值引用参数,创建 pair 对象
template<class U, class V> pair (U&& a, V&& b);

In addition, the pair class template in the C++11 standard also adds the following constructor: pair (piecewise_construct_t pwc, tuple<Args1...> first_args, tuple<Args2...> second_args);, but this way of constructing a pair class template is rarely used.

The following program demonstrates the above methods of creating pair objects:

#include <iostream>
#include <utility>      // pair
#include <string>       // string
using namespace std;

int main() {
    // 调用构造函数 1,也就是默认构造函数
    pair <string, double> pair1;
    // 调用第 2 种构造函数
    pair <string, string> pair2("STL教程","http://c.biancheng.net/stl/");  
    // 调用拷贝构造函数
    pair <string, string> pair3(pair2);
    // 调用移动构造函数
    pair <string, string> pair4(make_pair("C++教程", "http://c.biancheng.net/cplus/"));
    // 调用第 5 种构造函数
    pair <string, string> pair5(string("Python教程"), string("http://c.biancheng.net/python/"));  
   
    cout << "pair1: " << pair1.first << " " << pair1.second << endl;
    cout << "pair2: "<< pair2.first << " " << pair2.second << endl;
    cout << "pair3: " << pair3.first << " " << pair3.second << endl;
    cout << "pair4: " << pair4.first << " " << pair4.second << endl;
    cout << "pair5: " << pair5.first << " " << pair5.second << endl;
    return 0;
}

The output of the program is:

pair1: 0
pair2: STL教程 http://c.biancheng.net/stl/
pair3: STL教程 http://c.biancheng.net/stl/
pair4: C++教程 http://c.biancheng.net/cplus/
pair5: Python教程 http://c.biancheng.net/python/

When the above program creates the pair4 object, it calls the make_pair() function, which is also provided by the <utility> header file, and its function is to generate a pair object. Therefore, when we pass the return value of the make_pair() function (which is a temporary object) as a parameter to the pair() constructor, it calls the move constructor instead of the copy constructor.

On the basis of the above program, C++ 11 also allows us to manually assign values ​​to the pair1 object, such as:

pair1.first = "Java教程";
pair1.second = "http://c.biancheng.net/java/";
cout << "new pair1: " << pair1.first << " " << pair1.second << endl;

The execution result is:

new pair1: Java教程 http://c.biancheng.net/java/

At the same time, the creation process of the pair4 object in the above program can also be written in the following form, which are completely equivalent:

pair <string, string> pair4 = make_pair("C++教程", "http://c.biancheng.net/cplus/");
cout << "pair4: " << pair4.first << " " << pair4.second << endl;
  1. <utility>In addition to providing methods for creating pair objects in the header file, <、<=、>、>=、==、!=these 6 operators are overloaded for pair objects. The operation rules are: for two pair objects to be compared, first compare the size of the pair.first element, if If they are equal, continue to compare the size of the pair.second element.

Note that for the two pair objects being compared, the corresponding key and value types are the same, otherwise there will be no comparability, and the compiler will prompt that there is no matching operator, that is, no suitable overloaded operator can be found.

for example:

#include <iostream>
#include <utility>      // pair
#include <string>       // string
using namespace std;

int main() {
    pair <string, int> pair1("STL教程", 20);
    pair <string, int> pair2("C++教程", 20);
    pair <string, int> pair3("C++教程", 30);
    // pair1和pair2的key不同,value相同
    if (pair1 != pair2) {
        cout << "pair != pair2" << endl;
    }
    // pair2和pair3的key相同,value不同
    if (pair2 != pair3) {
        cout << "pair2 != pair3" << endl;
    }
    return 0;
}

The program execution result is:

pair != pair2
pair2 != pair3
  1. Finally, it should be pointed out that the pair class template also provides a swap() member function, which can exchange the key-value pairs of two pair objects. The premise of the successful operation is that the key and value types of the two pair objects must be the same . For example:
#include <iostream>
#include <utility>      // pair
#include <string>       // string
using namespace std;

int main() {
    pair <string, int> pair1("pair", 10);                   
    pair <string, int> pair2("pair2", 20);
    // 交换 pair1 和 pair2 的键值对
    pair1.swap(pair2);
    cout << "pair1: " << pair1.first << " " << pair1.second << endl;
    cout << "pair2: " << pair2.first << " " << pair2.second << endl;
    return 0;
}

The program execution result is:

pair1: pair2 20
pair2: pair 10

Guess you like

Origin blog.csdn.net/crossoverpptx/article/details/131704632