STL容器

匠心C++学习目录

数据类型与break和continue
STL容器
常见排序算法
程序内存模型
函数相关操作
类和对象相关操作
模板c++
谓词和仿函数


一、STL容器分类

  1. Sequence Containers:维持顺序的容器。
    (a). vector:动态数组,是我们最常使用的数据结构之一,用于 O(1) 的随机读取。因为大
    部分算法的时间复杂度都会大于 O(n),因此我们经常新建 vector 来存储各种数据或中
    间变量。因为在尾部增删的复杂度是 O(1),我们也可以把它当作 stack 来用。
    (b). list:双向链表,也可以当作 stack 和 queue 来使用。由于 LeetCode 的题目多用 Node 来
    表示链表,且链表不支持快速随机读取,因此我们很少用到这个数据结构。一个例外
    是经典的 LRU 问题,我们需要利用链表的特性来解决,我们在后文会遇到这个问题。
    ©. deque:双端队列,这是一个非常强大的数据结构,既支持 O(1) 随机读取,又支持 O(1)
    时间的头部增删和尾部增删,不过有一定的额外开销。
    (d). array:固定大小的数组,一般在刷题时我们不使用。
    (e). forward_list:单向链表,一般在刷题时我们不使用。
  2. Container Adaptors:基于其它容器实现的数据结构。
    (a). stack:后入先出(LIFO)的数据结构,默认基于 deque 实现。stack 常用于深度优先搜
    索、一些字符串匹配问题以及单调栈问题。
    (b). queue:先入先出(FIFO)的数据结构,默认基于 deque 实现。queue 常用于广度优先
    搜索。
    ©. priority_queue:最大值先出的数据结构,默认基于vector实现堆结构。它可以在O(n log n)
    的时间排序数组,O(log n) 的时间插入任意值,O(1) 的时间获得最大值,O(log n) 的时
    间删除最大值。priority_queue 常用于维护数据结构并快速获取最大或最小值。
  3. Associative Containers:实现了排好序的数据结构。
    (a). set:有序集合,元素不可重复,底层实现默认为红黑树,即一种特殊的二叉查找树
    (BST)。它可以在 O(n log n) 的时间排序数组,O(log n) 的时间插入、删除、查找任
    意值,O(log n) 的时间获得最小或最大值。这里注意,set 和 priority_queue 都可以用
    于维护数据结构并快速获取最大最小值,但是它们的时间复杂度和功能略有区别,如
    priority_queue 默认不支持删除任意值,而 set 获得最大或最小值的时间复杂度略高,具
    体使用哪个根据需求而定。
    (b). multiset:支持重复元素的 set。
    ©. map:有序映射或有序表,在 set 的基础上加上映射关系,可以对每个元素 key 存一个
    值 value。
    (d). multimap:支持重复元素的 map。
  4. Unordered Associative Containers:对每个 Associative Containers 实现了哈希版本。
    (a). unordered_set:哈希集合,可以在 O(1) 的时间快速插入、查找、删除元素,常用于快
    速的查询一个元素是否在这个容器内。
    (b). unordered_multiset:支持重复元素的 unordered_set。
    ©. unordered_map:哈希映射或哈希表,在 unordered_set 的基础上加上映射关系,可以对
    每一个元素 key 存一个值 value。在某些情况下,如果 key 的范围已知且较小,我们也
    可以用 vector 代替 unordered_map,用位置表示 key,用每个位置的值表示 value。
    (d). unordered_multimap:支持重复元素的 unordered_map。
    因为这并不是一本讲解 C++ 原理的书,更多的 STL 细节请读者自行搜索。只有理解了这些
    数据结构的原理和使用方法,才能够更加游刃有余地解决算法和数据结构问题。

二、STL的六大组件

在这里插入图片描述
其中迭代器分类有
在这里插入图片描述
仿函数是重载()符号

三、算法

在这里插入图片描述

1、partial_sum函数

这个函数求前缀和(即到每个位置为止之前所有数字的和)。适用于各种STL容器。
partial_sum的范例如下:

template <class InputIterator, class OutputIterator>
OutputIterator partial_sum (InputIterator first, 
                            InputIterator last,
                            OutputIterator result);

其中前两项是输入SLT容器迭代器的起始和终止,后面的是输出STL容器的起始迭代器。
使用例子:

Solution(vector<int> weights): sums(std::move(weights)) {
	partial_sum(sums.begin(), sums.end(), sums.begin());
}

如果想自定义求和公式,其调用范例如下:

template <class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator partial_sum (InputIterator first, 
                            InputIterator last,
                            OutputIterator result, 
                            BinaryOperation binary_op);

partial_sum的头文件为:

#include <numeric>

2、lower_bound函数

该函数适用于找到target值对应的最靠左侧的(或者说是下标值最小)的下标。
使用范例

ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,const T& val);

头文件

#include <algorithm>

3、upper_bound函数
用于在指定范围内查找大于目标值的第一个元素。
使用范例:

/查找[first, last)区域中第一个大于 val 的元素。
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val);
//查找[first, last)区域中第一个不符合 comp 规则的元素
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,const T& val, Compare comp);

头文件

#include <algorithm>

注意:upper_bound函数在查找元素时,适用于在查找区间,STL容器为排好序的容器。
4、back_inserter 函数
用于在末尾插入元素。实现方法是构造一个迭代器,这个迭代器可以在容器末尾添加元素。这个迭代器是以安插(insert)方式而非覆写(overwrite)方式运作的
使用范例:

template <class Container>
  back_insert_iterator<Container> back_inserter (Container& x);

和partial_sum搭配使用的例子

 partial_sum(w.begin(), w.end(), back_inserter(pre));

5、 reverse函数
反转给定区间的STL容器元素,调用方式如下(以list容器和vector容器为例):

list<T> nums;
nums.reverse();
vector<T> temp;
reverse(temp.begin(), temp.end());

其头文件为:

#include <algorithm>

注意:
1)我们可以看到list和vector调用reverse的方式不同。这是由于list不支持随机迭代器(即不能出现 list.begin() + m这种访问方式),所以在底层算法中,设计了list.reverse()这种访问方式
2)sort()函数具有和reverse()函数相同的调用方式

6、 transform函数
transform函数是将一个容器的元素转移到另一个容器中,使用方法如下
在这里插入图片描述

vector<int> nums(n,1);
vector<int> res(n,0);
res.resize(nums.size());
transform(nums.begin(), nums.end(),res.begin());

其中transform函数可以和谓词配合使用,
比如将nums全部取反,存到res中

vector<int> nums(n,1);
vector<int> res(n,0);
res.resize(nums.size());
transform(nums.begin(), nums.end(),res.begin(), logical_not<bool>());

7、 for_each函数
用于遍历STL容器,其语法为
在这里插入图片描述
当_func为普通函数时,使用例子为
注意:普通函数时,只需要将函数名字输入进去就行

//普通函数
void print01(int val)
{
	cout << val << " ";
}

//for_each算法基本用法
void test01() {
	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	//遍历算法
	for_each(v.begin(), v.end(), print01);

当_func为仿函数时,使用例子为
注意:仿函数时,只需要将仿函数输入进去

//函数对象
class print02
{
public:
	void operator()(int val)
	{
	cout << val << " ";
	}
};
//for_each算法基本用法
void test01() {
	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	//遍历算法
	for_each(v.begin(), v.end(), print02());

8、 find函数
返回的是迭代器

在这里插入图片描述
注意:
1)binary_search是二分查找法进行查找,适合用于有序数组
2)这些函数返回迭代器,但是binary_search返回的是bool

9、 merge函数
将两个STL融合合并为一个,并排序

void main()
{
	vector<int> nums1;
	vector<int> nums2;
	for(int i = 0; i <10; i++)
		nums1.push_back(i);
	for(int i = 11; i <15; i++)
		nums2.push_back(i);
	vector<int> res;
	res.resize(nums1.size() + nums2.size());
	merge(nums1.begin(), nums1.end(), nums2.begin(), nums2.end(), res.begin());
}

注意:
1)合并前的两个容器需要是有序的,且有序的顺序是一样的(即都是升序或者都是降序)
2)合并的数组要提前分配空间

10、 random_shuffle函数
用于对数组的随机打乱

void main()
{
	srand((unsigned int)time(NULL));
	vector<int> nums1;
	for(int i = 0; i <10; i++)
		nums1.push_back(i);
	random_shuffle(nums1.begin(), nums1.end());
}

其中srand(保证每次随机结果不一样)

11、 replace函数
在这里插入图片描述
for an example

#include <algorithm>
#include <vector>
class myPrint
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
void test01()
{
	vector<int> v;
	v.push_back(20);
	v.push_back(30);
	v.push_back(20);

	cout << "替换前:" << endl;
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;
	//将容器中的20 替换成 2000
	cout << "替换后:" << endl;
	replace(v.begin(), v.end(), 20,2000);
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;
}
int main() {
	test01();
	
	return 0;
}

11、 replace_if函数
在这里插入图片描述
12、 accumulate函数
1)用于求解STL容器中的各元素总体和
2)头文件

#include <numeric>

3)语法
在这里插入图片描述
该函数的返回值就是STL容器的元素总和

13、 fill函数
1)用于将STL容器中所有的元素全部设置为相同元素
2)头文件

#include <numeric>

3)语法

在这里插入图片描述
14、set_union容器并集函数

在这里插入图片描述
for an example

class myPrint
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
void test01()
{
	vector<int> v1;
	vector<int> v2;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i);
		v2.push_back(i+5);
	}
	vector<int> vTarget;
	//取两个容器的和给目标容器开辟空间
	vTarget.resize(v1.size() + v2.size());
	//返回目标容器的最后一个元素的迭代器地址
	vector<int>::iterator itEnd =
	set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, myPrint());
	cout << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

注意:
1)两个容器需要是有序的序列
2)函数的返回值是输出矩阵最后元素对应位置的迭代器

15、set_intersection容器交集函数
在这里插入图片描述
for an example

class myPrint
{
public:
	void operator()(int val)
	{
	cout << val << " ";
	}
};
void test01()
{
	vector<int> v1;
	vector<int> v2;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
		v2.push_back(i+5);
	}
	vector<int> vTarget;
	//取两个里面较小的值给目标容器开辟空间
	vTarget.resize(min(v1.size(), v2.size()));
	//返回目标容器的最后一个元素的迭代器地址
	vector<int>::iterator itEnd =
	set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, myPrint());
	cout << endl;
}
int main() {
	test01();
	system("pause");
	return 0;
}

注意:
1)必须是有序容器
2)函数的返回值是输出矩阵最后元素对应位置的迭代器

16、set_difference容器差集函数
在这里插入图片描述
注意:所有的注意事项和前两项一致

四、string容器

1、string赋值操作

//方法1
string s1 = "hello";
//方法2
string s2 = s1;
//方法3
char m[5] = {'h', 'e', 'l', 'l', 'o'};
s2 = m;
//方法4
s2 = assign(s1);
s2 = assign(s1,n); // 其中n表示的是前n个字符
s2 = assign(n,'h'); //表示使用n个h填充s2

2、string相加

//方法一
string s1 = "hello";
string s2 = "world";
s1 = s1 + s2;
//方法二
char m[5] = {'h', 'e', 'l', 'l', 'o'};
s1 = s1 + m;
//方法三
char m1 = 'o';
s1 +=  m1;
//方法四
s1.append(s2);
//方法五
s1.append(m,n) //将char数组前n个元素加到字符串上
//方法六
s1.append(m);
//fangfa七
s1.append(s2, pos, n) //将字符串s2在下标pos处开始,n个元素加到s1处

3、查找和替换
在这里插入图片描述
注意:
1)以replace(int pos, int n, const string& s)为例,replace是将原始字符串从pos处开始的n个元素删除,将s增添在pos处,即:
s1.replace(pos,n,s) = s1.substr(0,pos) + s + s1.substr(pos + n);
而不是死磕n个长度
4、对比操作

string s1 = "hel";
string s2 = "mkl";
s1.compare(s2);

按照ASCII进行对比,当两个字符串相等时,返回0;当s1大时,返回1;

五、vector容器

1、vector赋值

vector<int> nums;
nums.push_back(1);
nums.push_back(2);
nums.push_back(3);
nums.push_back(4);

vector<int> nums1(nums);
nums1.assign(nums.begin(), nums.end());

2、swap

vector<int> nums1, nums2;
nums1.push_back(1);
nums1.push_back(2);
nums1.push_back(3);
nums1.push_back(4);

nums2.push_back(1);
nums2.push_back(2);
nums1.swap(nums2);

注意:
1)缩小nums1所占用的capacity,节约空间:
vector(nums1).swap(nums1);
2)彻底释放vector空间,使用swap()函数可以实现

3、reserve
用于设置预留空间大小,即

vector<int> nums;
nums.reserve(n);

表示预留大小为n的空间

六、deque容器

1、赋值
在这里插入图片描述

六、list容器

1、list容器插入与删除
在这里插入图片描述

七、set容器

1、插入

set<int> nums
nums.insert(10);
nums.insert(10);
nums.insert(30);
nums.insert(20);

注意:
1)set插入元素只有insert函数
2)set自动排序,即上面例子会自动保存为10,20,30
3)set不保存重复数字,即当插入n个1时,只保存一个
4)multiset可以插入重复数字
5)set的底层实现是二叉树
2、赋值
两种方式如下

set<int> s2(nums);
s2 = nums;

3、删除

set<int> nums
nums.insert(10);
nums.insert(10);
nums.insert(30);
nums.insert(20);
nums.erase(30);
nums.erase(nums.begin());

注意:
1)删除有两种方式,一种是直接将需要删除的值输入erase;另一种是将迭代器输入erase,但是这种一般用于删除首位或者尾部
4、从大到小存储元素
使用仿函数完成

class mycompare
{
	bool operator()(int a, int b)
	{
		return a < b;
	}
};

int main()
{
	set<int,mycompare> nums
	nums.insert(10);
	nums.insert(10);
	nums.insert(30);
	nums.insert(20);
	nums.erase(30);
	return 0;
}

此时nums存储的数据不是10,20,30;而是30,20,10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值