[C++ Grocery Store] Zusammenfassung der Verwendung von Set und Map

Fügen Sie hier eine Bildbeschreibung ein

I. Einleitung

1.1 Assoziative Container

Zuvor haben wir einige Container in STL eingeführt, z. B. Vektor, Liste, Deque, Forward_list (eingeführt in C++ 11) usw. Diese Container werden zusammenfassend als sequentielle Container bezeichnet, da ihre zugrunde liegende Schicht eine lineare Sequenzdatenstruktur ist. , was darin gespeichert ist, ist das Element selbst. Was ist also ein assoziativer Container? Wie unterscheidet es sich von einem sequentiellen Container?

Assoziative Container werden auch zum Speichern von Daten verwendet. Im Gegensatz zu sequentiellen Containern speichern sie Schlüssel-Wert-Paare von <Schlüssel, Wert>-Strukturen, die beim Datenabruf effizienter sind als sequentielle Container.

1.2 Schlüssel-Wert-Paare

Wird zur Darstellung einer Struktur mit einer Eins-zu-Eins-Beziehung verwendet. Diese Struktur enthält im Allgemeinen nur zwei Mitgliedsvariablen, Schlüssel und Wert. Schlüssel stellt den Schlüsselwert dar und Wert stellt die dem Schlüssel entsprechenden Informationen dar. Wenn Sie beispielsweise ein Wörterbuch für die Englisch-Chinesisch-Übersetzung erstellen möchten, müssen englische Wörter und ihre entsprechende chinesische Bedeutung im Wörterbuch vorhanden sein. Darüber hinaus besteht eine Eins-zu-eins-Entsprechung zwischen englischen Wörtern und ihrer chinesischen Bedeutung. Das heißt, durch die englischen Wörter im Wörterbuch können Sie die entsprechende chinesische Bedeutung finden.

Definition von Schlüssel-Wert-Paaren in SGI-STL

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)
	{
    
    }
};

Hinweis : Warum muss die unterste Ebene Paare speichern? Nehmen Sie Map als Beispiel. Map ist eine <key, value>-Struktur. Gemäß unserer bisherigen Praxis speichern wir einen Schlüssel und einen Wert im Knoten der Map. Bei der Dereferenzierung des Iterators treten jedoch Probleme auf, da der Operator* dies nur kann Gibt einen Wert zurück. Gibt es also einen Schlüssel oder einen Wert zurück? Dies scheint unangemessen. Um bei der Dereferenzierung gleichzeitig Schlüssel und Wert zurückzugeben, fragen wir uns, ob wir Schlüssel und Wert kombinieren können, um eine neue Struktur zu erhalten, und diese Struktur bei der Dereferenzierung zurückgeben können, also Paar Es wurde geboren.

1.3 Baumstrukturierte assoziative Container

Abhängig vom Anwendungsszenario implementiert STL insgesamt zwei Arten von assoziativen Containern mit unterschiedlichen Strukturen: Baumstruktur und Hash-Struktur. Es gibt vier Haupttypen baumstrukturierter assoziativer Container: Map, Set, Multimap und Multiset. Das gemeinsame Merkmal dieser vier Containertypen besteht darin, dass sie als zugrunde liegende Struktur einen ausgewogenen Suchbaum (d. h. einen Rot-Schwarz-Baum) verwenden und die Elemente im Container eine geordnete Reihenfolge darstellen. Im Folgenden stellen wir die einzelnen Container der Reihe nach vor.

2. eingestellt

2.1 Einführung in das Set

  • Ein Set ist ein Container, der Elemente in einer bestimmten Reihenfolge speichert.

  • In einer Menge identifiziert der Wert eines Elements es auch (Wert ist der Schlüssel, Typ ist T), und jeder Wert muss eindeutig sein. Elemente in einer Menge können im Container nicht geändert werden (Elemente sind immer konstant), sie können jedoch in den Container eingefügt oder daraus gelöscht werden.

  • Intern werden die Elemente in einer Menge immer nach bestimmten strengen schwachen Sortierkriterien geordnet, die durch ihr internes Vergleichsobjekt (Typvergleich) vorgegeben werden.

  • Set-Container sind beim Zugriff auf einzelne Elemente per Schlüssel im Allgemeinen langsamer als unordered_set-Container, ermöglichen aber die direkte Iteration von Teilmengen basierend auf der Reihenfolge.

  • Set wird mithilfe eines binären Suchbaums (Rot-Schwarz-Baum) auf der untersten Ebene implementiert.

Hinweis :

  • Im Gegensatz zu Map und Multimap speichern Map und Multimap echte Schlüssel-Wert-Paare <Schlüssel, Wert>, und Set speichert nur Werte, aber was tatsächlich unten gespeichert wird, ist das Schlüssel-Wert-Paar, das aus <Wert, Wert> besteht.

  • Wenn Sie ein Element in eine Menge einfügen, müssen Sie nur den Wert einfügen und es ist nicht erforderlich, ein Schlüssel-Wert-Paar zu erstellen.

  • Die Elemente im Satz können nicht wiederholt werden (Sie können den Satz also zur Deduplizierung verwenden).

  • Wenn Sie den Iterator der Menge verwenden, um die Elemente in der Menge zu durchlaufen, können Sie eine geordnete Sequenz erhalten.

  • Standardmäßig werden Elemente in einer Menge auf der Grundlage von „Kleiner als“ verglichen.

  • Um ein Element in der Menge zu finden, beträgt die Zeitkomplexität: log 2 n log2^nl o g 2n

  • Die Anzahl der Elemente im Satz darf nicht geändert werden.

  • Die unterste Ebene im Satz wird mithilfe eines binären Suchbaums (Rot-Schwarz-Baum) implementiert.

  • Die Funktion von set besteht darin, Duplikate zu sortieren und zu entfernen.

2.2 Verwendung des Sets

2.2.1 Vorlagenparameterliste des Satzes

Fügen Sie hier eine Bildbeschreibung ein
Kleine Tipps : T ist der in der Menge gespeicherte Elementtyp, und das Schlüssel-Wert-Paar <Wert, Wert> wird tatsächlich auf der untersten Ebene gespeichert. Compare ist ein Funktor. Standardmäßig werden die Elemente in der Menge nach weniger als verglichen (die Standardeinstellung ist aufsteigende Reihenfolge). Alloc ist die Verwaltungsmethode für den Elementraum im Satz, die mithilfe des von STL bereitgestellten Raumkonfigurators verwaltet wird.

2.2.2 Aufbau des Sets

Funktionsdeklaration Merkmale
set (const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()); Konstruieren Sie eine leere Menge
set (InputIterator zuerst, InputIterator zuletzt,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()); Konstruieren Sie eine Menge mit Elementen im Bereich [erster, letzter]
set(const set<Key, Compare, Alloc>& x); Kopieren Sie die Konstruktion des Sets

2.2.3 Iterator der Menge

Funktionsdeklaration Merkmale
Iterator begin() Gibt einen Iterator zum Startelement im Satz zurück
Iterator end() Gibt den Iterator zurück, der dem letzten Element im Satz folgt
const_iterator cbegin() const Gibt einen konstanten Iterator des Startelements in der Menge zurück
const_iterator cend() const Gibt den const-Iterator zurück, der dem letzten Element im Satz folgt
reverse_iterator rbegin() Gibt den umgekehrten Iterator des ersten Elements der Menge zurück, also end
reverse_iterator rend() Gibt einen umgekehrten Iterator an die Position neben dem letzten Element der Menge zurück
const_reverse_iterator crbegin()const Gibt den umgekehrten Const-Iterator des ersten Elements der Menge zurück, nämlich cend
const_reverse_iterator crend() const Gibt den umgekehrten Const-Iterator der nächsten Position des letzten Elements der Menge zurück, d. h. cbegin

2.2.4 Kapazität einstellen

Funktionsdeklaration Merkmale
bool empty() const Überprüfen Sie, ob die Menge leer ist. Geben Sie „true“ zurück, wenn sie leer ist, andernfalls geben Sie „false“ zurück
size_type size() const Gibt die Anzahl der gültigen Elemente in der Menge zurück

2.2.5 Änderungsvorgang festlegen

Funktionsdeklaration Merkmale
pair<iterator,bool> insert (const value_type& val); Fügen Sie Element x in die Menge ein. Was tatsächlich eingefügt wird, ist ein Schlüssel-Wert-Paar bestehend aus <x, x>. Wenn die Einfügung erfolgreich ist, wird <die Position des Elements in der Menge, true> zurückgegeben. Wenn die Einfügung fehlschlägt , es bedeutet, dass x bereits in der Menge existiert. , gib <x’s position in set, false> zurück
Leeres Löschen (Iteratorposition) Löschen Sie das UND-Element an Position pos
size_type erase(const key_type& x) Löschen Sie das Element mit dem Schlüsselwert x
Leeres Löschen (Iterator zuerst, Iterator zuletzt) Elemente im Bereich [erster, letzter) löschen
swap(set<Key, Compare, Alloc>& x) Tauschen Sie die Elemente in zwei Sätzen aus
void klar() Löschen Sie die Elemente im Set
Iterator find(const key_type& x) const Gibt die Position des Elements mit dem Wert x in der Menge zurück
size_type count(const key_type& x)const Gibt die Anzahl der Elemente in der Menge mit dem Wert x zurück
Iterator Lower_bound (const value_type& val) const; Gibt den ersten Iterator des Elements in der Menge zurück, der größer oder gleich dem Wert ist (wird im Allgemeinen verwendet, um die linke Seite des Iteratorbereichs zu finden).
Iterator Upper_bound (const value_type& val) const; Gibt den ersten Iterator in der Menge zurück, der größer als der Wert ist (wird im Allgemeinen verwendet, um die rechte Seite des Iteratorbereichs zu finden).
pair<iterator,iterator> equal_range (const value_type& val) const; Was zurückgegeben wird, ist ein Paar. Dieses Paar ist ein Intervall, das alle Werte in der Menge enthält. Erstens ist die linke Grenze (die der Rückgabewert von „lower_bound“ ist) und zweitens ist die rechte Grenze (was der Rückgabewert von „upper_bound“ ist).

2.2.6 Beispiele für die Verwendung von set

#include <iostream>
#include <set>
using namespace std;

void TestSet()
{
    
    
	//用array数组中的元素构造set
	int array[] = {
    
     1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	set<int> s(array, array + sizeof(array) / sizeof(array[0]));
	cout << "set中的元素个数:" << s.size() << endl;

	//正向打印set中的元素,从打印结果中可以看出:set可以去重
	cout << "正向打印:";
	for (auto& e : s)
	{
    
    
		cout << e << ' ';
	}

	cout << endl;

	//使用迭代器逆向打印set中的元素
	cout << "逆向打印:";
	auto it = s.rbegin();
	while (it != s.rend())
	{
    
    
		cout << *it << ' ';
		++it;
	}
	cout << endl;

	//set中值为3的元素出现了几次
	cout << "set中三的个数:" << s.count(3) << endl;
}

int main()
{
    
    
	TestSet();
	return 0;
}

Fügen Sie hier eine Bildbeschreibung ein

3. Multiset

3.1 Einführung in Multiset

  • Ein Multiset ist ein Container, der Elemente in einer bestimmten Reihenfolge speichert, wobei Elemente wiederholt werden können.

  • In einem Multiset wird es auch durch den Wert des Elements identifiziert (da das Multiset selbst Schlüssel-Wert-Paare speichert, die aus <Wert, Wert> bestehen, sodass der Wert selbst der Schlüssel ist, der Schlüssel der Wert ist und der Typ T ist ). Die Werte von Multiset-Elementen können im Container nicht geändert werden (da Elemente immer konstant sind), sie können jedoch in den Container eingefügt oder daraus gelöscht werden.

  • 在内部,multiset 中的元素总是按照其内部的比较规则(类型比较)所指示的特定严格弱排序准则进行排序。

  • multiset 容器通过 key 访问单个元素的速度通常比 unordered_multiset 容器慢,但当使用迭代器遍历时会得到一个有序序列。

  • multiset 的底层结构是二叉搜索树(红黑树)。

注意

  • multiset 在底层存储的是 <value,value> 的键值对。

  • multiset 的插入接口中只需要插入 value 即可。

  • 与 set 的区别是,multiset 中的元素可以重复,set 中 value 是唯一的。

  • 使用迭代器对 multiset 中的元素进行遍历,可以得到有序的序列。

  • multiset 中的元素不能修改。

  • 在 multiset 中找某个元素,时间复杂度是 O ( l o g 2 N ) O(log2^N) O(log2N)

  • multiset 的作用是可以对元素进行排序。

3.2 multiset 的使用

multiset 的接口和 set 的接口相同,这里不再过多赘述,下面演示一下,multiset 中允许出现重复值。

void TestMultiset()
{
    
    
	// 用array数组中的元素构造multiset
	int array[] = {
    
     1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	multiset<int> s(array, array + sizeof(array) / sizeof(array[0]));
	cout << "multiset中的元素个数:" << s.size() << endl;

	//正向打印set中的元素,从打印结果中可以看出:set可以去重
	cout << "正向打印:";
	for (auto& e : s)
	{
    
    
		cout << e << ' ';
	}

	cout << endl;

	//下面删掉所有的7
	auto pa = s.equal_range(7);
	s.erase(pa.first, pa.second);

	//正向打印set中的元素,从打印结果中可以看出:set可以去重
	cout << "正向打印:";
	for (auto& e : s)
	{
    
    
		cout << e << ' ';
	}

	cout << endl;
}

int main()
{
    
    
	TestMultiset();
	return 0;
}

Fügen Sie hier eine Bildbeschreibung ein

四、map

4.1 map 的介绍

  • map 是关联容器,它按照特定的次序(按照 key 来比较)存储由键值 key 和 value 组合而成的元素。

  • 在 map 中,键值 key 通常用于排序和唯一地标识元素,而值 value 中存储与此键值 key 关联的内容。键值 key 和值 value 的类型可能不同,并且在 map 的内部,key 与 value 通过成员类型 value_type 绑定在一起,为其取别名称为 pair。

Fügen Sie hier eine Bildbeschreibung ein

  • 在内部,map 中的元素总是按照键值 key 进行比较排序的。

  • map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序对元素进行直接迭代(即对 map 中的元素进行迭代时,可以得到一个有序的序列)。

  • map 支持下标访问,即在 [ ] 中放入 key,就可以找到与 key 对应的 value。

  • map 通常被实现为二叉搜索树,更准确的说是平衡二叉搜索树(红黑树)。

4.2 map 的使用

4.2.1 map 的模板参数说明

Fügen Sie hier eine Bildbeschreibung ein
key:键值对中 key 的类型

T:键值对中 value 的类型

Compare:比较器的类型,map 中的元素是按照 key 来比较的,缺省情况下按照小于来比较(排升序),一般情况下内置类型元素该参数不需要传递,如果无法比较式,比如自定义类型,需要用户自己显示传递比较规则(一般情况下按照函数指针或者仿函数来传递)。

Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库提供的空间配置器。

注意:在使用 map 时,需要包含头文件。

4.2.2 map 的构造

函数声明 功能介绍
explicit map (const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()); map 的默认构造函数
template <class InputIterator>map (InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()); map 的迭代器区间构造函数
map(const map<Key, T, Compare, Alloc>& x) map 的拷贝构造函数

4.2.3 map 的迭代器

函数声明 功能介绍
begin() 和 end() begin:首元素的位置,end最后一个元素的下一个位置
cbegin() 和 cend() 与 begin 和 end 的意义相同,但是 cbegin 和 cend 所指向的元素不能修改
rbegin() 和 rend() 反向迭代器,rbegin 在 end 位置,rend 在 begin 位置,其++和- -操作与 begin 和 end 操作移动相反
crbegin() 和 crend() 与 rbegin 和 rend 位置相同,操作相同,但 crbegin 和 crend 所指向的元素不能修改

4.2.4 map 的容量与元素访问

函数声明 功能简介
bool empty() const 检测 map 中的元素是否为空,是返回 true,否则返回 false
size_type size() const 返回 map 中有效元素的个数
mapped_type& operator[ ](const key_type& k) 返回 key 对应的 value

注意:在元素访问时,有一个与 operator[ ] 类似的接口 at()(该接口不常用),都是通过 key 找到 与 key 对应的 value,然后返回其引用,不同的是:当 key 不存在时,operator[ ] 用默认 value 与 key 构造键值对然后插入,返回该默认的 value,at() 接口则是直接抛异常。operator[ ] 的底层是通过调用 insert 来实现的,他主要有以下三个功能:查找读取(key 存在时)、插入(key 不存在时,此时的 value 是一个匿名对象,调用 value 的默认构造)、插入修改(key 不存在,并且给一个 value 的初始值)。

Fügen Sie hier eine Bildbeschreibung ein

void TestMap1()
{
    
    
	map<string, string> dict;
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("insert", "插入"));

	cout << dict["sort"] << endl;//查找和读取
	dict["map"];				 //插入
	dict["map"] = "映射,地图";	 //修改
	dict["insert"] = "xxx";		 //修改
	dict["set"] = "集合";		 //插入+修改
}

4.2.5 map 中元素的修改

函数声明 功能介绍
pair<iterator, bool> insert(const value_type& x) 在 map 中插入键值对 x,注意 x 是一个键值对,返回值也是键值对:iterator 代表新插入元素的位置,bool 代表是否插入成功
void erase(iterator pos) 删除 pos 位置上的元素
size_type erase(const key_type& x) 删除键值为 x 的元素,返回删除掉的元素个数
void erase(iterator first, iterator last) 删除 [first,last) 区间中的元素
void swap(map<Key, T, Compare, Allocator>& mp) 交换两个 map 中的元素
void clear() 将 map 中的元素清空
iterator find(const key_type& x) 在 map 中查找 key 为 x 的元素,找到返回该元素的位置的 const 迭代器,否则返回 cend
size_type count(const key_type& x) const 返回 key 为 x 的键值在 map 中的个数,注意:map 中的 key 是唯一的,因此该函数的返回值要么为 0,要么为 1,因此也可以用该函数来检测一个 key 是否在 map 中

4.2.6 map 使用举例

void TestMap()
{
    
    
	map<string, string> m;
	// 向map中插入元素的方式:
	// 将键值对<"peach","桃子">插入map中,用pair直接来构造键值对
	m.insert(pair<string, string>("peach", "桃子"));//匿名对象

	// 将键值对<"peach","桃子">插入map中,用make_pair函数来构造键值对
	m.insert(make_pair("banan", "香蕉"));//此方法最常用

	// 借用operator[]向map中插入元素
	   /*
	operator[]的原理是:
	 用<key, T()>构造一个键值对,然后调用insert()函数将该键值对插入到map中
	 如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
	 如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
	 operator[]函数最后将insert返回值键值对中的value返回
	*/
	// 将<"apple", "">插入map中,插入成功,返回value的引用,将“苹果”赋值给该引
		m["apple"] = "苹果";
	// key不存在时抛异常
		//m.at("waterme") = "水蜜桃";
		cout << m.size() << endl;
	// 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列
	for (auto& e : m)
		cout << e.first << "--->" << e.second << endl;
	cout << endl;
	// map中的键值对key一定是唯一的,如果key存在将插入失败
	auto ret = m.insert(make_pair("peach", "桃色"));
	if (ret.second)
		cout << "<peach, 桃色>不在map中, 已经插入" << endl;
	else
		cout << "键值为peach的元素已经存在:" << ret.first->first << "--->" << ret.first->second << " 插入失败" << endl;
	// 删除key为"apple"的元素
	m.erase("apple");
	if (1 == m.count("apple"))
		cout << "apple还在" << endl;
	else
		cout << "apple被吃了" << endl;
}

int main()
{
    
    
	TestMap();
	return 0;
}

总结

  • map 中的元素是键值对。

  • map 中的 key 是唯一的,并且不能修改。

  • 默认按照小于的方式对 key 进行比较。

  • map 中的元素如果用迭代器去遍历,可以得到一个有序的序列。

  • map 的底层为平衡搜索树(红黑树),查找效率比较高 O ( l o g 2 N ) O(log2^N) O(log2N)

  • 支持 [ ] 操作符,operator[ ] 中实际上是调用 insert 进行插入查找。

五、multimap

5.1 multimap 的介绍

  • multimap 是关联式容器,它按照特定的顺序,存储由 key 和 value 映射成的键值对 <key,value>,其中多个键值对之间的 key 是可以重复的。

  • 在 multimap 中,通常按照 key 排序和唯一的标识元素,而映射的 value 存储与 key 关联的内容。key 和 value 的类型可能不同。通过 multimap 内部的成员类型 value_type 组合在一起,value_type 是组合 key 和 value 的键值对:typedef pair<const key, T> value_type;

  • 在内部,multimap 中的元素总是通过其内部的比较对象,按照指定的特定严格弱排序标准对 key 进行排序的。

  • Die Geschwindigkeit des Multimap-Zugriffs auf ein einzelnes Element über den Schlüssel ist normalerweise langsamer als die des unordered_multimap-Containers, aber die Verwendung eines Iterators zum direkten Durchlaufen der Elemente in der Multimap kann eine geordnete Sequenz über den Schlüssel erhalten.

  • Multimap wird unter der Haube mithilfe binärer Suchbäume (Rot-Schwarz-Bäume) implementiert.

Hinweis : Der einzige Unterschied zwischen Multimap und Map besteht darin, dass der Schlüssel in Map eindeutig ist, während der Schlüssel in Multimap wiederholt werden kann.

5.2 Nutzung von Multimap

Die Schnittstelle in Multimap kann auf Map verweisen und die Funktionen sind ähnlich.

Hinweis :

  • Tasten in Multimap können wiederholt werden.

  • Standardmäßig vergleichen Elemente in Multimap Schlüssel nach Kleiner als (in aufsteigender Reihenfolge angeordnet).

  • In Multimap gibt es keine überladene Operator[]-Operation. Da Schlüssel wiederholt werden können, kann ein Schlüssel mehreren Werten entsprechen.

  • Der Rückgabewert der Einfügung von Multimap ist nicht mehr „Paar“, da die Einfügung definitiv erfolgreich ist und nur der Iterator des eingefügten Elements zurückgegeben wird.

  • Fügen Sie bei Verwendung dieselbe Header-Datei wie die Karte ein.

6. Fazit

Das heutige Teilen endet hier! Wenn Sie der Meinung sind, dass der Artikel gut ist, können Sie ihn dreimal unterstützen . Auf Chunrens Homepage gibt es viele interessante Artikel . Freunde können gerne Kommentare abgeben. Ihre Unterstützung ist die treibende Kraft für Chunrens Fortschritt!
Fügen Sie hier eine Bildbeschreibung ein

Guess you like

Origin blog.csdn.net/weixin_63115236/article/details/133410739
Recommended