C++中的pair map set

465 阅读4分钟

C++中的pair map set 三者之间的联系与区别

联系:map 的元素类型实际上是 pair(键值对),其中键是唯一的,而 set 只存储唯一的键(可以认为是只有键没有值的 map)。 区别:pair 仅仅是一个将两个值绑定在一起的结构体,没有提供容器的功能。map 是一个键值对集合,每个元素都是一个 pair,通过键来访问值。set 只存储唯一的元素,不像 map 那样存储键值对。

pair

#include<bits/stdc++.h>
using namespace std;

int main() {
 	/*pair*/ 
	pair<int, string> p = make_pair(1, "apple");
	// 访问 pair 的元素
	cout << "First: " << p.first << ", Second: " << p.second << endl;
	// 修改 pair 的元素
	p.first = 2;
	p.second = "banana";
	cout << "First: " << p.first << ", Second: " << p.second << endl;
	return 0;
}

image-20240222152842978.png

pair的赋值方式

使用构造函数

直接在创建 pair 对象时,通过构造函数传递值。

pair<int, string> p(1, "apple");

使用 make_pair

make_pair 是一个辅助函数,可以根据其参数自动推导出返回的 pair 对象的类型。

pair<int, string> p = make_pair(1, "apple");

列表初始化(C++11 及以上)

在 C++11 及更高版本中,你可以使用花括号 {} 进行列表初始化。

pair<int, string> p = {1, "apple"};

复制(拷贝)赋值

如果你已经有了另一个 pair<int, string> 对象,可以直接将其赋值给新对象。

pair<int, string> p1(1, "apple");
pair<int, string> p2 = p1; // p2 现在有了 p1 的所有值

移动赋值(C++11 及以上)

对于支持移动语义的对象,可以使用移动赋值来转移资源,这通常更高效。

pair<int, string> p1 = make_pair(1, "apple");
pair<int, string> p2 = move(p1); // 使用 p1 的资源,p1 被置于不确定但有效的状态

使用 tie(C++11 及以上)

虽然 tie 通常用于解包 pairtuple,但你也可以通过它来赋值,尤其是在解构赋值中。

int a = 2;
string b = "banana";
tie(a, b) = make_pair(1, "apple"); // a 和 b 现在分别是 1 和 "apple"

使用结构化绑定(C++17 及以上)

C++17 引入了结构化绑定,允许你直接解构 pair 并赋值。

auto [a, b] = make_pair(1, "apple"); // a 是 int 类型,值为 1;b 是 string 类型,值为 "ap

map

#include<bits/stdc++.h>
using namespace std;

int main() {
	/*map*/
	map<string, int> m;
	// 插入元素
	m.insert(make_pair("apple", 5));
	m["banana"] = 3;
	// 访问元素
	cout << "apple: " << m["apple"] << endl;
	// 检查元素是否存在
	if (m.find("cherry") != m.end()) {
		cout << "cherry found" << endl;
	} else {
		cout << "cherry not found" << endl;
	}
	// 遍历 map
	for (const auto& pair : m) {
		cout << pair.first << " has " << pair.second << " units" << endl;
	}
	// 获取 map 的大小
	cout << "Size of map: " << m.size() << endl;
	return 0;
}

image-20240222152948485.png

在 C++ 中,map 容器提供了一个成员函数 find,用于在 map 中查找一个键。这个函数接受一个键作为参数,并返回一个迭代器。如果找到了这个键,则返回指向相应元素的迭代器;如果没有找到,则返回一个特殊的迭代器 end,它表示 map 结尾的位置,而不是一个有效的元素位置。因此,表达式 m.find("cherry") != m.end() 用于检查键 "cherry" 是否存在于 map m 中。

  • m.find("cherry"):调用 mapfind 方法尝试在 map 中找到键 "cherry"
  • m.end():返回一个迭代器,它表示 map 的末尾(注意,这不是最后一个元素,而是末尾之后的位置,也就是不存在的“下一个位置”)。
  • !=:比较两个迭代器是否不相等。

如果 find 方法返回的迭代器不等于 end() 迭代器,这意味着 "cherry" 存在于 map 中,因为 find 方法找到了一个有效位置,而不是末尾。如果 find 返回的迭代器等于 end(),则表示 "cherry" 不在 map 中。

set

#include<bits/stdc++.h>
using namespace std;

int main() {
	/*set*/
	set<int> s;
	// 插入元素
	s.insert(4);
	s.insert(1);
	s.insert(2);
	// 尝试插入重复元素(不会成功)
	s.insert(2);
	// 访问和遍历 set
	for (int element : s) {
		cout << element << " ";
	}
	cout << endl;
	// 检查元素是否存在
	if (s.find(3) != s.end()) {
		cout << "3 found" << endl;
	} else {
		cout << "3 not found" << endl;
	}
	// 获取 set 的大小
	cout << "Size of set: " << s.size() << endl;
	// 删除元素
	s.erase(1);
	cout << "After erasing 1: ";
	for (int element : s) {
		cout << element << " ";
	}
	cout << endl;
	return 0;
}

image-20240222153247439.png

s.insert(4); 
s.insert(1); 
s.insert(2);
  • 执行以上代码之后,为什么遍历结果是1 2 4 ?

    在 C++ 中,std::set 是基于红黑树(一种自平衡二叉查找树)实现的。这意味着它会自动将插入的元素排序。当你向 std::set 中插入元素时,它会根据元素的值将它们排序(默认情况下是升序)。因此,无论你以什么顺序插入元素,当你遍历这个集合时,元素会按照升序排列。

  • 这个自动排序的特性使得 std::set 非常适用于需要快速查找、插入和删除操作且元素不重复的情况,同时还需要保持元素有序的场景。