[C++ Advanced] 4. Introduction and use of STL---set and map

Table of contents

1. Associative container

2. Key-value pairs

3. Associative container of tree structure

4. Introduction and use of set

4.1 Introduction to set 

4.2 Use of set

5. Introduction and use of multiset

6. Introduction and use of map

6.1 Introduction to map

6.2 The use of maps 

7. Introduction and use of multimap


1. Associative container

        I have already touched some containers in STL, such as: vector, list, deque, etc. These containers are collectively called sequential containers , because the bottom layer is a linear sequence data structure, which stores the elements themselves

What are associative containers?

        Associative containers are also used to store data. Unlike sequential containers, they store key-value pairs of <key, value> structure, which is more efficient than sequential containers in data retrieval.

set and map are associative containers 

2. Key-value pairs

What are key-value pairs? 

        A key-value pair is a structure used to represent a one-to-one correspondence. The structure generally only contains two member variables key and value, key represents the key value, and value represents the information corresponding to the key

For example, if you want to create a dictionary for English-Chinese translation, then there must be English words and their corresponding Chinese meanings in the dictionary, and there is a one-to-one correspondence between English words and their Chinese meanings, that is, through the corresponding words, in the dictionary. The corresponding Chinese meaning can be found

        The key-value pair is used in set and map. This key-value pair is called pair. It is a class template defined by struct, that is, the member variables in the pair can be accessed externally.

The definition of key-value pairs in SGI-STL is as follows:

template <class T1, class T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;
    T1 first;
    T2 second;
    pair() : first(T1()), second(T2())
    {}
    pair(const T1& a, const T2& b) : first(a), second(b)
    {}
};

Pair document introduction: pair - C++ Reference (cplusplus.com) https://legacy.cplusplus.com/reference/utility/pair/?kw=pair

The member types are introduced as follows:

How to use pair, the following introduces set and map and then explains

3. Associative container of tree structure

        According to different application scenarios, STL implements a total of two managed containers with different structures: tree structure and hash structure

        There are mainly four kinds of associative containers with tree structure: map, set, multimap, and multiset . The common feature of these four containers is that they use a balanced search tree (that is, red-black tree) as their underlying result, and the elements in the container are a ordered sequence

4. Introduction and use of set

4.1 Introduction to set 

Set document introduction: set - C++ Reference (cplusplus.com) https://legacy.cplusplus.com/reference/set/set/?kw=set

The translation is as follows: 

  1. set is a container that stores elements in a certain order
  2. In a set, the value of an element also identifies it (the value is the key, the type is T), and each value must be unique. The elements in the set cannot be modified in the container (elements are always const), but they can be inserted or removed from the container
  3. Internally, the elements in a set are always ordered according to a specific strict weak ordering criterion indicated by its internal comparison object (type comparison)
  4. set containers are generally slower than unordered_set containers for accessing individual elements by key, but they allow direct iteration over ordered subsets
  5. Set is implemented at the bottom with a binary search tree (red-black tree) 

 There are three template parameters for set:

  1. The third template parameter class Alloc = allocator<T> is a space allocator, ignore it
  2. The second template parameter class Compare = less<T> is a functor, usually ignore it, just use the default value. It has also been introduced before, and if it is necessary to pass parameters, the elements in the set are compared according to less than by default.
  3. The first template parameter class T is the type of elements stored in the set, and actually stores <value, value> key-value pairs at the bottom

Notice:

  1. Different from map/multimap, the real key-value pair <key, value> is stored in map/multimap, and only value is stored in set/multiset , but the key-value pair composed of <value, value> is actually stored in the bottom layer
  2. When inserting elements in the set, you only need to insert the value, and there is no need to construct a key-value pair
  3. That is, set/multiset is a K model, and map/multimap is a KV model

Use set to include header files: 

#include <set>

Note: The elements in the set cannot be repeated (so you can use set for deduplication)

4.2 Use of set

First introduce the first four member types of set

  • key_type is the first template parameter, ie (T), value_type is also the first template parameter (T) 
  • value_type corresponds to the first template parameter (T1) of the key-value pair, and value_type corresponds to the first template parameter (T2) of the key-value pair, namely <key_type, value_type>

  • key_compare is the second template parameter (Compare), key_compare is also the second template parameter (Compare)
  • key_compare and value_compare are also key-value pairs, similar to the above

(1) The constructor of set

The constructors provided by set are: the first empty construction and the second iterator range construction, which generally use empty construction, and the third is a copy constructor

test code

void Test_Set()
{
	set<int> s1;//空构造
	set<int> s2(s1.begin(), s1.end());//区间构造
	set<int> s3(s1);//拷贝构造
}

(2) Assignment overloading

test code

void Test_Set()
{
	set<int> s1;//空构造
	set<int> s2(s1);//拷贝构造
	set<int> s3;
	s3 = s1;//赋值重载
}

The destructor, this will not be introduced, it will be called automatically at the end of the program 

(4)Iterators

Use the set iterator to traverse the elements in the set to get an ordered sequence 

(5) Capacity

(6)Modifiers

The elements in the set are not allowed to be modified 

(7)find

Find an element in the set, the time complexity is: logN 

The usage of the above interfaces is roughly the same as that of the previously learned container interfaces, so I won’t demonstrate them any more.

5. Introduction and use of multiset

Multiset documentation introduction: multiset - C++ Reference (cplusplus.com) https://legacy.cplusplus.com/reference/set/multiset/

translate: 

  1. Multiset is a container that stores elements in a specific order, where elements can be repeated
  2. In the multiset, the value of the element will also identify it (because the multiset itself stores the key-value pair composed of <value, value>, so the value itself is the key, the key is the value, and the type is T). The value of the multiset element cannot Modifications are made within the container (since elements are always const), but can be inserted or removed from the container
  3. Internally, elements in a multiset are always sorted according to a specific strict weak ordering criterion dictated by its internal comparison rules (type comparisons)
  4. A multiset container accessing a single element by key is usually slower than an unordered_multiset container, but an ordered sequence will be obtained when traversing with an iterator
  5. The underlying structure of the multiset is a binary search tree (red-black tree)

Template parameters and member types are consistent with set, no explanation 

Notice:

  1. The key-value pairs of <value, value> are stored in the bottom layer of the multiset
  2. The insertion interface of mtltiset only needs to be inserted
  3. The difference with set is that the elements in multiset can be repeated, and the value in set is unique
  4. Use an iterator to traverse the elements in the multiset to get an ordered sequence
  5. Elements in a multiset cannot be modified
  6. Find an element in the multiset, the time complexity is O(logN)
  7. The role of multiset: elements can be sorted

         The use of multiset is consistent with that of set. The biggest difference is: set deduplication + sorting, multiset elements can be repeated + sorting

Note: When the searched element is the same element, the iterator that encounters the same first element in the inorder is returned

Use multiset to include header files:

#include <set>

6. Introduction and use of map

6.1 Introduction to map

Map documentation introduction: map - C++ Reference (cplusplus.com) https://legacy.cplusplus.com/reference/map/map/?kw=map

translate:

  1. Map is an associative container, which stores elements composed of key and value in a specific order (compared by key)
  2. In a map, the key value key is usually used to sort and uniquely identify elements, and the value value stores the content associated with this key value key. The types of the key value key and the value value may be different, and inside the map, the key and value are bound together through the member type value_type, and its alias name is pair
  3. typedef pair<const Key, T> value_type
  4. Internally, elements in a map are always sorted by key
  5. The speed of accessing a single element by key value in map is usually slower than that of unordered_map container, but map allows direct iteration of elements according to order (that is, when iterating elements in map, an ordered sequence can be obtained)
  6.  map supports subscript accessors, that is, put the key in [], you can find the value corresponding to the key
  7. Maps are usually implemented as binary search trees (more precisely: balanced binary search trees (red-black trees))

There are 4 template parameters for map 

  1. The fourth template parameter class Alloc = allocator<pair<const Key, T> > is a space configurator, ignore it now
  2. The third template parameter class Compare = less<Key> is a functor, usually you don’t need to worry about it, you can just use the default value, as mentioned earlier, if you need to pass the parameter again, the default is to compare by less than
  3. The second template parameter class T is the type of value in the key-value pair
  4. The second template parameter class Key is the type of key in the key-value pair

Note: Compare: The type of the comparator. The elements in the map are compared according to the key. By default, they are compared according to less than. In general (built-in type elements), this parameter does not need to be passed. If it cannot be compared (custom type), the user needs to explicitly pass the comparison rules by himself (generally, according to the function pointer or functor) 

To use map, you need to include the header file:

#include <map>

Note: map is also deduplication + sorting 

6.2 The use of maps 

First introduce the map member type:

  •  key_type is the first template parameter (Key)
  • mapped_type is the second template parameter (T)
  • value_type is obtained by typedef of pair<const key_type, mapped_type>
  • key_compare is the third template parameter (Compare), which compares key_type (Key), and the default value is less
  • value_compare is a nested function class for comparing elements

The map interface is similar to the set, but the map has more random access interfaces , which is very important for the map. The following introduces

(1) Constructor

test code

void Test_Map()
{
	//KV模型,通过 Key查找Value
	//map<Key, Value>
	map<int, char> m1;//空构造
	map<int, string> m2;//空构造

	map<int, char> m3(m1.begin(), m1.end());//区间构造
	map<int, char> m4(m1);//拷贝构造
}

 (2) Assignment overloading

void Test_Map()
{
	map<int, char> m1;//空构造
	map<int, char> m2(m1);//拷贝构造
	//赋值重载
	map<int, char> m3;
	m3 = m1;
}

The destructor is called automatically, without interpretation

(3)Iterators

Support for iterators supports range for 

test code

void Test_Map()
{
	map<int, char> m1;//空构造
	//插入数据。后面解释
	m1.insert(make_pair(1, 'a'));
	m1.insert(make_pair(2, 'b'));
	m1.insert(make_pair(3, 'c'));
	m1.insert(make_pair(4, 'd'));
	m1.insert(make_pair(4, 'd'));//key已存在则不插入,map去重

	//遍历
	//map<int, char>::iterator it = m1.begin();
	auto it = m1.begin();
	while (it != m1.end())
	{
		//通过Key查找Value
		//first是Key,second是Value,(KV模型)
		//键值对 pair<T1, T2> ---> pair<first, second>
		cout << it->first << "-->" << it->second << endl;
		++it;
	}
	cout << endl;
	//范围for
	for (auto& e : m1)//建议加上引用,否则数据大量的时候会带来拷贝大的代价
	{
		cout << e.first << "-->" << e.second << endl;
	}
}

operation result

 (4)Capacity

A null judgment and a size of the returned data will not be demonstrated

(5)Modifiers

swap and clear will not be demonstrated, insert and erase will be introduced below

 The erase interface is as follows

Commonly used is to pass the key to delete the node, no more explanation

The insert interface is as follows:

The most commonly used one is the first one. Here comes the question, what is pair<iterator, bool>? ?

First look at the explanation of the insert interface:

  • The parameter type value_type is obtained by performing typedef on pair<const key_type, mapped_type>, that is to say, the parameter is a key-value pair, and is passed by reference
  • insert The first (boxed) return type is pair<iterator, bool>
  • pair<iterator, bool> The first iterator is an iterator, and the second is bool, which is used to reflect whether the insertion is successful, and returns true if successful, otherwise returns false
  • If the insertion is successful (that is, the element does not exist for insertion), the return is pair<iterator, true>, and the iterator returns the iterator (pair) of the position of the newly inserted element
  • If the insertion fails (that is, the element already exists), the return is pair<iterator, false>, and the iterator returns the iterator (pair) of the existing element position

Note: This is very important to understand [] below

test code

void Test_Map()
{
	map<int, char> m1;//空构造
	//插入也要指明键值对的类型 pair<T1, T2>
	m1.insert(pair<int, char>(1, 'a'));
	m1.insert(pair<int, char>(2, 'b'));
	// pair<T1, T2> 也可以写成 make_pair
	m1.insert(make_pair(3, 'c'));
	m1.insert(make_pair(4, 'd'));
	m1.insert(make_pair(4, 'd'));//key已存在则不插入,map去重

	for (auto& e : m1)//建议加上引用,否则数据大量的时候会带来拷贝大的代价
	{
		cout << e.first << "-->" << e.second << endl;
	}
}

operation result

Explain make_pair

 make_pair is a template function, which is introduced in the documentation of pair

 make_pair is defined as follows:

In simple terms, the function of this function is like making typedef for pair<T1, T2> as make_pair , just use it directly 

Note: pair<T1, T2>(x, y) is an anonymous object

Random access to map is explained below

(6)Element access 

The interface is as follows:

The operator[] interface is defined as follows

The condition for operator[] access is: just pass in the first template parameter, which is the value of Key, that is to say, [] access is accessed through Key

The details of operator[] are as follows:

translate: 

  1. If k(Key) matches the key of an element in the container (i.e. Key exists), the function returns a reference to its mapped value, i.e. returns a reference to the value of Key
  2. If k(Key) does not match the key of any element in the container (i.e. Key does not exist), the function inserts a new element with that key and returns a reference to its mapped value, i.e. returns a reference to the newly inserted Key value
  3. Note that even if no mapped value is assigned to the element (i.e. no value is passed to T, T is empty), the element is constructed using its default constructor, which increases the size of the container by 1 when a new element is inserted
  4. The at member function is similar to [], but it has the same behavior when the element with the key exists (that is, the function of at and [] is the same when the searched element Key exists), but throws when it does not exist Abnormal (that is, the searched Key does not exist, the function of [] is to insert the Key directly into the map, but at throws an exception and will not insert)

Summarize:

  • The function of [] is to find + modify + insert (the reason for the modification is that [] returns a reference to the value of mapped_type (T))
  • The function of at is to find + modify (insert is not supported)

[] Equivalent to:

(*((this->insert(make_pair(k, mapped_type()))).first)).second
  1.  make_pair(k, mapped_type()) The first parameter k (Key) is pair The first template parameter T1
  2. The second parameter mapped_type() is an anonymous object, which is the second template parameter T2 of pair, and mapped_type is the second template parameter T of map, that is, T()
(*((this->insert( make_pair(k, mapped_type()) )).first)).second

make_pair(k, mapped_type())

         The type returned by make_pair is pair<T1, T2>, make_pair returns pair<T1, T2>, insert receives it, and  takes pair<T1, T2> (x, y) as the parameter of insert , that is, the parameter const value_type& val

That is to say

(*((this->insert( make_pair(k, mapped_type()) )).first)).second

Can be converted to (easy to understand):

mapped_type& operator[] (const key_type& k)
{
    return (*((this->insert( make_pair(k, mapped_type()) )).first)).second
}

---
T& operator[](const Key& k)
{
    pair<iterator,bool> ret = insert( make_pair(k, T());
    //insert 返回 pair<iterator,bool>
    //迭代器在pair的first的位置(即用 . 可以访问pair的成员变量 first)
    //迭代器内容访问方式为 ->
    //-> 操作符的重载前面篇章有过解释
    return ret.first->second;
}

Assuming you are given a string, you want to count the number of times the fruit appears 

string arr[] = { "苹果", "西瓜", "香蕉", "草莓", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

You can use map for statistics, the code is as follows:

void Test_Map()
{
	//统计水果出现的次数
	string arr[] = { "苹果", "西瓜", "香蕉", "草莓", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

	map<string, int> countMap1;
	for (auto& e : arr)
	{
		//map<string, int>::iterator it = countMap
		auto it = countMap1.find(e);
		if (it == countMap1.end())//没有就进行插入
		{
			countMap1.insert(make_pair(e, 1));
		}
		else
		{
			it->second++;
		}
	}

	for (const auto& kv : countMap1)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;

	//使用 []
	map<string, int> countMap2;
	for (auto& e : arr)
	{
        //不存在则插入
        //[] 的功能是 查找+修改+插入
        //operator[]的原理是:
	    //	用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中
	    //	如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
	    //	如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
	    //	operator[]函数最后将insert返回值键值对中的value返回
		countMap2[e]++;
	}

	for (const auto& kv : countMap2)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

operation result

Summarize

  1. The elements in the map are key-value pairs
  2. The key in the map is unique and cannot be modified
  3. By default, the key is compared by less than
  4. If the elements in the map are traversed by an iterator, an ordered sequence can be obtained
  5. The bottom layer of the map is a balanced search tree (red-black tree), and the search efficiency is logN
  6. map supports the [] operator, and the actual insertion search is performed in operator[] 

(7) find

If you use it directly, you won’t explain it. If you don’t know how to read the document 

7. Introduction and use of multimap

Introduction to multimap documentation: multimap - C++ Reference (cplusplus.com) https://legacy.cplusplus.com/reference/map/multimap/

translate:

  1. Multimaps are associative containers that store key-value pairs <key,value> mapped from key and value in a specific order, where keys between multiple key-value pairs can be repeated
  2. In a multimap, elements are usually sorted and uniquely identified by key, while the value of the map stores the content associated with the key. The types of key and value may be different, and they are combined through the member type value_type inside the multimap, and value_type is a key-value pair that combines key and value: typedef pair<const Key, T> value_type;
  3. Internally, elements in a multimap are always sorted by its internal comparison object, according to the specific strict weak ordering criteria specified by the keys
  4. The speed of multimap to access a single element by key is usually slower than that of unordered_multimap container, but using iterator to directly traverse the elements in multimap can get the ordered sequence of keys
  5. Multimap is implemented at the bottom with a binary search tree (red-black tree)

 Note: The only difference between multimap and map is that the key in map is unique, while the key in multimap can be repeated

 The use of multimap is consistent with that of map, so it will not be explained

Notice:

  1. There is no overloaded operator[] operation in multimap, because the Key of multimap may not be unique
  2. Same as the header file included with map when used

----------------I am the dividing line---------------

The article is over here, the next one will be updated soon

Guess you like

Origin blog.csdn.net/m0_64280701/article/details/129267943