C++ common containers all in one go

1 Overview

The C++ container is part of the STL (Standard Template Library) (one of the six major components). Literally, the container in life is used to store (accommodate) water or food, and the container in C++ is used to store various All kinds of data, different containers have different characteristics, the following figure (mind map) lists several common C++ containers, and this part of C++ containers has many similarities with the sequences in python, maybe this It also well confirms the saying in the world that " C produces all things ". Because I only learned C++ after learning python, I suddenly felt: " There is no way out after the mountains and rivers are full of doubts, and there is another village with dark willows and flowers ". Because python is a top-level language, things like iterators and generators were not very clear at that time, and then they encountered similar content in C++, and they had a better understanding. Maybe this is why many people don't understand The reason why it is recommended for beginners to learn python.
insert image description here

2. Detailed description of the container

2.1vector (vector)

From this naming, it can be well understood that in linear algebra, vectors are one-dimensional structures, and in containers, vectors are also seemingly one-dimensional storage forms. It can be understood as an array of variable length. It’s just that adding and deleting data at the end is the most efficient, while adding and deleting data at other locations is less efficient. As an example (appetizer):

#include <iostream> 
#include <vector> 
using namespace std;
// 程序的主函数
int main()
{
    
    
	vector<int> V;
	V.push_back(1);
	V.push_back(2);
	V.push_back(1);
	V.push_back(2);
	cout << V[0] << endl;
	system("pause");
	return 0;
}

Printout: 1.
As can be seen from the above examples, the usage of vectors and arrays is very similar. Of course, containers also have an extremely useful function, which is the nested use of containers.

#include <iostream> 
#include <vector> 
using namespace std;
// 程序的主函数
int main()
{
    
    
	vector<vector<int>> V;
	vector<int> sub_V;
	sub_V.push_back(1);
	sub_V.push_back(2);
	sub_V.push_back(1);
	V.push_back(sub_V);
	cout << V[0][1] << endl;
	system("pause");
	return 0;
}

The vector printed out 2at this time can be regarded as a two-dimensional array, which is of course more flexible and powerful than a two-dimensional array.
Of course, vector containers have other richer operations. for example:

    int size = vec1.size();         //元素个数
 
    bool isEmpty = vec1.empty();    //判断是否为空
 
    vec1.insert(vec1.end(),5,3);    //从vec1.back位置插入5个值为3的元素
 
    vec1.pop_back();              //删除末尾元素
 
    vec1.erase(vec1.begin(),vec1.end());//删除之间的元素,其他元素前移
 
    cout<<(vec1==vec2)?true:false;  //判断是否相等==、!=、>=、<=...
 
    vector<int>::iterator iter = vec1.begin();    //获取迭代器首地址
 
    vector<int>::const_iterator c_iter = vec1.begin();   //获取const类型迭代器
 
    vec1.clear();                 //清空元素

To give the most common example:

#include <iostream> 
#include <vector> 
using namespace std;
// 程序的主函数
int main()
{
    
    
	vector<int> V;
	V.push_back(1);
	V.push_back(2);
	V.push_back(3);
	for (vector<int>::iterator it = V.begin(); it != V.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "==========================" << endl;
	V.insert(V.begin() + 2,10);
	for (vector<int>::iterator it = V.begin(); it != V.end(); it++)
		cout << *it << " ";
	system("pause");
	return 0;
}

Note that if the data is not inserted at the end, an iterator of the insertion position is passed in.
printout:
insert image description here

2.2deque (double-ended queue)

Deque, as the name suggests, can insert and delete data from both ends, and supports fast random access to data. for example:

#include <iostream> 
#include <deque> 
using namespace std;
// 程序的主函数
int main()
{
    
    
	deque<int> D;
	D.push_back(1);
	D.push_back(2);
	D.push_back(3);
	for (deque<int>::iterator it = D.begin(); it != D.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "============在其索引2的位置插入10:" << endl;
	D.insert(D.begin() + 2,10);
	for (deque<int>::iterator it = D.begin(); it != D.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "============在其头部插入0:" << endl;
	D.push_front(0);
	for (deque<int>::iterator it = D.begin(); it != D.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "============在其头部弹出0:" << endl;
	D.pop_front();
	for (deque<int>::iterator it = D.begin(); it != D.end(); it++)
		cout << *it << " ";
	system("pause");
	return 0;
}

printout:
insert image description here

2.3 list (list)

The list is implemented with a doubly linked list. The so-called doubly linked list means that you can search from the head of the linked list to find the tail of the linked list, or perform a reverse search from the tail to the head. This makes it very efficient to insert and delete elements at any position in the list, but the random access speed becomes very slow, because the saved addresses are discontinuous, so the list does not have overloaded operators, that is, the access to []list elements At that time, it was no longer as convenient as vectors and double-ended queues, and its elements could not be accessed like we used to access arrays in C language.
Let's take a look at an example:

#include <iostream> 
#include <list> 
using namespace std;
// 程序的主函数
int main()
{
    
    
	//list的创建和初始化
	list<int> lst1;          //创建空list


	list<int> lst2(3);       //创建含有三个元素的list


	list<int> lst3(3, 2); //创建含有三个元素的值为2的list


	list<int> lst4(lst3);    //使用lst3初始化lst4


	list<int> lst5(lst3.begin(), lst3.end());  //同lst4
	cout << "lst4中的元素有:" << endl;
	for (list<int>::iterator it = lst4.begin(); it != lst4.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "lst5中的元素有:" << endl;
	for (list<int>::iterator it = lst5.begin(); it != lst5.end(); it++)
		cout << *it << " ";
	cout << endl;
	system("pause");
	return 0;
}

Run, print output:
insert image description here
Then let's look at an example of adding and sorting an element.

#include <iostream> 
#include <list> 
#include <vector> 
using namespace std;
// 程序的主函数
int main()
{
    
    
	//list的创建和初始化
	list<int> lst1;          //创建空list

	for(int i = 0; i < 10; i++)
		lst1.push_back(9-i);                    //添加值
	cout << "lst1中的元素有:" << endl;
	for (list<int>::iterator it = lst1.begin(); it != lst1.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "对lst1中的元素进行排序:" << endl;
	lst1.sort();
	for (list<int>::iterator it = lst1.begin(); it != lst1.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "在索引为5的地方插入999:" << endl;
	list<int>::iterator insert_it = lst1.begin();
	for (int i = 0; i < 5; i++)
		insert_it++;
	lst1.insert(insert_it, 3, 999);
	for (list<int>::iterator it = lst1.begin(); it != lst1.end(); it++)
		cout << *it << " ";
	cout << endl;
	cout << "删除相邻重复元素后:" << endl;
	lst1.unique();                         //删除相邻重复元素
	for (list<int>::iterator it = lst1.begin(); it != lst1.end(); it++)
		cout << *it << " ";
	cout << endl;
	system("pause");
	return 0;
}

After running, print the output:
insert image description here
special attention, since the bottom layer of the list is a doubly linked list, the insert operation cannot directly insert data like 向量and 双端队列, and can only move to the corresponding position through the self-addition of the iterator, and then insert the data.

2.4 array (array)

There is not much difference between array and array in C language. After creation, only one type of data can be stored, and the size cannot be changed. Relatively simple, for example:

#include <iostream> 
#include <string>
#include <array>
using namespace std;
// 程序的主函数
int main()
{
    
    
	array<int, 4> arr = {
    
    1, 3, 2};
	cout << "arr values:" << std::endl;
	for (array<int, 4>::iterator it = arr.begin(); it != arr.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
	cout << "sizeof(arr) = " << sizeof(arr) << endl;
	cout << "size of arr = " << arr.size() << endl;
	cout << "max size arr = " << arr.max_size() << endl;
	cout << "empty = " << (arr.empty() ? "no" : "yes") << endl;
	system("pause");
	return 0;
}

Of course, most commonly, array also supports nesting, and this method can be used to construct a two-dimensional (multi-dimensional) array. Since it is relatively simple, no examples are given here.

2.5 string (string)

A container similar to vector. Specially used to save characters. Random access is fast. Tail insertion and deletion are fast. In some statements, string is not considered an STL container, but for the integrity of the content, we still learn it together.

#include <iostream> 
#include <string>
using namespace std;
// 程序的主函数
int main()
{
    
    
	string s1 = "Bob:";
	string s2("hellow world!");
	for (int i = 0; i < s1.size(); i++)
	{
    
    
		cout << s1[i];
	}
	cout << endl;
	for (int i = 0; i < s2.size(); i++)
	{
    
    
		cout << s2[i];
	}
	cout << endl;

	cout << s1 + s2 << endl;
	s1.insert(s1.size(),"you say ");
	cout << s1 + s2 << endl;
	system("pause");
	return 0;
}

Run, and the printout is as follows:
insert image description here
Through the above examples, we can find that there is not much difference from the string we learned in C language. In fact, the difference itself is not very big, but elements can be added after creation (blind guess is newly created A string with the same name, nothing more), and the way to add elements is also very simple, just insert(插入位置,需要添加的字符串)add them directly through this format. The above example is added from the end, so the index must be s1.size(). Of course, there are addition of strings, comparison of strings, etc., which are more basic content and have not been added to the examples. Interested students can find materials to learn by themselves.

2.6 map (mapping)

The map container is very similar to a dictionary in python , or exactly the same. Data is stored and accessed through key-value pairs, and the bottom layer is realized through red-black trees. Let's first look at an example of map creation and initialization.

#include <iostream> 
#include <map> 
#include <string>
using namespace std;
// 程序的主函数
int main()
{
    
    
	//map的创建和初始化
	//第一种:用insert函数插入pair数据:
	map<int, string> my_map;
	my_map.insert(pair<int, string>(1, "first"));
	my_map.insert(pair<int, string>(2, "second"));
	//第二种:用insert函数插入value_type数据:
	my_map.insert(map<int, string>::value_type(3, "first"));
	my_map.insert(map<int, string>::value_type(4, "second"));
	//第三种:用数组的方式直接赋值:
	my_map[5] = "first";
	my_map[6] = "second";
	map<int, string>::iterator it;           //迭代器遍历
	for (it = my_map.begin(); it != my_map.end(); it++)
		cout << it->first << "->" <<it->second << endl;
	system("pause");
	return 0;
}

Run, and print out the following results:
insert image description here
From the above results, we can see that the method of directly assigning values ​​to arrays is the simplest and most understandable. Of course, the map stores key-value pairs, so the previous int type data (key) does not represent its location. For example, it is also possible for us to modify the int to float. code show as below:

#include <iostream> 
#include <map> 
#include <string>
using namespace std;
// 程序的主函数
int main()
{
    
    
	//map的创建和初始化
	//第一种:用insert函数插入pair数据:
	map<float, string> my_map;
	my_map.insert(pair<float, string>(1, "first"));
	my_map.insert(pair<float, string>(2, "second"));
	//第二种:用insert函数插入value_type数据:
	my_map.insert(map<float, string>::value_type(3, "first"));
	my_map.insert(map<float, string>::value_type(4, "second"));
	//第三种:用数组的方式直接赋值:
	my_map[5.3] = "first";
	my_map[6.6] = "second";
	map<float, string>::iterator it;           //迭代器遍历
	for (it = my_map.begin(); it != my_map.end(); it++)
		cout << it->first << "->" <<it->second << endl;
	system("pause");
	return 0;
}

Of course, like other container types, map also supports nesting, such as:

#include <iostream> 
#include <map> 
#include <string>
using namespace std;
// 程序的主函数
int main()
{
    
    
	//map的嵌套用法
	map<int,map<int,string>> my_map;
	my_map[1][1] = "张三";
	my_map[1][2] = "李四";
	my_map[1][3] = "王五";

	for (map<int, map<int, string>>::iterator it = my_map.begin(); it != my_map.end(); it++)
	{
    
    
		for (map<int, string>::iterator in_it = it->second.begin(); in_it != it->second.end(); in_it++)
		{
    
    
			cout << it->first << "年级" << in_it->first << "号同学:" << in_it->second << endl;
		}
	}
	cout << endl;	
	system("pause");
	return 0;
}

Run, the printout is as follows:
insert image description here
There is another very important issue, which is the deletion of map elements. There are many ways to delete map elements, and the following are just a few common ones.

#include <iostream>
#include <map>
#include <string>
using namespace std;

void printMap(const map<string, int>& students)
{
    
    
	for (auto ii = students.begin(); ii != students.end(); ii++)
	{
    
    
		cout << "姓名:" << ii->first
			<< " \t诗作: " << ii->second << "篇"
			<< endl;
	}
	cout << endl;
}

int main(int argc, char* argv[]) {
    
    
	map<string, int> students;
	students["李白"] = 346;
	students["杜甫"] = 300;
	students["王维"] = 200;
	students["李商隐"] = 113;
	students["杜牧"] = 156;
	cout << "原map:" << endl;
	printMap(students);

	students.erase("李白");
	cout << "删除 李白 后:" << endl;
	printMap(students);

	students.erase(std::begin(students));
	cout << "删除第一个元素后:" << endl;
	printMap(students);

	map<string, int>::iterator iter = students.find("杜牧");
	students.erase(iter);
	cout << "删除杜牧后:" << endl;
	printMap(students);
	system("pause");
	return 0;
}

After running, print output:
insert image description here
As can be seen from the above example, the key-value pairs in the map do not necessarily save data in the order we created them. The map will be sorted internally according to the value of the key, but keep the corresponding key-value pairs The relationship remains unchanged.

2.7 set (collection)

Set is also a kind of associative container. It is the same as map. The bottom layer is implemented by red-black tree. When inserting and deleting operations, only the pointer is moved, and it does not involve memory movement and copying, so the efficiency is relatively high. It can be clearly seen from the Chinese name that there will be no duplicate elements in the set. If the same element is saved, it will be directly regarded as invalid. Let's look at a simple example first (about the creation of set and the addition of elements, etc. ):

#include <iostream> 
#include <set> 
#include <vector> 
using namespace std;
// 程序的主函数
int main()
{
    
    
	vector<int> ivec;
	for (vector<int>::size_type i = 0; i != 10; i++) {
    
    
		ivec.push_back(i);
		ivec.push_back(i);
	}
	set<int> iset(ivec.begin(), ivec.end());
	cout << "向量中的元素为:" << endl;
	for (vector<int>::iterator it = ivec.begin(); it != ivec.end(); it++)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
	cout << "集合中的元素为:" << endl;
	for (set<int>::iterator it = iset.begin(); it != iset.end(); it++)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
	cout << "向量的大小为:" << endl;
	cout << ivec.size() << endl;
	cout << "集合的大小为:" << endl;
	cout << iset.size() << endl; 

	system("pause");
	return 0;
}

Print output:
insert image description here
The method in the above example is equivalent to directly assigning the value of the vector to the collection, thereby creating the collection by the way, so if you want to create a collection by assigning values ​​one by one, how to write the code? How to clear the elements in the collection? And is it known that an element is in the set? Similarly, let's take a look at a piece of code.

#include <iostream> 
#include <set> 
#include <vector> 
#include <string>
using namespace std;
// 程序的主函数
int main()
{
    
    
	set<string> set1;
	set1.insert("the"); 

	//删除集合
	while (!set1.empty())
	{
    
    
		//获取头部
		set<string>::iterator it = set1.begin();
		//打印头部元素
		cout << *it << endl;

		//从头部删除元素
		set1.erase(set1.begin());
	}
	set<int>set2;
	for (int i = 100; i < 110; i++)
		set2.insert(i);
	cout << "set2中5出现的次数为:";
	cout << set2.count(5) << endl;
	set2.clear();
	cout << "set2清除之后的大小为:";
	cout << set2.size() << endl;
	system("pause");
	return 0;
}

Run, print output:
insert image description here
Through the above examples, we can find that set can directly insert()add data through methods, and the data is automatically sorted inside, so don’t worry about the order of data. Of course, it can also be added to a specified position through an iterator like map , you can directly use the method to query whether there is such data in the set count(), if there is, it will be returned 1, and if it is not, it will be returned 0.

3. Postscript

I completed this post during the National Day of this year (2022). It is true that I have given up a lot of time to play and reunite with relatives, but I have always believed in the meaning and importance of hard work. Many times we don’t know when we will To be successful, we don't know whether we will succeed, but we still need to work hard and fight hard while we are young. In the novel "The Shepherd Boy's Fantastic Journey", there is such a sentence: " When you want something, the whole universe will work together to wish you your wish come true. " Come on! ! !Please add a picture description

Guess you like

Origin blog.csdn.net/weixin_43719763/article/details/127147035