c++学习 STL

c++学习 STL

注:进阶版见深入学习c++ c++标准库体系结构与内核分析笔记

STL(standard template library)即标准模板库,顾名思义,是基于模板实现的。
他被内建在编译器中,无需下载即可使用。
广义上分为:容器(container)、算法(algorithm)、迭代器(iterator)。
思想:数据与算法分离,通过迭代器联系。
拥有以下特点:
1、高可重用性
2、高性能
3、高移植性
4、跨平台

容器
序列式容器:
容器中元素的位置是由元素进入的顺序决定的。

关联式容器:
其他排位规则的容器。

迭代器
类似于指针,默认指向容器中第一个元素,对指针的操作几乎都适用于迭代器。
但实际上迭代器是一个类对象,它封装了一个指针,并重载了一些操作符。
迭代器类型:

vector<T>::iterator

算法
算法可以通过迭代器对容器的元素进行操作。

-------------------------------------我是分隔符---------------------------------------------

-------------------------------------我是分隔符---------------------------------------------

string容器

char是一个指针,string是一个类。
string封装了char
,管理这个字符串,是一个char*型的容器。

初始化

string str1;
string str2("hello");
str1 = "hello";
str1 = str2;
str1 = 'h';

取单个字符

str1[1];
str1.at(1);

区别:当访问越界时,[]方式直接程序挂掉,而at方式会抛出异常out_of_range。

常用api
拼接:
在这里插入图片描述
查找和替换:
在这里插入图片描述
比较:
在这里插入图片描述
取子串:
在这里插入图片描述

插入和删除:
在这里插入图片描述
-------------------------------------我是分隔符---------------------------------------------

vector容器

vector是一个动态数组或可变数组。

动态原理:
当vector的容量不足时,系统会开辟一块更大的新空间,将原数据拷贝进
来,加入新数据,之后将原空间释放。

初始化:(包含<vector>
在这里插入图片描述初始化例子:

int array[2]= { 1,2 };	
vector<int> a(array,array+sizeof(array)/sizeof(int));
vector<int> b(a.begin(),a.end());
vector<int> c(3,4);
vector<int> d(c);

操作基础:

myvector.begin();	//迭代器,指向第一个元素
myvector.end(); 	//迭代器,指向最后一个元素的后一个位置
myvector.rbegin(); 	//迭代器,指向倒数第一个元素
myvector.rend();  	//迭代器,指向第一个元素的前一个位置

赋值操作:
在这里插入图片描述
大小操作:
在这里插入图片描述
注:容量>=元素个数

存取操作:
在这里插入图片描述
注:取容器的首地址应该是&(myvector[0]),而不能是myvector,因为myvector只是一个类名,它内部维护的一个指针才是指向元素内存空间的。

插入和删除:
在这里插入图片描述
注:
1、vector是一个单向容器,适用于频繁处理末尾元素的情况,使用insert时效率将十分低下。
2、添加元素时vector会自动增长容量,但是在删除元素时,vector不会自动缩减容量(resize也不会)。
所以可以使用swap来收缩空间:

vector<t>(v).swap(v);
//v即要收缩的容器
//vector<t>(v)是拷贝v的匿名对象
//交换后,语句结束,匿名对象(此时已经成为了原来的v)被释放

-------------------------------------我是分隔符---------------------------------------------

deque容器

与vector不同的是,deque是一个双向容器。
增加了在对首的存取(push_front和pop_front)。
他双端插入和删除元素效率较高,但指定位置插入也会导致数据元素移动,效率低下。

原理:
在这里插入图片描述
就是说,deque将数据储存为多块,需要时开辟一块,不需要后收回一块,所以我们不用考虑容器容量远大于元素数量的情况(收缩空间)。
也由于这种原理,对于deque的排序效率将十分低下,常常将deque中的数据拷贝到vector中,排序后再送回。

构造:
在这里插入图片描述
赋值:
在这里插入图片描述

大小操作:
在这里插入图片描述
插入删除:
在这里插入图片描述
数据存取:
在这里插入图片描述
-------------------------------------我是分隔符---------------------------------------------

stack容器

stack容器即栈容器,基本规则:先进后出
注:
1、不提供迭代器
2、不能遍历
3、不能随机存取

构造:
在这里插入图片描述
赋值:
在这里插入图片描述
存取:
在这里插入图片描述

大小操作:
在这里插入图片描述
-------------------------------------我是分隔符---------------------------------------------

queue容器

queue容器即队列容器,基本规则:先进先出
支持在一端(队尾)插入和在一端(队首)删除。
注:
1、不提供迭代器
2、不能遍历
3、不能随机存取

构造:
在这里插入图片描述
存取、插入和删除:
在这里插入图片描述
赋值:
在这里插入图片描述
大小操作:
在这里插入图片描述
-------------------------------------我是分隔符---------------------------------------------

list容器

list容器即链表容器。
特点:
1、非连续存储,因此插入和删除的效率都高。
2、无需考虑收缩内存。
3、不支持随机存取,只能通过首地址++。

构造:
在这里插入图片描述

插入和删除:
在这里插入图片描述
大小操作:
在这里插入图片描述
在这里插入图片描述
赋值:
在这里插入图片描述
存取:
在这里插入图片描述
反转与排序:
在这里插入图片描述
注:
对于sort,它是list内置的函数,而不是一个算法。
算法中的sort只支持可随机存取的容器。

若list中存放的是基本数据类型,则sort默认按照从小到大排序。
若想从大到小排序,需:

bool myCompare(int v1,int v2){
	return v1 > v2;
}

myList.sort(myCompare);

若list中存放的是类,则:

bool myCompare(const Student& a, const Student& b){
	return a.Average > b.Average;
}

myList.sort(myCompare);

//-----------------------------------------------------------
//或者使用

myList.sort(lambda表达式);

-------------------------------------我是分隔符---------------------------------------------

priority_queue容器

https://blog.csdn.net/weixin_52115456/article/details/127606811

set和multiset容器

set和multiset是关联式容器,它所有元素都会根据元素的值自动排序。
set和multiset以红黑树(RB-tree,平衡二叉树的一种)为底层机制,查找效率非常好。
注:
1、set不允许元素重复,multiset允许。
2、set和multiset提供迭代器,但是不能通过迭代器修改数据的值。
3、set和multiset包含<set>即可。

构造:
在这里插入图片描述
赋值:
在这里插入图片描述
大小操作:
在这里插入图片描述
插入和删除:
在这里插入图片描述
注:
insert的默认顺序是从小到大,要想编为从大到小,就要用到:
仿函数

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

将这个仿函数类作为set模板的第二个参数,就可以改变排序顺序:

set<int,mycompare> myset;

查找:
在这里插入图片描述注:
equal_range返回lower_bound和upper_bound两个值,是通过返回pair模板类来实现的。

pair
对组(pair)将一对值合成一个值,这两个值可以类型不同,通过pair.first和pair.second来访问。
在这里插入图片描述在这里插入图片描述

使用案例:
专家评分,去最低和最高,并排出名次。

-------------------------------------我是分隔符---------------------------------------------

map和multimap容器

map与set的区别在于map有键值(key)和实值(value),而set不分键值和实值。
map中存放pair(pair见set和multiset容器末尾),其中pair的first是键值,second是实值。
map也是以红黑树为底层实现机制。
map按key值排序,故map中key值不能重复,而multimap可以。
map不允许通过迭代器改变其键值,但是允许通过迭代器改变其实值。

include <map>

构造:
在这里插入图片描述
赋值:
在这里插入图片描述
大小操作:
在这里插入图片描述
插入:
在这里插入图片描述
注:
前三种插入方式会返回一个pair<iterator,bool>,可以得到插入位置的迭代器和插入是否成功的结果。且当插入元素的键值已存在时,会插入失败。
而第四种方式,[]里的是key值,当key值不存在时,会插入这个新的元素,当key值存在时会修改其value。

输出时可以:

cout<<mymap[10]<<endl;

但是如果cout的是一个不存在的键值,则会插入这个新元素并默认初始化。

使用案例:
招聘员工时,员工信息分组,使用multimap每个组号是一个键值。

-------------------------------------我是分隔符---------------------------------------------

一些问题

1、STL容器所提供的都是值(value)寓意,而非引用(reference)寓意,也就是元素通过浅拷贝装进容器,所以当我们要把一个含有指针成员的类装进容器时,一定要实现它的深拷贝构造。
另外,建议在一个类中实现拷贝构造时,同时也实现=操作符的重载。(便于他人的使用)

2、通常STL不会抛出异常,需要使用者传入正确参数。

适用场景(仅供参考)

在这里插入图片描述
vector的使用场景: 比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。
deque的使用场景: 比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢。
list的使用场景︰ 比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。
set的使用场景: 比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
map的使用场景: 比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用户。

查找算法

如果查找目标为aim。
find

vector<T>::iterator ret = find(myvector.begin(),myvector.end(),aim);
//find返回迭代器
if(ret == myvector.end()){
	cout<<"未找到"<<endl;
}
else{
	cout<<"找到了"<<endl;
}

find_if
与find不同的是,find_if的第三个参数是一个回调函数(可以自己写),就是说find_if遍历时将每个元素传入回调函数中,如果回调函数返回true,则就是找到了。

binary_search
二分法查找,使用前提是容器元素有序,不返回迭代器。

bool ret = binary_search(myvector.begin(),myvector.end(),aim);
//找到了返回true。

adjacent_find
查找相邻重复元素,使用前提是容器元素有序,返回相邻重复元素第一个位置的迭代器。

vector<T>::iterator ret = adjacent_find(myvector.begin(), myvector.end());

count
查找某元素出现的个数,并返回。

int num = count(myvector.begin(),myvector.end(),aim);

count_if
与find_if同理。

遍历算法

#include<algorithm>

for_each
按照回调函数(_callback)的功能进行遍历。

for_each(myvector.begin(),myvector.end(),_callback);

transform
将指定容器(myvector)区间元素搬运到另一容器(myvector2)中。
注意: transform不会给目标容器分配内存,所以需要我们提前分配好内存。

transform(myvector.begin(),myvector.end(),myvector2.begin(),_callback);

myvector区间元素经过回调函数处理后的返回值送入myvector2。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值