[C ++]-associated container

One, disorderly associated container

Speaking of unordered associative containers, he is one of the associative containers, and its bottom layer is implemented using a chained hash table. I will keep updating the chained hash table in the post-order blog post Please look forward to. He has a very important feature
about the chained hash table , that is , the efficiency of his addition and deletion check is O (1).
In the associative container, we are generally divided into set and map . Set represents a collection, storing keywords. map represents a mapping table, storing key-value pairs [key, value].
In the unordered associative container, the
set is divided into unordered_set-unordered single set, unordered_multiset-unordered multiple set.

The map is divided into unordered_map-unordered single remapping, unordered_multimap-unordered multiple mapping.
Insert picture description here

1. Detailed explanation of unordered_set

(1) Insert insertion
First, we define an unordered single set. He stores elements whose key value will not be repeated

unordered_set<int> set1;

Then loop to insert elements

for (int i = 0; i < 50; i++)
	{
		set1.insert(rand() % 20 + 1);
	}

For the insert of the associated container, only the value of the inserted element needs to be given, and it is not necessary to give an iterator like vector / deque / list. Because the bottom layer is the hash table, there is a corresponding function calculation for the inserted position

At this time, let's check the size of this container and the number of elements with key 15

cout << set1.size() << endl;
cout << set1.count(15) << endl;

The results are as follows:
Insert picture description here
Although we entered 50 numbers, because it is a single set, it automatically removes duplicate elements, and the number of elements with key 15 is definitely 1.

But the same is the insertion of the above code. If we change it to an unordered multiple set, the definition is as follows:

unordered_multiset<int> set1;

The output is as follows:
Insert picture description here
because its storage key value is an element that will be repeated. So all 50 elements are stored, and the number of elements with key 15 is the corresponding number of repetitions.

(2) Traverse the collection container
Method 1: Use iterator traversal

auto it1 = set1.begin();
	for (; it1 != set1.end(); ++it1)
	{
		cout << *it1 << " ";
	}

Method 2: Use for each traversal

for (int v : set1)
	{
		cout << v << " ";
	}

(3) Find and delete elements
Method 1: Use iterator traversal to find elements and find and delete

for (it1 = set1.begin(); it1 != set1.end(); )
	{
		if (*it1 == 30)
		{
			it1 = set1.erase(it1);//调用erase,it1迭代器就失效了,所以要对迭代器更新
		}
		else
		{
			++it1;
		}
	}

Method 2: Use the function find
find to return the end iterator if no element is found

it1 = set1.find(20);
	if (it1 != set1.end())
	{
		set1.erase(it1);
	}

(4) Application
Title requirement: In 100,000 integers, find duplicate element
analysis in massive data: Because here we are only required to find duplicate element values ​​in massive data, so using set is a very good method , The specific code is implemented as follows:

int main()
{
	const int ARR_LEN = 100000;
	int arr[ARR_LEN] = { 0 };
	for (int i = 0; i < ARR_LEN; ++i)
	{
		arr[i] = rand() % 10000 + 1;
	}
	unordered_set<int> set;
	for (int v : arr)//O(n)
	{
		set.insert(v);//O(1)
	}
	for (int v : set)
	{
		cout << v << " ";
	}
	cout << endl;
	return 0;
}

2. Detailed explanation of unordered_map

First of all, let's take a look at the nature of map. What differs from set is that map stores key-value pairs [key, value], so it can be inserted into the map table by packaging it into a type.
The type definition is as follows:

struct pqir
	{
	first;  
	second;  
	}

Where first means key and second means value

(1) Insert insertion
First, let's define an unordered single map map1.

unordered_map<int, string> map1;

Method 1: Use make_pair

map1.insert(make_pair(1000, "张三"));

Method 2: Because the structure is inserted, you can use the following methods

    map1.insert({ 1010,"李四" });
	map1.insert({ 1020,"王五" });

note! The single remapping table does not allow keys to be duplicated, but multiple mapping tables can be used
because there is already a Zhang San with a key of 1000. Therefore, it is invalid to insert an element at the position where the key is 1000, as follows

map1.insert({ 1000,"王凯" });

Method 3: Use brackets
The bracket operator overload function is as follows:

V& operator[](const K &key)
	{
		insert({key,V()});
	}

Observe the above function carefully. If the key does not exist, he will insert a pair of data [key, string ()]
For example:

map1[2000] = "刘硕";

Equivalent to the statement map1.insert ({2000, "Liu Shuo"});

There is also a modification effect, map1 [1000] = "Zhang San 2";
(2) Search
Method 1: Use an iterator to find

auto it1 = map1.find(1030);
	if (it1 != map1.end())
	{
		cout << "key:" << it1->first << "value:" << it1->second << endl;
	}

Method two: map provides bracket operator overload function can be found

cout << map1[1000] << endl;

(3) Application
Title requirements: 100,000 integers, which statistics are repeated, and the number of times the statistics are repeated
Analysis: This is not only to find the numbers, but also to count which numbers are repeated, so the multiple mapping table map
code is used as follows:

int main()
{
	const int ARR_LEN = 100000;
	int arr[ARR_LEN] = { 0 };
	for (int i = 0; i < ARR_LEN; ++i)
	{
		arr[i] = rand() % 10000 + 1;
	}
	unordered_map<int, int>map1;//分别代表值和重复次数
	for (int k : arr)
	{
		
		auto it = map1.find(k);
		if (it == map1.end())//表示这个数字就没出现过
		{
			map1.insert({ k,1 });
		}
		else
		{
			it->second++;
		}
	}
	//打印
	for (const pair<int, int>&p : map1)//定义常引用通过for each来遍历容器而不是修改容器
	{
		if (p.second > 1)
		{
			cout << "key:" << p.first << "count:" << p.second << endl;
		}
	}
	return 0;
}

The code also improvement
into a:
in duplicate values for each to find the code, we can use map1 [k] ++; code for an
improved two:
print function has the following implementation iterator

auto it = map1.begin();
	for (; it != map1.end(); ++it)
	{
		if (it->second > 1)
		{
			cout << "key:" << it->first << "count:" << it->second << endl;
		}
	}

Second, the orderly associated container

Speaking associated container he ordered an associated container, the underlying use of red-black tree to be implemented on red-black trees in Bowen after the order, I will continue to update, please stay tuned readers -
About Red and black trees, the time complexity of his addition and deletion check is O (log2n), which represents the height of the tree.
In an ordered associative container, set is divided into set and multiset, map is divided into map and multimap

1. Detailed set

(1) The element is a common type
. The addition, deletion, modification and modification are almost the same as unordered single set. First, his definition is

set<int> set1;
for (int i = 0; i < 20; ++i)
	{
		set1.insert(rand() % 20 + 1);
	}

Because the red-black tree has its own properties, you only need to give it the element to be inserted

His traversal is the result of a mid-order traversal of the underlying red-black tree

for (int v : set1)
	{
		cout << v << " ";
	}

(2) The element is a self-defined type
. The explanation above is for the ordinary type of operation. Next, let's explain how to store a custom Student type in an ordered collection.
First, we define a Student class

class Student
{
public:
	Student(int id,string name):_id(id),_name(name){}
private:
	int _id;
	string _name;
	friend ostream& operator<<(ostream& out, const Student& stu);
};
ostream& operator<<(ostream& out, const Student& stu)
{
	out << "id" << stu._id << "name:" << stu._name << endl;
	return out;
}

The definition of the main function is

int main()
{
	set<Student> set1;
	set1.insert(Student(1000, "张雯"));
	set1.insert(Student(1001, "李广"));
	return 0;
}

But the running result at this time is as follows:
Insert picture description here
because it is a custom type, a default less than operator overload function should be provided when comparing

bool operator<(const Student& stu)const//按id进行排序
	{
		return _id < stu._id;
	}

Traverse

for (auto it = set1.begin(); it != set1.end(); ++it)
	{
		cout << *it << endl;
	}

The results are as follows:
Insert picture description here

2. Detailed map

Still just the Student custom type just now, his definition in the map is as follows:

int main()
{
	map<int, Student> stuMap;
	stuMap.insert({ 1000,Student(1000,"张雯") });
	stuMap.insert({ 1030,Student(1030,"高阳") });
	stuMap.insert({ 1020,Student(1020,"李广") });
	return 0;
}

(1) Delete
stuMap.erase (it) stuMap.erase (1020)
(2) Query
method 1: stuMap.find (key)
method 2: Use square brackets

cout << stuMap[1020] << endl;

But based on the above code, the result of this operation is as follows:
Insert picture description here
because, for the map table, if the value of my custom type, you need to provide a default constructor as follows:

Student(int id=0, string name="") :_id(id), _name(name) {}
	

Here, there is no need to write the overload of the less than operator, because it is sorted according to the key, and know how to sort the integers. The
operation results after adjustment are as follows:
Insert picture description here

(3) Traverse output

auto it = stuMap.begin();
	for (; it != stuMap.end();++it)
	{
		cout << "key:" << it->first << "value:" << it->second << endl;
	}

operation result
Insert picture description here

Published 98 original articles · won praise 9 · views 3658

Guess you like

Origin blog.csdn.net/qq_43412060/article/details/105291864