STL标准模板库

本文深入解析C++标准模板库(STL)中的各种容器,包括vector、deque、list、set、multiset、map、multimap、queue、priority_queue、stack及array的特性与使用方法,涵盖构造、赋值、迭代器、大小、插入、删除、查找等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STL主要分成三类:
algorithm(算法) : 对数据进行处理(解决问题)步骤的集合方式;
container(容器) : 用来管理许多不用类型数据元素的集合体;
iterator(迭代器) : 可遍历容器内的全部或者一部分的元素的对象;

使用STL的头文件有:

<algorithm> <functional> <iterator> <verctor> <deque> <list>
	<map> <memory> <numeric> <queue> <set> <stack> <utility>

算法 : 在STL中已经实现了的,我们只需要去调用接口就可以达到需要完成的 目的, 不需要去自己再实现算法,除非我们需要实现某些特定的算法时可以自己加入一些算法;

容器 : 分为以下几种 :
vector : (单端数组)

使用时要加 <vector> 头文件
它是将元素置于一个动态数组种加以管理的容器, 可以随机存取元素
      				支持索引值直接存取,[]操作符或at()方法对元素进行操作;
    
      vector使用方法:
      		对象构造:
      					 vector<T>v_T;    T为数据类型,(int,float,string,指针和类);
      					带参数构造: vector(v_T.begin(),v_T.end()); 构造函数将begin(),(元素最开始的值)
      					end(),(元素最后一个值+1的位置)中的元素拷贝给本身,
      					注意: 该区间是左闭右开的区间;
      					vector(n,elem); 构造函数将 n 个elem(元素)拷贝给本身;
      					vector(const vector&v1); 拷贝构造函数
      		赋值:
      					v1.assign(2,66); 改变vector中的元素的个数和值;
      					v1.assign(v2.degin(),v2.end());使用迭代器重新赋值
      					int demo[]={1,2,3,4};
      					v2.assign(demo,demo+3); 使用指针赋值
      					v1=v2; 赋值运算
      		vector的大小:
      					v1.size();  返回容器中元素的个数;
      					v1.empty(); 判断容器是否为空;
      					v1.resize(num); 重新指定容器的长度为num,若容器变长,则以默认值填充新位置,
      					如果容器变短,则末尾超出容器长度的元素被删除掉;
      					v1.resize(num,elem); 重新指定容器的长度为num,容器变长,则以elem值填充新	
      					位置,变短则末尾超出容器长度的元素被删除掉;
      		vector末尾添加和移除操作
      					v1.push_back(1);  在容器尾部加入一个元素,该元素对应的值为1;
      					v1.pop_back();     移除容器中最后一个元素
      		vector数据存取
      					使用下标操作  v1[0]=100;
      					使用at 方法     v1.at(0)=100;
      					接口返回的引用  v1.front()和 v1.back();
      					注意: 第一和第二种方式必须注意越界;
      		vector元素插入
      					v1.insert(pos,elem); 在pos位置插入一个elem元素的拷贝,返回新数据的位置;
      					v1.insert(pos,n,elem);在pos位置插入n个elem数据,无返回值;
      					v1.insert(pos,begin(),end());在pos位置插入(begin(),end())区间的数据,无返回值
      		vector元素删除
      					v1.clear();  删除所以元素;
      					v1.erase(v1.brgin()+1); 删除某个位置的单个元素
      					v1.erase(v1.begin(),v1.begin()+3);删除begin()到begin+3这个区间的所以元素

deque: (双端数组)

使用时加 <deque> 头文件
特点: 在接口上和vector非常相似,在许多操作的地方可以直接替换;
	  可以随机存取元素(支持索引值直接存取,[]操作符或at()方法);
	  头部和尾部添加或删除元素都非常快,但是在中部插入或移除元素就比较费时;
	  
		deque对象构造和vector一样,没有差异;
						deque<T>v1;				
		deque元素的添加和移除操作
						v1.push_back(elem); 容器尾部添加一个数据;
						v1.push_front(elem); 容器头部插入一个数据;
						v1.pop_back();       删除容器最后一个数据;
						v1.pop_front();     删除容器第一个数据;
		deque的数据存取和vector一样;就是在头部插入数据时没有vector费时;
		
		deque与迭代器
					v1.begin(); 返回容器中第一个元素的迭代器;
					v1.end();    返回容器中最后一个元素+1的位置的迭代器;	
					v1.rbegin();返回容器中倒数第一个元素的迭代器;
					v1.rend();   返回容器中倒数最后一个元素+1的位置的迭代器;
					v1.cbegin();返回容器中第一个元素常量的迭代器;
					v1.cend();   返回容器中最后一个元素+1的位置的常量迭代器;
				普通迭代器遍历
						for(deque<int>::iterator it=v1.begin();it!=v1.end();++it){
									(*it)++;//迭代器指针需要先解引再进行++;
									cout<<*it<<endl;
							}
				常量迭代器
						for(deque<int>::const_iterator it=v1.cbegin();it!=v1.cend();++it){
											cout<<*it<<endl;
							}
				逆转迭代器
						for(deque<int>::reverse_iterator it=v1.rbegin();it!=v1.rend();++it){
												cout<<*it<<endl;
							}
		deque赋值
				v1.assign(begin(),end());(begin(),end())区间的数据拷贝赋值
				本身,注意该区间是左闭右开的区间;
				v1.assign(n,elem);将n个elem拷贝赋值给本身;
				v1&opertor=(const v1&deq);重载赋值给本身;
				v1.swap(v2);将v1和v2的元素互换;
		deque的大小的使用方法和vector一样的;
		deque的插入方式和vector一样;
		deque的删除方式和vector一样;

list: 双向链表容器,可以高效地进行插入删除元素

需要 <list> 头文件
	特点:
		list不可以随机存取元素,所以不支持at.(pos)函数与[]操作符,可以对其迭代器
			执行++,但是不可以这样操作迭代器: it+3;   
		list对象的构造和vector一样;
		list头尾添加和移除元素操作和deque一样;
		list数据存取
					v1.front();  返回第一个元素;
					v1.back();  返回最后一个元素;
		list的迭代器和deque一样;
		list的赋值和deque一样;
	    list的大小操作和deque一样;
		list的插入和vector一样;
		list删除元素:
		    	v1.clear(); 移除容器所有数据
		    	v1.erase(begin(),end()); 删除(begin(),end())区间的数据,返回
		    					下一个数据的位置;
		    	v1.erase(pos); 删除pos位置的数据,返回下一个数据的位置;
		        v1.remove(elem); 删除容器中所有与elem值匹配的元素;
		list的反序排列			 
		    	v1.reverse();//反转链表,如1,2,3运行次方法后:3,2,1;

C++11新特性: 变参模板,完美转发和emplace(队列)
变参模板: 使得emplace可以接受任意参数,这样就可以适用于任何对象的
构造;
完美转发: 使得接收下来的参数,能够原样的传递给对象的构造函数,这带来
另一个方便性;

set和multiset容器(红黑树变体的数据结构所实现的容器)

需要头文件<set>
set和multiset是一个集合容器,其中set所包含的元素是唯一的,集合中的元
			素按一定的顺序排列,set采用红黑树变体的数据结构实现,红黑树属于平
			衡二叉树,在插入和删除操作上比vector快,在n个数中查找目标数的效率
			是log2n;
			红黑树定义: 每个节点都带有属性(红色或黑色)的自平衡二叉查找树;
			满足下列性质:
					节点是红色或黑色;
					根节点是黑色;
					所有叶子节点都是黑色节点(NULL);
					每个红色节点必须有两个黑色子节点,(从根到叶子的节点上不能有
					两个连续的红色节点);
					从任一节点到其每个叶子的所有简单路径都包含相同的黑色节点;
set和multiset的特点:
		set中元素插入过程是按排序规则插入,所以不能指定插入位置;
		set不可以直接存取元素,(不可以使用at(pos)[]操作符);
		set和multiset的区别在于:set支持唯一的键值,每个元素只可以出现一次;而
								multiset中同样的值可以出现多次;
		不可以直接修改set和multiset容器中的元素值,因为该类容器是自动排序的;
		如果希望修改一个元素值,必须先删除原有的元素,再插入新的元素;
set和multiset对象的构造和list一样;
仿函数(函数对象) function 头文件<functional>
		尽管函数指针被广泛用于实现函数回调,但C++还提供了一个重要的实现回调函数
		的方法,就是函数对象;
		function,翻译成函数对象,伪函数,它是重载了"()"操作符的普通类对象,从语法
		上讲,它与普通函数类型一样;
		<functional>头文件中包含的greater<>与less<>就是函数对象;
		greater<>和less<>的简单实现原理:
		struct greater{
				bool operator()(const int&left,const int&right){
					return(left>right);
					}
				}
		struct less{
				bool operator()(const int&left,const int&right){
					return(left<right);
					}
				}
		set和multiset容器就是调用函数对象的operator()方法比较两个值的大小;
set和multiset的插入和pair的用法:
		pair表示一个对组,它将两个值视为一个单元,把两个值捆绑在一起;
		pair<T1,T2>用来存放的两个值的类型,可以不一样,也可以一样,如T1为int,
		T2为string, T1,T2也可以是自定义类;
		pair.first是pair里面的第一个值,是T1类型;
		pair.second是pair里面的第二个值,是T2类型;
set和multiset的迭代器和list的迭代器一样;
set和multiset的大小和list一样,
		注意: 它们没有resize的方法;
set和multiset的删除和list的方式一样;
		删除区间内的某个或某些元素
		setInt是用set<int>声明的容器,假设它内部现已包含按顺序的1, 2, 3, 4元素
		set<int>::iterator itBegin=setInt.begin();
		++ itBegin;
		set<int>::iterator itEnd=setInt.begin();
		++ itEnd;
		++ itEnd;
		++ itEnd;
		setInt.erase(itBegin,itEnd);
		//此时容器setInt包含按顺序的1, 4, 5, 6四个元素。

		删除容器中第一个元素
		setInt.erase(setInt.begin());		//4, 5, 6

		删除容器中值为5的元素
		setInt.erase(5);               //4, 6

		删除setInt的所有元素
		setInt.clear();			//容器为空
set和multiset的查找
		v1.find(elem); 查找elem元素,返回指向elem元素的迭代器
		v1.count(elem);返回容器中值为elem的元素个数,对set来说,要么是0,要么是1
						对multiset来说,值可能大于1;
		v1.lower_bound(elem); 返回第一个>=elem元素的迭代器;
		v1.upper_bound(elem); 返回第一个>elem元素的迭代器;
		v1.equal_range(elem); 返回容器中与elem相等的上下限的两个迭代器,上限是
							  闭区间,下限是开区间,(begin(),end()),以上函数
							  返回两个迭代器,而这两个迭代器被封装在pair中;

map和multimap容器(关联式容器,如:储物柜)

需要头文件<map>
map是标准的关联式容器,一个map里存储的元素是一个键值对序列,(key,value)键值对,它提供基于key快速检索数据的能力;
				map中的key值是唯一的,集合中的元素按一定的顺序排列,元素插入过程
				是按排序规则插入,所以不能指定插入的位置;
				map底层的具体实现是采用红黑树变体的平衡二叉树的数据结构,在插
				入,删除和检索操作上比vector快很多;
				map可以直接存取key所对应的value,支持[]操作符,:map[key]=value;
		map和multimap的区别在于:
					map支持唯一键值,每个键只能出现一次,而multimap中相同键可以
					出现多次,multimap不支持[]操作符;
		map/multimap对象的构造和set一样;
					map<T1,T2>v1;T1和T2可以是各种数据类型,指针类型和自定义类型
		map的插入与迭代器
					v1.insert(...); 往容器插入元素,返回pair<iterator,bool>
					map中插入元素的方式有:
					map<int,string>mapStu;
					方式一、通过pair的方式插入对象
					mapStu.insert(  pair<int,string>(1,"张三")  );
					方式二、通过pair的方式插入对象
					mapStu.inset(make_pair(2, “李四”));
					方式三、通过value_type的方式插入对象
					mapStu.insert(  map<int,string>::value_type(3,"王五")  );
					方式四、通过数组的方式插入值
					mapStu[4] = "赵六";
					mapStu[5] = “陈七";
		注意:
				前三种方式,采用的是insert()方式,该方式返回值为pair<iterator,bool>
				第四种方式非常直观,但遇到相同的键时会进行覆盖操作,: 插入key
					为4的键值时,先在mapStu中查找主键为4的项,若没有,则将一个键生
					成为4,值为默认初始化值的对组插入到mapStu中,然后再将值改成
					"赵六",若发现已经存在4这个键,则修改这个键对应的value;
				string strName=mapStu[8];//取值操作或插入操作
				只有当mapStu存在8这个键时才是正确的取值操作,否则会自动插入一
					个实例,键值为8,值为默认构造时的初始值;
		map/multimap的迭代器和deque一样;	
		map/multimap 排序:
			map<T1,T2,less<T1> >  mapA;  //该容器是按键的升序方式排列元素。未指定函数对象,默认采用less<T1>函数对象。
   			map<T1,T2,greater<T1>> mapB;   //该容器是按键的降序方式排列元素。
			less<T1>与greater<T1>  可以替换成其它的函数对象functor。可编写自定义函数对象以进行自定义类型的比较,使用方法与set构造时所用的函数对象一样。

map对象的拷贝构造与赋值
		map(const map &mp);		     //拷贝构造函数
	    map& operator=(const map &mp);	//重载等号操作符
		map.swap(mp);				//交换两个集合容器
map/multimap的大小和set一样;
map的删除:
		map.clear();		//删除所有元素
		map.erase(pos);	//删除pos迭代器所指的元素,返回下一个元素的迭代器。
		map.erase(beg,end);//删除区间[beg,end)的所有元素	,返回下一个元素的迭代器。
		map.erase(key);     //删除容器中key为key的对组,返回删除的对组个数
		map.erase(key_type *first, key_type *last)  //删除数组指定的半闭半开的区间中特定的key对应的所有队组
			map<int, string> mapA;
		mapA.insert(pair<int,string>(2, "李四"));	  
		mapA.insert(pair<int,string>(1, "张三"));	
		mapA.insert(pair<int,string>(3, "王五"));	
		mapA.insert(pair<int,string>(4, "赵六"));	

		//删除区间内的元素,迭代器指示区间(半闭半开)
		map<int,string>::iterator itBegin=mapA.begin();
		++ itBegin;
		map<int,string>::iterator itEnd=mapA.end();
		mapA.erase(itBegin,itEnd);    //此时容器mapA仅仅包含{1,"张三"}一个元素。

		mapA.insert(pair<int,string>(2, "李四"));	
		mapA.insert(pair<int,string>(3, "王五"));	
		mapA.insert(pair<int,string>(4, "赵六"));

		//删除容器中的第一个元素,使用迭代器指示位置
		mapA.erase(mapA.begin());	//mapA包含{2,"李四"}{3,"王五"}{4,"赵六"}三个元素

		//删除容器中key为4的元素
		mapA.erase(4);    

		//删除mapA的所有元素
		mapA.clear();			//容器为空
map/multimap的查找:
		map.find(key);   查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end();
		map.count(key);   //返回容器中键值为key的对组个数。对map来说,要么是0,要么是1;对multimap来说,值>=0。
		map.lower_bound(keyElem);  //返回第一个key>=keyElem元素的迭代器。
		map.upper_bound(keyElem);	   //  返回第一个key>keyElem元素的迭代器。
		map.equal_range(keyElem);		//返回容器中key与keyElem相等的上下限的两个迭代器。上限是闭区间,下限是开区间,如[beg,end)。

queue(队列容器)
queue的队列容器,是一种"先进先出"的容器;
默认情况下queue是利用deque容器实现的一种容器;
它只允许在队列的前端(front)进行删除操作,而在队列的后端(back)进
行插入操作;

需要头文件<queue>
		queue的对象构造和vector一样;
		queue 对象的带参构造
		queue<int, list<int>> queueList;  //内部使用list 来存储队列元素的queue 容器.
		错误: queue<int, vector<int>> queueList; //内部不能使用vector来存储队列元素			
	queue的push()pop()方法
		queue.push(elem);   //往队尾添加元素
		queue.pop();       //从队头处移除队首元素
	queue对象的拷贝构造与赋值
		queue(const queue &que);		     //拷贝构造函数
		queue& operator=(const queue &que);	//重载等号操作符
	queue的数据存取
		queue.back();   //返回最后一个元素
		queue.front();   //返回第一个元素
	queue的大小使用方式和vector一样;
优先级队列priority_queue
	优先队列: 它的入队顺序没有变化,但是出队的顺序是根据优先级的高低来决定的,优先
			 级高的优先出队;
			最大值优先级队列,最小值优先级队列;
			用来开发一些特殊的应用;

stack: (堆栈容器) 头文件
stack是堆栈容器,是一种"先进后出"的容器

			//stack是基于deque容器而实现的容器。
#include <stack>  
stack对象的默认构造
stack采用模板类实现, stack对象的默认构造形式: stack <T> stkT;  
stack <int> stkInt;            //一个存放int的stack容器。
stack <float> stkFloat;     //一个存放float的stack容器。
stack <string> stkString;     //一个存放string的stack容器。
...				    
//尖括号内还可以设置指针类型或自定义类型。
stack的push()pop()方法 
stack.push(elem);   //往栈头添加元素
stack.pop();        //从栈头移除第一个元素

stack<int> stkInt;  	
stkInt.push(1);
stkInt.push(2);
stkInt.pop();   
stkInt.push(3);
此时stkInt存放的元素是1, 3
stack对象的拷贝构造与赋值
stack(const stack &stk);		     //拷贝构造函数
stack& operator=(const stack &stk);	//重载等号操作符

stack<int> stkIntA;
stkIntA.push(1);
stkIntA.push(2);
stkIntA.push(3);

stack<int> stkIntB(stkIntA);		//拷贝构造
stack<int> stkIntC;
stkIntC = stkIntA;				//赋值
stack的数据存取
stack.top();	  //返回最后一个压入栈元素

stack<int> stkIntA;
stkIntA.push(1);
stkIntA.push(2);
stkIntA.push(3);

int iTop = stkIntA.top();		//3
stkIntA.top() = 88;			//88
stack的大小
stack.empty();   //判断堆栈是否为空
stack.size(); 	     //返回堆栈的大小

stack<int> stkInt;
stkInt.push(1);
stkInt.push(2);
stkInt.push(3);
	
int iSize = stkInt.size();		//3

array容器(C++11新增)

array容器概念
1.array是将元素置于一个固定数组中加以管理的容器。
2.array可以随机存取元素,支持索引值直接存取, 用[]操作符或at()方法对元素进行操作,也可以使用迭代器访问
3.不支持动态的新增删除操作
4.array可以完全替代C语言中的数组,使操作数组元素更加安全!

array对象的构造
1.array采用模板类实现,array对象的默认构造形式(涉及非类型参数-数值类模板)
2.array<T,10>  arrT;   //10 为数值型模板参数

array<int, 6> a1;     //一个存放int的array容器
array<float, 6> a2;   //一个存放float的array容器
array<student, 6> a3; //一个存放student的array容器

array<int, 6> a1={1,2,3,4,5,6}; //定义时同时初始化

array的赋值
a2.assign(0);//第一种玩法  改变原来array中的所有元素的值
array<int, 6> a1 = {1, 2, 3};
array<int, 6> a2 ;

a2 = a1;    //第二种玩法 赋值运算,将a1 赋值给a2

array的大小
array.size();	    //返回容器中元素的个数
array.max_size(); //返回容器中最大的元素个数,与size 等同
array.empty();   //判断容器是否为空


array的数据存取 
第一  使用下标操作 a1[0] = 100;
第二  使用at 方法 如: a1.at(2) = 100;
第三  接口返回的引用 a2.front() 和 a2.back()
第四  返回内建数组的指针 a1.data()  
注意:   第一和第二种方式必须注意越界

注意:任何时候在模板(template)中使用一个嵌套从属类型名称, 需要在前一个位 置, 添加关键字typename;
比如上例中使用迭代器类型时,就要使用typename.虽然在vs2010 和vs2015中没有错误,但在VC++2019和gcc编译器中,都会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值