C++STL基础——各个容器的用法

vector

1、构造

vector<int> v(5, 5); // 开辟5个空间,每个位置都填充5
vector<int> v1(v.begin(), v.end()); // 将v的前闭后开区间的值 构造v1
vector<int> v3(v.begin(), v.begin() + 2); // 前闭后开
vector<int> v2(v); // 拷贝构造

2、赋值操作

vector<int> v1(5, 5);
vector<int> v2;
v2= v1; // v1赋值给v2
vector<int> v3;
v3.assign(v1.begin(), v1.end()); // 区间赋值,前闭后开
vector<int> v4;
v4.assign(10, 100); // 将10个100赋值给v4

3、大小操作

vector<int> v(4, 5);
v.push_back(10);
int count = v.size(); // 返回容器中元素的个数
cout << count << endl;
count = v.capacity(); // 返回容器的大小
cout << count << endl;
	
bool flag = v.empty(); // 判断容器是否为空,空返回true,否则false
// 重新指定大小
v.resize(10); // 10个大小空间,若容器中不够10个默认用0填充
v.resize(10, 100); // 用100填充
v.push_back(11); // 尾插到重定义大小之后
cout << endl;
v.resize(4); // 如果指定大小比原来变小了,超出部分被删除掉

4、遍历
方式1:通过迭代器访问

template <typename T>
void printVector(vector<T>& sp)
{
	auto f = sp.begin();// 起始迭代器,指向第一个元素
	auto l = sp.end();// 结束迭代器,指向最后一个元素的下一个
	while(f != l) {
		cout << *f << " ";
		++f;
	}
	cout << endl;
}

或者使用for循环
for (vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
	cout << *it << endl;
}

方式2:利用STL提供的for_each

void myPrint(int val)
{
	cout << val << endl;
}
template <typename T>
void printVector(vector<T>& v)
{
	for_each(v.begin(), v.end(), myPrint); // 传入遍历的区间和操作
}

5、插入和删除操作

vector<int> v(5, 5); 
v.push_back(2); // 尾插
v.pop_back(); //尾删

// 插入
v.insert(v.begin(), 2);// 迭代器处插入,此时为头插
v.insert(v.begin()+2, 3, 100); // 在2索引处插入3个100

// 删除
v.erase(v.begin()); // 删除迭代器指向的元素
v.erase(v.begin(), v.begin()+2); // 删除0-2索引,前闭后开
v.clear(); // 清空

6、数据存取

vector<int> v(5, 5);
int temp = v.back(); // 返回容器中最后一个元素
cout << temp << endl;
temp = v.front(); // 返回第一个元素
cout << temp << endl;
temp = v.at(2); // 访问 下标为2处的元素
cout << temp << endl;
temp = v[2]; // // 访问 下标为2处的元素
cout << temp << endl;

v[2] = 22; // 修改指定下标处元素
v.at(3) = 33; // 修改指定下标处元素

7、互换操作

	vector<int> v(5, 5);
	vector<int> v1(1, 4);
	v.swap(v1); // v与v1互换
	v1.swap(v); // 这两种调用方式没有区别
	printVector(v);
	printVector(v1);

swap的用途:内存收缩

	vector<int> v;
	for (int i = 0; i < 100000; ++i) {
		v.push_back(i);
	}
	cout << "V的容量:" << v.capacity() << endl;
	cout << "V的大小:" << v.size() << endl;
	// 这时V的容量已经很大了,但是后续我们并不需要这么多的空间
	
	v.resize(10); // 比如现在只需要10个空间,那么后续的几万空间都是多余的。
	cout << "V的容量:" << v.capacity() << endl;  // 还是之前的容器所以容量还是那么大
	cout << "V的大小:" << v.size() << endl;
	// 重指定大小不会缩小之前已经扩充的容器容量,只是改变了size

	// 这时就可以用swap进行内存收缩
	vector<int>(v).swap(v); // 创建一个匿名对象与v做交换
	cout << "V的容量:" << v.capacity() << endl; // 变为指定的10
	cout << "V的大小:" << v.size() << endl;

8、预留空间

	// 减少vector在动态扩容时的扩展次数
	vector<int> v;
	int count = 0;
	int capa = v.capacity();
	v.reserve(100000);
	// 如果预留100000,那么1次就开辟100000
	for (int i = 0; i < 100000; ++i) {
		v.push_back(i);
		if (capa != v.capacity()) {
			capa = v.capacity();
			++count;
		}
		// 看一下扩容了多少次
	}
	cout << "扩容了:" << count << "次" << endl; // 30次 加了reserve后扩容一次
	cout << "V的容量:" << v.capacity() << endl;
	cout << "V的大小:" << v.size() << endl;

string

1、构造

	// 构造函数
	string str1; // 默认构造
	string str2("123"); //初始化构造
	string str3(str1); // 拷贝构造
	string str4(3, 'a'); // 使用n个字符a初始化构造 "aaa"

2、赋值操作

	string str1;
	str1 = "hello world!";

	string str2;
	str2 = str1; // = 重载不是拷贝构造

	string str3;
	str3 = 'a'; // 将字符 转换为字符串 赋给str3

	string str4;
	str4.assign("hello C++"); // 函数的形式赋值,

	string str5;
	str5.assign("hello C++", 3); // 将“hello C++” 的前3个付给str5

	string str6;
	str6.assign(5, 'a'); // 5个a的字符串给str6 "aaaaa"

	string str7;
	str7.assign(str5); // str5赋值给str7

	// 实际上底层 对"="赋值运算符的重载用的也是assign成员函数。一般用“=”

3、拼接操作

	string str1 = "我";
	str1 += "C++"; // 打印“我C++”
	str1 += '.'; //也可以拼接字符 打印“我C++.”

	string str2 = "LOL DNF CF";
	str1 += str2; // 也可以追加string类似的字符串

	string str3 = "I";
	str3.append(" love"); // 成员函数拼接 “I love”
	str3.append(" 12345", 3); // 将字符串的前3个拼接给str3 “I love 12”
	str3.append(str1); // "I love 12 我"
	str3.append("abcdef", 1, 3); // 从下标1开始截取3个 <==> str3+=“bcd”
	str3.append(str2, 2, 3); // 从下标2开始截取3个,若截取个数超过了字符串的长度,那么到结尾停止截取
	str3.append(str2, 8); // 从下标8开始到结尾

	// 底层重载+=运算符实际上都是用的append成员函数。

4、字符串的查找和替换

	// 查找
	string str1 = "LOL DNF CF DN";
	int pos = str1.find("DN"); // 查询指定字符串的首个下标 返回4
	cout << pos << endl;
	pos = str1.find("Dn"); // 查找不到返回-1 返回-1
	cout << pos << endl;

	pos = str1.rfind("DN"); // 倒着查,返回11
	cout << pos << endl;

	// 替换
	str1.replace(1, 3, "1234"); // 从1索引开始的3个字符长度替换为"1234"
	cout << str1 << endl;

5、字符串的比较

	string str1 = "123";
	string str2 = "123";
	int flag = str1.compare(str2); // 相等返回0,不相等返回ASCCI码差
	cout << flag << endl;

	bool ff = str1 == str2; // 相等返回1,不相等返回0
	cout << ff << endl;

6、字符串的字符存取
[] 的重载 at()成员函数

	string str1 = "hello";
	cout << str1[0] << endl; // 打印 h

	cout << str1.at(1) << endl; // 打印 e

	// 修改单个字符
	str1[2] = 'f';
	cout << str1 << endl; // 打印“heflo”

	str1.at(3) = 'f';
	cout << str1 << endl; // 打印“heffo”

7、插入和删除

	string str1 = "hello";
	str1.insert(1, "111");
	cout << str1 << endl; // 在1索引插入“111” 打印“h111elo”

	str1.erase(1, 3); // 从1索引位置删除3个字符 打印“hello”
	cout << str1 << endl;

8、子串截取

	string str = "hello";
	string str1 = str.substr(1, 3); // 从1索引截取3个字符返回子串
	cout << str1 << endl;
	str1 = str.substr(3, 5); // 如果越界,则遇到字符串结尾停止
	cout << str1 << endl;

stack 栈

1、构造与赋值

stack<int> s; // 默认构造
stack<int> s1(s); // 拷贝构造
stack<int> s2;
s2 = s1; // 赋值操作

2、栈的接口
栈不允许有遍历操作

	stack<int> s; // 默认构造
	s.push(10); // 入栈
	s.push(12);
	s.push(14); 
	s.pop(); // 出栈
	stack<int> s1(s); // 拷贝构造
	int size = s1.size(); // 返回栈中元素个数
	int top = s1.top(); // 返回栈顶元素

	bool flag = s1.empty(); // 判断栈是否为空,空返回true,反之false

set与multiset

set 与 multiset的区别:
1、set是存取无序且元素不可重复的。底层是红黑树实现,插入时会自动排序且去重
2、multiset是可以有重复元素的

1、构造与赋值

	set<int> st;// 默认构造
	set<int> st1(st); // 拷贝构造
	set<int> st2;
	st2 = st1; // 赋值

2、遍历

template <typename T>
void printSet(set<T>& sp)
{
	for (auto it = sp.begin(); it != sp.end(); ++it) {
		cout << *it << " ";
	}
	cout << endl;
}
template <typename T>
void printMultiset(multiset<T>& sp)
{
	for (auto it = sp.begin(); it != sp.end(); ++it) {
		cout << *it << " ";
	}
	cout << endl;
}

3、set与multiset区别展示

	set<int> st;
	st.insert(1);
	st.insert(3);
	st.insert(2);
	st.insert(4);
	st.insert(4);

	printSet(st); // 打印1 2 3 4  自动排序去重

	multiset<int> st1;
	st1.insert(1);
	st1.insert(3);
	st1.insert(4);
	st1.insert(4);
	st1.insert(2);
	printMultiset(st1); // 打印 1 2 3 4 4 自动排序但不去重

4、大小和交换操作
set是不支持resize重新指定大小的

	set<int> st;
	st.insert(1);
	st.insert(3);
	st.insert(2);
	st.insert(4);

	int size = st.size(); // 返回容器中元素的个数
	bool flag = st.empty(); // 判空

	set<int> st1;
	st.swap(st1); // 交换

5、插入和删除

	set<int> st;
	st.insert(1); // 插入一个元素
	set<int>::iterator it = st.begin(); // 不支持随机访问
	++it;
	it = st.erase(it); // 删除迭代器指向的元素,返回下一个元素的迭代器
	st.erase(2); // 按值删除
	st.erase(it, ++it); // 区间删除前闭后开

	st.clear(); // 清空

6、查询和统计

	set<int> st;
	set<int>::iterator it = st.find(2); // 查找元素2,找到返回迭代器位置,找不到返回end
	int count = st.count(2); 
	// 统计指定元素个数,对于set只有0和1,对于multiset可能大于1

7、排序规则

class MyCompare
{
public:
	bool operator()(int v1, int v2) const  // 通过仿函数实现新的排序规则
	{
		return v1 > v2;
	}
};
// 改变排序规则
void demo()
{
	set<int> st1;
	st1.insert(1);
	st1.insert(3);
	st1.insert(2);
	st1.insert(4);
	printSet(st1); // 默认升序

	set<int, MyCompare> st2; // 通过对自定义MyCompare类“()”的重载  实现自定义排序规则
	st2.insert(1);
	st2.insert(3);
	st2.insert(2);
	st2.insert(4);
	for (set<int, MyCompare>::iterator it = st2.begin(); it != st2.end(); ++it) {
		cout << *it << " ";
	}
	cout << endl; // 打印 4 3 2 1
}

自定义类型排序

// 存放自定义类型时必须指定仿函数,确定排序规则
class Person
{
public:
	Person(string name, int age){
		this->name = name;
		this->age = age;
	}

	string name;
	int age;
};
class compare
{
public:
	bool operator()(const Person& p1, const Person& p2) const {
		return p1.age > p2.age;
	}
};
void demo()
{
	set<Person, compare> s1;
	s1.insert(Person("vv", 12));
	s1.insert(Person("aa", 16));
	s1.insert(Person("bb", 13));
	s1.insert(Person("cc", 11));

	for (set<Person, compare>::iterator it = s1.begin(); it != s1.end(); ++it) {
		cout << it->name << it->age << endl;
	} // 按年龄降序
}

queue队列

队列不允许有遍历的行为

1、构造及其接口

	queue<int> q; // 默认构造
	q.push(10); // 队尾插入 入队
	q.push(12); 
	queue<int> q1(q); // 拷贝构造
	queue<int> q2;
	q2 = q1; // 赋值操作
	q1.pop(); // 队头删除 出队
	int f = q1.front(); // 返回队头元素
	int b = q1.back(); // 返回队尾元素
	int size = q1.size(); // 返回队中元素个数
	bool flag = q1.empty();// 判断队列是否为空

pair对组

1、对组的创建与使用

	pair<int, int> p(1, 12); // 键值对 (key, value)键值对的类型可以自定义
	pair<int, string> p2 = make_pair(1, "12"); // 这两种方式效果一样

	// 获取
	cout << p.first << " : " << p.second << endl;
	cout << p2.first << " : " << p2.second << endl;

map

  • map中所有元素都是pair对组
  • 对组的第一个是键第二个是值,通过pair.first pair.second 获取
  • 所有元素在插入时会通过键值自动排序
  • 本质:map/multimap 都属于关联式容器,底层使用二叉树实现
  • 优点:可以根据key值快速找到value值
  • map与multimap的区别:map中不允许有重复的键key,multimap中可以有重复的键key

1、遍历

template <typename K,typename V>
void printMap(map<K, V>& m)
{
	for (auto it = m.begin(); it != m.end(); ++it) {
		cout << it->first << " : " << it->second << endl;
	}
}

2、大小与交换操作

	map<int, int> mm;
	int size = mm.size(); // 返回map容器中的键值对的个数
	bool flag = mm.empty(); // 判空

	map<int, int> m2;
	m2.swap(mm); // 交换

3、插入和删除

	map<int, int> mm;
	mm.insert(pair<int, int>(1,10));
	mm.insert(pair<int, int>(2,20));
	mm.insert(pair<int, int>(3,30)); // 第一种
	mm.insert(make_pair(4, 40));
	mm.insert(make_pair(5, 50));	// 第二种
	mm.insert(map<int, int>::value_type(6, 60)); // 第三种
	mm[7] = 70;		// 第四种  若通过[]访问的键不存在,map会自动创建一个键值对值为0
	 // 插入时前两种最为常用,通过键访问值时一般用[]的方式
	mm[3] = 20; // 键=3的键值对已存在,将30修改为20
	printMap(mm);

	map<int, int>::iterator it = mm.begin();
	it = mm.erase(it, ++it); // 区间删除,前闭后开 返回下一个元素的迭代器
	it = mm.erase(it); // 删除迭代器指向的元素,返回下一个元素的迭代器

	bool flag = mm.erase(0); // 按键值 删除,通过键删除这条键值对 成功返回1,失败返回0
	mm.clear(); // 清空

4、查找和统计

	map<int, int> mm;
	mm.insert(make_pair(4, 40));
	mm.insert(make_pair(5, 50));

	map<int, int>::iterator it = mm.find(3); // 成功返回键=3的pair对组,失败返回end

	// 统计
	int num = mm.count(3); // 统计键=3的键值对的个数,对于map来说只有0和1
	
	multimap<int, int> m2;
	m2.insert(make_pair(4, 40));
	m2.insert(make_pair(4, 40));
	m2.insert(make_pair(4, 40));
	m2.insert(make_pair(5, 50));
	num = m2.count(4); // multimap可能大于1
	cout << num << endl;

5、map的排序
类似于set

class MyCompare
{
public:
	bool operator()(int v1, int v2) const {
		return v1 > v2;
	}
};
// map的排序
void demo()
{
	map<int, int, MyCompare> m1;
	m1.insert(make_pair(1, 10));
	m1.insert(make_pair(2, 20));
	m1.insert(make_pair(5, 50));
	m1.insert(make_pair(3, 30));
	m1.insert(make_pair(4, 40));
	
	for (auto it = m1.begin(); it != m1.end(); ++it) {
		cout << it->first << ":" << it->second << endl;
	}
}

list链表

1、遍历

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

2、构造

	list<int> l1; // 默认构造
	list<int> L1(2); // 开辟2个大小空间值默认为0
	list<int> l2(l1); // 拷贝构造
	list<int> l3(l1.begin(), l1.end()); // 区间构造
	list<int> l4(4, 5); // 指定初始值 4 个 5 构造

3、赋值和交换操作

	list<int> L1(4, 5);
	list<int> L2;
	L2 = L1;
	list<int> L3;
	L3.assign(L1.begin(), L1.end()); // 区间赋值 
	L3.assign(6, 6); // 6 个 6赋值给L3

	L1.swap(L3);  
	L3.swap(L1); // 这两种写法效果上没有区别,都是交换两个容器

4、大小操作

	list<int> L1(4, 5);

	int size = L1.size(); // 返回容器中的元素个数
	bool flag = L1.empty(); // 判空

	L1.resize(6); // 重新指定容器的大小,若边长默认用0填充
	L1.resize(3); // 若变短,删除超出的

	L1.resize(6, 4); // 超出部分用指定的元素填充,若变短 同上

5、插入和删除

	list<int> L1(4, 5);
	list<int> L2(5, 3);
	L1.push_back(6); // 尾插
	L1.pop_back(); // 尾删
	L1.push_front(7); // 头插
	L1.pop_front(); // 头删

	list<int>::iterator it = L1.begin(); // list 迭代器不支持随机访问,只能双向迭代
	L1.insert(++it, 3); // 中间插入,在迭代器指定处插入元素3
	L1.insert(it, L2.begin(), L2.end()); // 在迭代器指定处 区间插入前闭后开
	L1.insert(it, 3, 8); // 在迭代器指定处 插入 3个8

	it = L2.begin();
	L2.erase(++it); // 删除迭代器指向的元素
	L2.erase(++it, L2.end()); // 区间删除 前闭后开
	L2.remove(3); // 按值删除,删除容器中所有3
	L2.clear(); // 清空

6、存取操作

	list<int> L1(2);
	L1.push_back(2);
	L1.push_back(3);
	L1.push_back(4);
	L1.push_back(5);
	L1.push_back(6);
	
	int f_val = L1.front(); // 返回第一个元素
	int l_val = L1.back(); // 返回最后一个元素

7、反转和排序
注意:所有不支持随机访问迭代器的容器不能使用标准算法。
但是 对于这种不支持随机访问迭代器的容器,内部都对相关算法进行了封装

bool myCompaper(int a, int b)
{
	return a > b;
}
// 反转和排序
void demo()
{
	list<int> L1(1,1);
	L1.push_back(2);
	L1.push_back(3);
	L1.push_back(4);
	L1.push_back(5);
	L1.push_back(6);
	printList(L1);
	L1.reverse(); // 逆序
	printList(L1);

	// 排序
	// sort(L1.begin(), L1.end()); //不支持
	L1.sort(); // 默认升序
	printList(L1);

	L1.sort(myCompaper); // 也可以自定义比较方式,入参为函数地址
	printList(L1);
}

deque

  • deque 内部工作原理:
  • deque内部有个中控器,维护每个缓冲区的内容,缓冲区中存放真实数据
  • 中控器维护的是每个缓冲区的首地址,使得使用deque时像是在使用连续的内存空间
  • 头尾增删快,访问慢

1、遍历

template <typename T>
void printDeque(const deque<T> & sp)
{
	// 只读迭代
	for (auto it = sp.begin(); it != sp.end(); ++it) {
		cout << *it << " ";
	}
	cout << endl;
}

2、构造

	deque<int> d1;
	for (int i = 0; i < 10; ++i) {
		d1.push_back(i);
	}
	printDeque(d1);

	deque<int> d2(d1.begin(), d1.begin() + 3); // 区间赋值构造
	printDeque(d2);

	deque<int> d3(10, 100); // 10个100
	printDeque(d3);

	deque<int> d4(d3); // 拷贝构造
	printDeque(d4);

3、赋值操作

	deque<int> d1(5, 5);
	deque<int> d2;
	d2 = d1; // d1 赋值给d2

	d2.assign(d1.begin(), d1.begin()+2); // 前闭后开
	d2.assign(4, 2);// 4个2赋值给d2

4、大小操作

	deque<int> d1(5, 5);
	bool flag = d1.empty(); // 判空
	int size = d1.size(); // 只有大小,没有容量,deque容量是无限扩充的
	d1.resize(10); // 大小重定义默认0填充 
	d1.resize(10, 2); // 2填充

	d1.resize(3); // 如果重定义比原来的小,则删除超出的

5、插入和删除

	deque<int> d1(5, 5);
	d1.push_back(3); // 尾插
	d1.push_front(3); // 头插
	d1.pop_back(); // 尾删
	d1.pop_front(); // 头删

	// 中间插入删除操作
	d1.insert(d1.begin()+2, 1000); // 在下标2处插入1000
	d1.insert(d1.begin() + 2, 2, 100); // 在下标2处插入2个100

	deque<int> d2(4, 1);
	//在d2的1索引位置插入d1的[1,4)区间的值
	d2.insert(d2.begin()+1, d1.begin() + 1, d1.begin() + 4); 

	d2.erase(d2.begin()+1); // 删除下标1处的元素
	d2.erase(d2.begin(), d2.begin()+3); // 区间删除,前闭后开
	d2.clear(); // 清空

6、数据存取

	deque<int> d1(5, 5);
	int temp = d1[0]; 
	temp = d1.at(2);	// 访问指定下标处的元素

	d1[0] = 10;
	d1.at(2) = 10;		// 修改指定下标处的元素

	temp = d1.front(); // 返回容器中第一个元素
	temp = d1.back();  // 返回容器最后一个元素
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值