C++学习笔记——STL【容器:映射 map 与 multimap】

map 的基本概念

map是c++标准库中定义的关联容器,用于存储关键字(key)-值(value)形式的键值对。key 和 value可以是任意你需要的类型。

map 中的键 key不能重复,可以作为索引来快速定位对应的值。如果插入一个键值对时,key 已经在容器中存在,会导致新的值覆盖原先的值。(multimap 允许容器中有重复key值元素。)

map內部的实现自建一颗红黑树,这颗树具有对数据自动排序的功能,在map内部所有的数据都是有序的。

构造函数与赋值操作

功能描述:

  • 对map容器进行构造和赋值操作

构造函数:

  • map<T1, T2> mp; //map默认构造函数:
  • map(const map &mp); //拷贝构造函数

赋值操作:

  • map& operator=(const map &mp); //重载等号操作符
#include<iostream>
#include<string>
#include<map>

using namespace std;

/*打印输出map*/
void print_map(map<string,int>& m) {
	for (map<string, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

int main() {

	// 默认构造函数
	map<string, int> m1;
	/*插入键值对*/
	m1.insert(pair<string, int>("张三", 18));
	m1.insert(make_pair("李四",20));
	m1.insert(make_pair("王五",12));
	m1.insert(make_pair("老六",3));
	print_map(m1);
	/* 默认按照 key 升序排序
	key = 老六 value = 3
	key = 李四 value = 20
	key = 王五 value = 12
	key = 张三 value = 18
	*/
	
	/*拷贝构造函数*/
	map<string, int> m2(m1);
	print_map(m2);
	/*
	key = 老六 value = 3
	key = 李四 value = 20
	key = 王五 value = 12
	key = 张三 value = 18
	*/
	m2.insert(pair<string, int>("老王", 38));
	
	/*赋值操作*/
	map<string, int>m3 = m2;
	print_map(m3);
	/*
	key = 老六 value = 3
	key = 老王 value = 38
	key = 李四 value = 20
	key = 王五 value = 12
	key = 张三 value = 18
	*/
	return 0;
}

map 容器大小与容器交换

功能描述:

  • 统计map容器大小以及交换map容器

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容器
#include<iostream>
#include<string>
#include<map>

using namespace std;

/*打印输出map*/
void print_map(map<string,int>& m) {
	for (map<string, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

/*大小、和交换*/
void test43_2() {
	map<string, int> m;
	m.insert(make_pair<string,int>("张三", 25));
	m.insert(pair<string, int>("老王", 44));
	m.insert(make_pair<string, int>("老六", 33));
	cout << "m:" << endl;
	print_map(m);
	/*
	key = 老六 value = 33
	key = 老王 value = 44
	key = 张三 value = 25
	*/

	/*判断m容器是否为空*/
	if (m.empty()) {
		cout << "m为空" << endl;
	}
	else {
		cout << "m的大小为:" << m.size() << endl;//m的大小为:3
	}

	/*交换 m 与 m2 容器中的数据*/
	map<int, int>m2;
	m2.insert(pair<int, int>(1, 100));
	m2.insert(pair<int, int>(2, 200));
	m2.insert(pair<int, int>(3, 300));
	m2.insert(pair<int, int>(4, 400));
	// 类型不同无法交换
	// m.swap(m1); 

	/*交换 m 与 m3 容器中的数据*/
	map<string, int>m3;
	m3.insert(make_pair<string, int>("小明", 3));
	m3.insert(pair<string, int>("小红", 2));
	m3.insert(make_pair<string, int>("小花", 5));
	m3.insert(make_pair<string, int>("小胖", 7));
	cout << "m3:" << endl;
	print_map(m3);
	/*
	key = 小红 value = 2
	key = 小花 value = 5
	key = 小明 value = 3
	key = 小胖 value = 7
	*/

	m.swap(m3);
	cout << "m:" << endl;
	print_map(m);
	/*
	key = 小红 value = 2
	key = 小花 value = 5
	key = 小明 value = 3
	key = 小胖 value = 7
	*/

	cout << "m3:" << endl;
	print_map(m3);
	/*
	key = 老六 value = 33
	key = 老王 value = 44
	key = 张三 value = 25
	*/
}

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

插入与删除

功能描述:

  • map容器进行插入数据和删除数据

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(key); //删除容器中值为key的元素。
#include<iostream>
#include<string>
#include<map>

using namespace std;

void test51_1() {

	map<string, int>m;
	/*insert函数插入键值对 返回 pair 组对,第一个值指向为插入成功的元素的迭代器,第二个值为是否插入成功*/
	m.insert(pair<string,int>("关羽",4));
	// 插入成功的元素是:key = 张飞,value = 2
	pair<map<string, int>::iterator, bool> r1 = m.insert(pair<string, int>("张飞", 2));
	if (r1.second) {
		
		cout << "插入成功的元素是:key = " << r1.first->first << ",value = " << r1.first->second << endl;
	}
	else {
		cout << "插入失败" << endl;
	}

	// 插入失败
	pair<map<string, int>::iterator, bool> r2 = m.insert(pair<string, int>("关羽", 4));
	if (r2.second) {
		cout << "插入成功的元素是:key = " << r2.first->first << ",value = " << r2.first->second << endl;
	}
	else {
		cout << "插入失败" << endl;
	}
	m.insert(pair<string,int>("赵云",1));
	m.insert(pair<string,int>("刘备",7));

	/*使用迭代器遍历*/
	for (map<string, int>::iterator p = m.begin(); p != m.end(); p++) {
		cout << "键:" << p->first << ",值:" << p->second << endl;
	}
	/*
	键:关羽,值:4
	键:刘备,值:7
	键:张飞,值:2
	键:赵云,值:1
	*/

	/*迭代器 指向第一个元素*/
	map<string, int>::iterator p = m.begin();
	/*获取迭代器指向的元素*/
	cout << "键:" << p->first << ",值:" << p->second << endl; // 键:关羽,值:4
	/*删除迭代器指向的元素 返回指向下一个元素的迭代器*/
	map<string, int>::iterator p_next = m.erase(p);
	cout << "键:" << p_next->first << ",值:" << p_next->second << endl; // 键:刘备,值:7

	for (map<string, int>::iterator p = m.begin(); p != m.end(); p++) {
		cout << "键:" << p->first << ",值:" << p->second << endl;
	}
	/*
	键:刘备,值:7
	键:张飞,值:2
	键:赵云,值:1
	*/

	cout << "------------------------------------" << endl;
	map<string, int>::iterator p_first = m.begin(); // 指向第一个元素的迭代器
	p_first++; // 向后移动一个位置
	map<string, int>::iterator p_end = m.end(); // 指向最后一个元素的迭代器
	/*删除迭代器指向区间内的元素 :第二个到最后一个之间的元素*/
	m.erase(p_first,p_end);
	for (map<string, int>::iterator p = m.begin(); p != m.end(); p++) {
		cout << "键:" << p->first << ",值:" << p->second << endl;
	}
	/*
	键:刘备,值:7
	*/

	/*清空map容器*/
	m.clear();
	cout << m.size() << endl; // 0

	/*根据键删除元素*/
	m.insert(pair<string,int>("曹操",99));
	cout << m.size() << endl; // 1
	m.erase("曹操");
	cout << m.size() << endl; // 0

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

元素查找与统计

功能描述:

  • 对map容器进行查找数据以及统计数据

函数原型:

  • find(key); 查找key是否存在,若存在,返回该键的元素的迭代器(如果是multimap,存在重复的Key时,返回第一个);若不存在,返回set.end();
  • count(key); //统计key的元素个数(对于map,由于key不能重复,所以只会返回0或1)
#include<iostream>
#include<string>
#include<map>

using namespace std;

int main() {

	map<string, int>m;
	m.insert(make_pair<string,int>("C",1));
	m.insert(make_pair<string,int>("C++",2));
	m.insert(make_pair<string,int>("C++",3));
	m.insert(make_pair<string,int>("Java",3));
	m.insert(make_pair<string,int>("Python",4));
	m.insert(make_pair<string,int>("C#",5));
	/*统计指定key的个数*/
	cout << m.count("C++") << endl;; // 1
	cout << m.count("JS") << endl; // 0

	/*根据key查找元素,如果找到,返回指向该元素的迭代器,
	如果没有找到,返回指向map容器最后一个元素的下一个位置的迭代器*/
	// key = C++,value = 2
	map<string, int>::iterator p1 = m.find("C++");
	if (p1 != m.end()) {
		cout << "key = " << p1->first << ",value = " << p1->second<<endl;
	}
	else {
		cout << "未找到元素" << endl;
	}

	// 未找到元素
	map<string, int>::iterator p2 = m.find("JS");
	if (p2 != m.end()) {
		cout << "key = " << p2->first << ",value = " << p2->second<<endl;
	}
	else {
		cout << "未找到元素" << endl;
	}

	multimap<string, int>m2;
	m2.insert(make_pair<string, int>("C", 1));
	m2.insert(make_pair<string, int>("C++", 2));
	m2.insert(make_pair<string, int>("C++", 3));
	m2.insert(make_pair<string, int>("Java", 3));
	m2.insert(make_pair<string, int>("Python", 4));
	m2.insert(make_pair<string, int>("C#", 5));

	// 如果找到多个,返回第一个匹配的元素
	map<string, int>::iterator p3 = m2.find("C++");
	// key = C++,value = 2
	if (p3 != m2.end()) {
		cout << "key = " << p3->first << ",value = " << p3->second << endl;
	}
	else {
		cout << "未找到元素" << endl;
	}
	p3++; // 迭代器往后移动一个位置
	cout << "key = " << p3->first << ",value = " << p3->second << endl; // key = C++,value = 3
	cout << m2.count("C++") << endl;; // 2
	cout << m2.count("JS") << endl; // 0
	return 0;
}

map 容器排序规则

map容器默认排序规则为 按照key值进行 从小到大排序。
利用仿函数,可以改变排序规则。
例如,key 是 int 类型,需要按照值从大到小降序排序

#include<iostream>
#include<string>
#include<map>

using namespace std;

class MapCompare {

public:
	// 需要加 const 
	// 否则报错:error C3848: 具有类型“const MapCompare”的表达式会丢失一些 const-volatile 限定符以调用“bool MapCompare::operator ()(int,int)”
	bool operator()(int a, int b) const{
		return a > b;
	}
};

int main() {

	/*key 为 int 默认从小到大排序*/
	/*在构建容器时,传入指定的比较规则*/
	map<int, string, MapCompare>m;
	m.insert(pair<int, string>(1, "C++"));
	m.insert(pair<int, string>(2, "C"));
	m.insert(pair<int, string>(3, "Java"));
	m.insert(pair<int, string>(4, "Python"));

	for (map<int, string>::iterator p = m.begin(); p != m.end(); p++) {
		cout << "key = " << p->first << ",value = " << p->second << endl;
	}

	/*
	key = 4,value = Python
	key = 3,value = Java
	key = 2,value = C
	key = 1,value = C++
	*/
	return 0;
}

map 使用案例:员工分组统计

案例描述

  • 公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作
  • 员工信息有: 姓名 工资组成;部门分为:策划、美术、研发
  • 随机给10名员工分配部门和工资
  • 通过multimap进行信息的插入 key(部门编号) value(员工)
  • 分部门显示员工信息

实现步骤

  1. 创建10名员工,放到vector中
  2. 遍历vector容器,取出每个员工,进行随机分组
  3. 分组后,将员工部门编号作为key,具体员工作为value,放入到multimap容器中
  4. 分部门显示员工信息
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>

using namespace std;

const string NAMES = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

class Employee {

public:
	string name;
	int age;
	int dept_id;

	Employee(string name, int age, int dept_id) {
		this->name = name;
		this->age = age;
		this->dept_id = dept_id;
	}
};
/*重载左移操作符*/
ostream& operator<<(ostream& out, const Employee& e) {
	out << "部门ID:" << e.dept_id << ",姓名:" << e.name << ",年龄:" << e.age;
	return out;
}
/*Employee对象按照年龄降序排序*/
bool EmployeeCompare(Employee& e1, Employee& e2) {
	return e1.age > e2.age;
}

// 输出Employee对象
void print_emp(const Employee& e) {
	cout << e << endl;
}

/*创建26个员工存入vector容器*/
void create_employee(vector<Employee>& v) {
	string s = "Emp-";
	for (int i = 0; i < 26; i++) {
		// 姓名
		string name = s + NAMES[i];
		// 年龄 18 -35
		int age = (rand() % (35 - 18 + 1)) + 18;
		// 部门ID 95-99
		int dept_id = (rand() % (99 - 95 + 1)) + 95;
		// 存入vector
		Employee e(name,age,dept_id);
		v.push_back(e);
	}
	// 按照年龄降序排序
	sort(v.begin(),v.end(), EmployeeCompare);
	// 使用算法遍历 vector
	cout << "============员工数据生成================" << endl;
	for_each(v.begin(),v.end(), print_emp);
}

/*将员工按照部门di分组存入multimap*/
void group(const vector<Employee>& v, multimap<int, Employee>& m) {
	for (int i = 0; i < v.size(); i++) {
		m.insert(pair<int, Employee>(v[i].dept_id, v[i]));
	}
}

/*根据部门ID展示员工信息*/
void show_emp_bydept(const multimap<int, Employee>& m) {
	cout << "============根据部门统计员工信息================" << endl;
	// 部门ID 为 95-99,作为循环条件
	for (int n = 95; n <= 99; n++) {
		// 获取当前部门ID = n 的员工数量
		int coutn_deptid = m.count(n);
		cout << "部门ID为 " << n << " 的员工有:" << coutn_deptid << "个" << endl;
		// 获取指向部门ID = n 的第一个员工的迭代器
		multimap<int, Employee>::const_iterator p = m.find(n);
		// 如果找到,就循环,
		if (p != m.end()) {
			// 循环次数就是 当前 key 出现的次数
			for (int i = 0; i < coutn_deptid; i++) {
				cout << "部门ID = " << p->first << ",员工信息 = " << p->second << endl;
				// 迭代器指向下一个位置
				p++;
			}
		}
		// 统计完成一个部门的信息
		cout << "============================================" << endl;
	}
}


int main() {
	// 随机种子
	srand((unsigned int) time(NULL));
	// 存储employee的容器
	vector<Employee> v;
	// 存储以按照部门编号分组的员工
	multimap<int, Employee> m;
	// 装入员工
	create_employee(v);
	// 员工分组
	group(v, m);
	// 根据部门ID统计各自数量,部门id区间 [95,99]
	show_emp_bydept(m);
}
============员工数据生成================
部门ID:96,姓名:Emp-D,年龄:35
部门ID:95,姓名:Emp-I,年龄:35
部门ID:99,姓名:Emp-T,年龄:34
部门ID:95,姓名:Emp-B,年龄:33
部门ID:96,姓名:Emp-C,年龄:33
部门ID:99,姓名:Emp-Q,年龄:32
部门ID:95,姓名:Emp-H,年龄:30
部门ID:97,姓名:Emp-G,年龄:29
部门ID:96,姓名:Emp-S,年龄:28
部门ID:99,姓名:Emp-Z,年龄:28
部门ID:98,姓名:Emp-A,年龄:27
部门ID:99,姓名:Emp-R,年龄:27
部门ID:99,姓名:Emp-Y,年龄:27
部门ID:99,姓名:Emp-E,年龄:26
部门ID:98,姓名:Emp-M,年龄:26
部门ID:99,姓名:Emp-O,年龄:25
部门ID:97,姓名:Emp-V,年龄:25
部门ID:97,姓名:Emp-J,年龄:24
部门ID:96,姓名:Emp-X,年龄:22
部门ID:98,姓名:Emp-L,年龄:20
部门ID:99,姓名:Emp-F,年龄:19
部门ID:96,姓名:Emp-K,年龄:19
部门ID:96,姓名:Emp-N,年龄:19
部门ID:96,姓名:Emp-P,年龄:19
部门ID:97,姓名:Emp-W,年龄:19
部门ID:99,姓名:Emp-U,年龄:18
============根据部门统计员工信息================
部门ID为 95 的员工有:3个
部门ID = 95,员工信息 = 部门ID:95,姓名:Emp-I,年龄:35
部门ID = 95,员工信息 = 部门ID:95,姓名:Emp-B,年龄:33
部门ID = 95,员工信息 = 部门ID:95,姓名:Emp-H,年龄:30
============================================
部门ID为 96 的员工有:7个
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-D,年龄:35
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-C,年龄:33
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-S,年龄:28
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-X,年龄:22
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-K,年龄:19
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-N,年龄:19
部门ID = 96,员工信息 = 部门ID:96,姓名:Emp-P,年龄:19
============================================
部门ID为 97 的员工有:4个
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-G,年龄:29
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-V,年龄:25
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-J,年龄:24
部门ID = 97,员工信息 = 部门ID:97,姓名:Emp-W,年龄:19
============================================
部门ID为 98 的员工有:3个
部门ID = 98,员工信息 = 部门ID:98,姓名:Emp-A,年龄:27
部门ID = 98,员工信息 = 部门ID:98,姓名:Emp-M,年龄:26
部门ID = 98,员工信息 = 部门ID:98,姓名:Emp-L,年龄:20
============================================
部门ID为 99 的员工有:9个
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-T,年龄:34
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-Q,年龄:32
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-Z,年龄:28
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-R,年龄:27
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-Y,年龄:27
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-E,年龄:26
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-O,年龄:25
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-F,年龄:19
部门ID = 99,员工信息 = 部门ID:99,姓名:Emp-U,年龄:18
============================================

C:\Users\86182\Desktop\C++\Stage05-STL\x64\Debug\Stage05-STL.exe (进程 6376)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C++ STL容器中的栈(stack)是一种后进先出(LIFO)的数据结构。栈的基本操作包括入栈(push)、出栈(pop)、查看栈顶元素(top)和判断栈是否为空(empty)。栈可以用数组或链表实现,但使用STL容器可以更方便地实现栈的操作。在STL中,栈是由适配器(adapter)stack实现的,可以使用push、pop、top和empty等成员函数来操作栈。栈的应用场景包括函数调用、表达式求值、括号匹配等。 ### 回答2: 栈(stack)是C++ STL(标准模板库)中的一个容器,是一个后入先出(Last In, First Out,LIFO)的数据结构。堆栈的基本操作是退栈(Pop)和入栈(Push),即在栈顶插入和删除元素。除了这两个基本操作,堆栈还提供了访问栈顶元素的方法,即Top()。 堆栈可以通过STL中的std::stack<T>来使用,其中T是元素的类型。堆栈的定义非常简单,只需要使用一个std::stack<T>对象即可。在使用之前,需要包含头文件<stack>。 堆栈的主要特性是插入和删除元素的时间复杂度为常数时间O(1),因为栈只需要在栈顶进行操作。堆栈一般用于实现递归、表达式求值、内存分配等。例如,在递归深度优先搜索中,可以使用堆栈来存储遍历的路径。 堆栈的操作非常简单,以下是常用的操作列表: 1. push():将一个元素插入栈顶。 2. pop():删除栈顶元素。 3. top():返回栈顶元素。 4. empty():判断堆栈是否为空。 5. size():返回堆栈中元素的个数。 下面是一个简单的堆栈的例子,可以更好地理解堆栈的基本操作: #include <iostream> #include <stack> using namespace std; int main() { stack<int> s; // 定义一个int类型的栈 s.push(10); // 将10入栈 s.push(20); // 将20入栈 s.push(30); // 将30入栈 while (!s.empty()) { cout << s.top() << " "; // 输出栈顶元素 s.pop(); // 删除栈顶元素 } return 0; } 在上面的例子中,我们首先定义了一个堆栈s,然后在堆栈s中依次插入了三个元素10、20和30。接下来使用while循环,栈顶元素依次输出,同时删除栈顶元素,直到堆栈为空。由于堆栈是后进先出的,所以输出的顺序是30、20和10。 总之,堆栈是一个非常常用的数据结构STL中的栈(stack)提供了非常方便的使用,可以减轻我们对堆栈数据结构进行操作的负担,提高代码的可读性和复用性。 ### 回答3: 栈(stack)是 C++ STL(Standard Template Library)中常见的一种容器数据结构,它可以在一端进行元素的插入和删除操作,遵循“后进先出”(LIFO,Last-In-First-Out)的原则。栈的操作不需要访问元素中间的部分,只需要在栈顶执行操作,保证了操作效率。栈可以用数组或链表等数据结构实现,但 C++ STL 提供了封装好的栈容器,使用起来方便且安全。 C++ STL 中栈容器的定义方式为:`std::stack`。栈默认情况下使用双端队列(deque)实现,用户也可以指定其他底层容器,如 vector、list 等。可以使用`push()`向栈顶插入元素,使用`pop()`弹出栈顶元素,使用`top()`获取栈顶元素。栈的元素个数可以使用`size()`来获取,判断栈是否为空可以使用`empty()`,在栈容器中查找某个元素的功能则不支持。 在实际应用中,栈容器可以用来实现函数的递归调用、表达式求值、括号匹配等操作。例如,可以使用栈来判断一个字符串中的括号是否匹配,具体做法是将左括号入栈,遇到右括号时弹出栈顶元素检查是否为相应的左括号。如果不匹配或者栈已经为空,则括号不匹配;如果字符串中所有的括号都匹配,则最后栈为空。 总之,栈作为一种容器数据结构,在实际应用中有着广泛的应用场景,C++ STL 提供的封装好的栈容器,具有使用方便、效率高等特点,可以帮助我们更快更方便地实现各种数据处理和算法设计。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值