【C++】STL容器

一、序列式容器

1. vector

vector容器详解

2. deque

deque容器是双端队列,支持快速随机访问,在头尾位置插入/删除元素速度很快。

  • vector容器对于在头部的插入、删除效率低,且数据量越大,效率越低。相对而言,deque容器对于在头部的插入、删除速度比vector容器快
  • vector容器访问元素的速度比deque容器快
  • deque容器的内存重分配优于vector容器,因为其内部结构不需要复制所有元素
    在这里插入图片描述

deque容器内部有一个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。中控器维护的是每个缓冲区的地址,使得使用deque容器时像是一片连续的内存空间。
在这里插入图片描述

3. list

STL中的list容器是一个双向循环链表,只支持双向顺序访问,在list容器中任何位置插入/删除速度很快。

  • 链表中的迭代器只支持前移和后移
  • 插入/删除操作不会造成原有的迭代器失效

在这里插入图片描述

所有不支持随机访问迭代器的容器, 不可以用标准算法, 但内部会提供对应一些算法!

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

void printList(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

int main()
{
	list<int> L;
	L.push_back(90);
	L.push_back(30);
	L.push_back(20);
	L.push_back(70);
	printList(L);	// 90 30 20 70

	// 反转
	L.reverse();
	printList(L);	// 70 20 30 90

	// 排序,默认升序
	L.sort();
	printList(L);	// 20 30 70 90

	// 排序,降序排序
	L.sort([](const int& num1, const int& num2) {return num1 > num2; });
	printList(L);	// 90 70 30 20
	system("pause");
	return 0;
}

什么情况下用vector,什么情况下用list,什么情况下用deque?

  • vector支持快速随机访问,但在非尾部插入/删除数据时效率很低,适合对象简单,对象数量变化不大,随机访问频繁的情况
  • 需要从首尾两端进行插入/删除操作的时候可以选择deque
  • 除非必要,我们尽可能选择使用vector而非deque,因为deque的迭代器比vector迭代器复杂很多
  • list不支持随机访问,适用于对象大,对象数量变化频繁,插入和删除频繁的情况。

二、配接器

1. stack

栈是一种先进后出的数据结构,栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为。
在这里插入图片描述

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

int main()
{
	stack<int> s;
	// 入栈
	s.push(10);
	s.push(20);
	s.push(30);

	// 栈是否为空
	while (!s.empty())
	{
		// 返回栈顶元素
		cout << "栈顶元素为: " << s.top() << endl;
		// 出栈
		s.pop();
	}
	// 返回栈的大小
	cout << "栈的大小为:" << s.size() << endl;
	system("pause");
	return 0;
}

2. queue

队列是一种先进先出的数据结构,队列允许从一端新增元素,从另一端移除元素,队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为。
在这里插入图片描述

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

class Person
{
	friend ostream& operator<<(ostream& out, const Person& p);
public:
	Person(string name, int age) {
		this->m_Name = name;
		this->m_Age = age;
	}
private:
	string m_Name;
	int m_Age;
};

ostream& operator<<(ostream& out, const Person& p)
{
	out << "姓名:" << p.m_Name << " 年龄:" << p.m_Age;
	return out;
}

int main()
{
	queue<Person> q;

	Person p1("唐僧", 30);
	Person p2("孙悟空", 1000);
	Person p3("猪八戒", 900);
	Person p4("沙僧", 800);

	// 入队
	q.push(p1);
	q.push(p2);
	q.push(p3);
	q.push(p4);

	// 队列是否为空
	while (!q.empty())
	{
		// 返回队头元素
		cout << q.front() << endl;
		// 返回队尾元素
		cout << q.back() << endl;
		// 出队
		q.pop();
	}

	// 返回队列大小
	cout << "队列大小为: " << q.size() << endl;
	system("pause");
	return 0;
}

三、关联式容器

1. set / multiset

  • set/multiset属于关联式容器,底层结构是用红黑树实现
  • 所有元素在插入时自动按升序排序
  • set不允许容器中有重复的元素,multiset允许容器中有重复的元素
  • 对于自定义数据类型,set容器必须指定排序规则
// 基本使用
#include <iostream>
#include <set>
using namespace std;

void printSet(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

int main()
{
	set<int> s;

	// 插入
	s.insert(10);
	s.insert(30);
	s.insert(20);
	s.insert(40);
	s.insert(50);
	s.insert(60);

	// 容器是否为空
	if (s.empty()) {
		cout << "set为空" << endl;
	}
	else {
		// 返回容器中元素的数目
		cout << "set的大小为: " << s.size() << endl;	// 6
	}

	// 删除
	s.erase(s.begin());
	printSet(s);	// 20 30 40 50 60

	s.erase(60);
	printSet(s);	// 20 30 40 50

	// 查找
	set<int>::iterator pos = s.find(30);

	// 统计
	// 对于set容器来说,结果为0或1
	int num = s.count(30);
	cout << "num = " << num << endl;	// 1

	system("pause");
	return 0;
}
// set不允许容器中有重复的元素,multiset允许容器中有重复的元素
#include <iostream>
#include <set>
using namespace std;

int main()
{
	// set不允许插入重复值
	// set插入数据的同时会返回插入结果
	set<int> s;
	pair<set<int>::iterator, bool> ret = s.insert(10);
	if (ret.second) {
		cout << "第一次插入成功!" << endl;	// √
	}
	else {
		cout << "第一次插入失败!" << endl;
	}

	ret = s.insert(10);
	if (ret.second) {
		cout << "第二次插入成功!" << endl;
	}
	else {
		cout << "第二次插入失败!" << endl;	// √
	}

	// multiset允许插入重复的值
	multiset<int> ms;
	ms.insert(10);
	ms.insert(10);

	for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) {
		cout << *it << " ";		// 10 10
	}
	cout << endl;

	system("pause");
	return 0;
}
// 所有元素在插入时自动按升序排序
#include <iostream>
#include <set>
using namespace std;

class MyCompare
{
public:
	bool operator()(int v1, int v2) const {
		return v1 > v2;
	}
};

int main()
{
	set<int> s1;
	s1.insert(10);
	s1.insert(40);
	s1.insert(20);
	s1.insert(30);
	s1.insert(50);

	// set容器默认升序排序
	for (auto v : s1)
		cout << v << " ";
	cout << endl;	// 10 20 30 40 50

	// 指定降序排序
	set<int, MyCompare> s2;
	s2.insert(10);
	s2.insert(40);
	s2.insert(20);
	s2.insert(30);
	s2.insert(50);

	for (auto v : s1)
		cout << v << " ";
	cout << endl;
	system("pause");
	return 0;
}
// 对于自定义数据类型,set容器必须指定排序规则
#include <iostream>
#include <set>
using namespace std;

class Person
{
	friend ostream& operator<<(ostream& out, const Person& p);
	friend class ComparePerson;
public:
	Person(string name, int age) {
		this->m_Name = name;
		this->m_Age = age;
	}
private:
	string m_Name;
	int m_Age;
};

ostream& operator<<(ostream& out, const Person& p) {
	out << "姓名: " << p.m_Name << " 年龄: " << p.m_Age;
	return out;
}

class ComparePerson
{
public:
	// 按照年龄降序排序 
	bool operator()(const Person& p1, const Person& p2) const {
		return p1.m_Age > p2.m_Age;
	}
};

int main()
{
	// 对于自定义数据类型,必须指定排序规则
	set<Person, ComparePerson> s;

	Person p1("刘备", 30);
	Person p2("关羽", 27);
	Person p3("张飞", 24);
	Person p4("赵云", 21);
	s.insert(p1);
	s.insert(p2);
	s.insert(p3);
	s.insert(p4);

	for (auto p : s)
		cout << p << endl;
	system("pause");
	return 0;
}

2. map / multimap

  • map / multimap属于关联式容器,底层结构是用红黑树实现
  • map中所有元素都是pair,第一个元素为键值,起到索引作用,第二个元素为实际值
  • 所有元素都会根据元素的键值自动按升序排序
  • map不允许容器中有重复键值元素,multimap允许容器中有重复键值元素
  • 对于自定义数据类型,map容器必须指定排序规则
// 基本使用
#include <iostream>
#include <map>
using namespace std;

int main()
{
	map<int, int> m;
	// 插入
	m.insert(pair<int, int>(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(map<int, int>::value_type(3, 30));
	// 不建议使用[]插入
	m[4] = 40;

	// 如果没有这个键,就创建这个键值对,值为0
	m[5];
	for (const auto& p : m)
		cout << p.first << " " << p.second << " ";	// 1 10 2 20 3 30 4 40 5 0
	// 可以用于访问
	cout << m[1] << endl;	// 10

	// 删除
	m.erase(m.begin());		// 2 20 3 30 4 40 5 0
	m.erase(5);				// 2 20 3 30 4 40

	// 容器是否为空
	if (m.empty()) {
		cout << "map为空" << endl;
	}
	else {
		// 返回容器中元素的数目
		cout << "map的大小为: " << m.size() << endl;
	}

	// 按键查找
	map<int, int>::iterator pos = m.find(3);

	// 按键统计
	// 对于map,结果为0或者1
	int num = m.count(3);
	cout << "num = " << num << endl;	// 1

	system("pause");
	return 0;
}
// 更改排序方式
#include <iostream>
#include <map>
using namespace std;

class MyCompare {
public:
	bool operator()(int v1, int v2) const {
		return v1 > v2;
	}
};

int main()
{
	map<int, int, MyCompare> m;
	m.insert(make_pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(make_pair(3, 30));
	m.insert(make_pair(4, 40));
	m.insert(make_pair(5, 50));

	for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	system("pause");
	return 0;
}

参考:https://www.bilibili.com/video/BV1et411b73Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值