概述
从大一下学习C++,老师就说STL是C++精华,“C语言的指针,C++的STL”,结果一直都没什么时间专门去学STL,结果现在到了大三下为了保研夏令营,要开始学习STL咯;
目录
1、STL介绍
2、STL容器--vector
1、vector的定义:
2、vector访问
3、vector实例解析
4、vector的常见用途
2、STL容器 --set
1、set定义
2、set容器内元素访问
3、set常用函数实例解析
4、set的常见用途
3、STL容器--string
1、string的定义与访问
2、通过迭代器访问
3、常用函数解析
4、STL容器--map
1、map的定义
2、map元素访问
3、常用函数解析
4、常见用途
5、STL容器--queue(无迭代器)
1、定义
2、常用函数解析
3、常见用途
6、容器--Stack(无迭代器)
1、定义
2、常用函数解析
7、STL常用算法
1、max() min()
2、abs()
3、swap(x,y)
4、reverse(it,it2)
5、next_permutation(it1,it2)
6、sort()
7、max_element 、min_element
8、__gcd(x,y)
8、Pair容器
1、Pair容器的定义
2、Pair对象的操作
3、Pair类型作为哈希表的key
9、Priority_queue优先队列
1、常见方法
2、构造函数
3、元素是pair的priority_queue
4、自定义类型的优先队列
5、例子
10、list
1、构造函数
2、常见函数
1、STL介绍
STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称。现在虽说它主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间。
STL的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL变得非常通用。例如,由于STL的sort()函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组;
STL另一个重要特性是它不是面向对象的。为了具有足够通用性,STL主要依赖于模板而不是封装,继承和虚函数(多态性)——OOP的三个要素。你在STL中找不到任何明显的类继承关系。这好像是一种倒退,但这正好是使得STL的组件具有广泛通用性的底层特征。另外,由于STL是基于模板,内联函数的使用使得生成的代码短小高效;
STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模版函数的方式,这相比于传统的由函数和类。
组成的库来说提供了更好的代码重用机会。在C++标准中,STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、<memory>、<numeric>、<queue>、<set>、<stack>和<utility>。
STL中六大组件:
1)容器(Container),是一种数据结构,如list,vector,和deques ,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器;
2)迭代器(Iterator),提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符地方法的类对象;
3)算法(Algorithm),是用来操作容器中的数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用;
4)仿函数(Function object)
5)迭代适配器(Adaptor)
6)空间配制器(allocator)
2、STL容器--vector
vector是一个比较常用的容器之一,翻译成向量,也可以叫做变长数组
使用前需要加入#include《vector》;以及using namespace std;
1、vector的定义:
vector <typename> name
typename可以是int,char,或者是STL容器,需要注意的是,假如typename也是STL容器的话,定义的时候记得在>>之间加空格:
vector <int> age;
vector <vector <int> > age; //类似于二维数组
// 二维数组还可以这么定义
vector <int> age[100];
//vector的构造函数
vector(size_type Count); 创建一个大小为Count的向量vect
vector(size_type Count,const Type& Val); 创建一个大小为Count的向量,该向量中所有的元素都初始化为Val
//二维数组,第一维数组的长度为vn,值是一个数组,而这个数组的初值为MAX_INT,即为二维数组
vector<vector<int> > Graph(vertex_num, vector<int>(vertex_num, MAX_INT));
第二种二维数组定义确定了一维的范围【0-99】,age[0]到age[99]都是一个vector<int>
2、vector访问
(1)普通下标:vi[1]
(2)迭代器访问:迭代器是指针哦!!
vector<int>::iterator it;
it=vi.begin();
it=vi.begin()+3; //和 “&vi[3]” 一样
vi[i]和*(vi.begin()+i)是一样的
既然提到了.begin(),还要提一下.end(),和.begin()首元素地址不一样,.end()是末尾元素地址的下一个地址。end()作为迭代器末尾的标志,不存储任何元素。即左闭右开;
只有vetcor和string的迭代器才允许加上整数这种写法 (vi.begin()+3);
3、vector实例解析
(1)push_back(x):向末尾添加一个元素x,时间复杂度为O(1)
(2)pop_back():末尾删除一个元素,时间复杂度为O(1)
(3)size():获得vector元素个数,时间复杂度为O(1)
(4)clear():清除所有元素,时间复杂度为O(N)
(5)insert(it,x):在迭代器it位置插入元素x,时间复杂度为O(N);原来的元素向后移
(6)erase(it):在迭代器it位置删除元素
(7)erase(first,last):在迭代器[ first,last )位置删除元素,不包括last
//删除vi[1],vi[2],vi[3]
vi.erase(vi.begin()+1,vi.begin()+4);
4、vector的常见用途
(1)存储数据
作为数组使用可以节省空间;
无需提前知道有多少个数据
(2)用邻接表存储图
2、STL容器 --set
set翻译成集合,是一个内部自动有序且不重复的容器。
需要提前加入#include <set>
1、set定义
和vector一样
set<int> age;
2、set容器内元素访问
set的元素只能通过迭代器访问:
set<char>::iterator it;
只有vetcor和string的迭代器才允许加上整数这种写法 (vi.begin()+3);
因此在set中遍历元素只能自增:it++或者++it
对了,不支持it<st.end()这种写法,遍历只能it!=st.end()这样写
3、set常用函数实例解析
(1)insert(x),插入元素x在set中,自动去重排序,时间复杂度为O(logN)
(2)find(value),返回set中对应值为value的迭代器,时间复杂度为O(logN) //没找到就是set.end()
(3)erase(it),在迭代器it位置删除元素,时间复杂度为O(1)
(4)erase(value),在迭代器删除元素value,时间复杂度为O(logN)
(5)erase(first,last):在迭代器[ first,last )位置删除元素,不包括last,时间复杂度为O(lats-first)
(6)size():获得set元素个数,时间复杂度为O(1)
(7)clear():清除所有元素,时间复杂度为O(N)
4、set的常见用途
自动排序且按升序排序
(1)multiset 不用处理唯一情况
(2)unordered_set 只去重不排序,速度比set快
3、STL容器--string
为了防止出现使用char[]而产生的错误,STL使用string来对字符串进行操作
同样,需要加入#include <string>
1、string的定义与访问
string str;
cin >> str; //输入
printf("%c",str[1]);
cout << str; //输出
输入输出string只能使用cin、cout,如果偏要使用printf(),那么c_str()将string转化为字符数组进行输出
printf("%s",str.c_str());
2、通过迭代器访问
和其他容器不一样,string的迭代器不需要参数
string::iterator it1;
通过迭代器可以访问string的每一位,且string迭代器和vector迭代器一样,可以直接加减数字
3、常用函数解析
(1)operator +=
(2)== != >= <= 比较方法是字典序
(3)length() size()
(4)insert(it,it2,it3) 被插入的位置是it,插入的字符串是 [ it2 , it3)
(5)erase(it) 删除单个字符
(6)erase(first,last):在迭代器[ first,last )位置删除元素,不包括last,时间复杂度为O(lats-first)
(7)erase( pos,length):pos为开始需要删除的位置,length为长度
(8)clear() 清空字符串,时间复杂度为O(1)
(9)substr(pos,len) 返回从位置从pos,长度为len的字符串子串
(10) find(str2) 返回str2出现的第一次次数,如果没有,返回string::npos 即-1,时间复杂度为O(m*n)
(11) find(str2,pos) 从Pos位置开始匹配,返回值与上面一样,时间复杂度为O(m*n)
(12)replace(pos,len,str2) 从pos 开始,长度为n的字符串被取代为str2,两个字符长度不一定要相同
(13)replace(it1,it2,str2) [it1,it2)的字符串被取代为str2,两个字符长度不一定要相同
4、STL容器--map
1、map的定义
键可以是字符串,可以是char,但是不能是char数组,map的键和值都可以是STL 容器
值得注意的是,Map需要两个tyoe,前者是键,后者是值
map<string,double> mp1;
map< set<int>,int >mp2;
2、map元素访问
1)通过下标
mp['c']=30 //定义且赋值
mp['c']=20 //更改值
2)通过迭代器访问
map<string, int>::iterator it1;
it1->first是键
it2->second是值
map的键也会从小到大排序,由于map内部是红黑树实现(set也是这样实现)
3、常用函数解析
(1)find(key) 返回键为key的迭代器,时间复杂度为O(logN)
(2)erase(it1) 删除单个元素,参数是迭代器
(3)erase(key) 删除单个元素,参数是键名
(4)erase(it1,it2) 删除区间内的元素,参数是迭代器
(5)size() 大小
(6)clear() 清空map中的元素
(7)lower_bound(key) 返回一个指向当前map容器中第一个大于或等于key键值对的双向迭代器
(8)upper_bound(key). 返回一个指向当前map容器中第一个小于或等于key键值对的双向迭代器
4、常见用途
- 需要判断大整数或者其他数据类型是否存在的问题,可以把map当作bool数组使用
- 字符串与字符串的映射需要用到需要建立字符(串)与整数之间映射关系
queue和stack千万注意:
1、for循环当中条件判断中有.size(),因为在poppush之后会size会动态变化
最好是使用while(!stack1.empty())
2、push()和pop()没有返回元素
5、STL容器--queue(无迭代器)
queue是访问限制性函数,只允许先进先出每一次只允许使用front()访问队首元素,使用back()访问队尾元素
1、定义
#include <queue>
using namespace std;
queue<int> queue1;
2、常用函数解析
以下函数时间复杂度都为O(1)
- push(x),将x从队尾入列
- x=front( ) 队首元素
- x=back( ) 队尾元素
- pop() 队首元素出列
- empty() 判断是否为空
- size() 大小
3、常见用途
当需要 实现广度优先搜索时,可以直接使用queue
注意!:使用front()和back()前需要判断是否为空empty(),否则会出现错误
延伸:
- deque()双端队列:首尾皆可以插入删除
- priority_queue():使用堆实现的默认将当前队列最大的元素置于队首的容器
6、容器--Stack(无迭代器)
使用#include<stack>
只有栈顶元素可以被外界使用,也就是说 stack 不具有遍历行为,没有迭代器。
1、定义
#include<stack>
using namespace std;
stack<int> s1;
stack<int> s2(s1);
2、常用函数解析
push(elem);//向栈顶添加元素
pop();//从栈顶移除第一个元素
top();//返回栈顶元素
empty();//判断堆栈是否为空
size();//返回堆栈的大小
7、STL常用算法
使用#include <algorithm>
1、max() min()
这两个函数的参数只能是两个
2、abs()
返回绝对值,参数必须是整数,如果是浮点数,那么必须用math的fabs
3、swap(x,y)
交换x,y的值
4、reverse(it,it2)
将数组指针或者容器迭代器在[it,it2)范围内的元素进行反转
5、next_permutation(it1,it2)
给出一个序列的下一个全排列序列
利用next_permutation的返回值,判断是否全排列结束(否则将死循环)
注意!!!
一开始是从当前序列“1,2,5,4,3”开始,而不是自动排好序开始
知道输出完最大全排序“5,4,3,2,1”之后,当前全排列变成最小的全排序序列“1,2,3,4,5”
6、sort()
需要头文件<algorithm>
语法描述:sort(begin,end,cmp),cmp参数可以没有,如果没有默认非降序排序。
对数组升序:sort(a,a+5);
若设计为非升序排序,则cmp函数的编写:
bool cmp(int a,int b){
return a>b;
}
7、max_element 、min_element
从一个范围中获取最大/最小的元素的地址,记住是地址
8、__gcd(x,y)
__gcd(x,y)是algorithm库中的函数,主要是用于求两个数的最大公约数
8、Pair容器
pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同
1、Pair容器的定义
基本的定义如下:
pair<int, string> a;
pair<string, string> a("James", "Joy");
2、Pair对象的操作
1、对于pair类,由于它只有两个元素,分别名为first和second,因此直接使用普通的点操作符即可访问其成员
pair<string, string> a("Lily", "Poly");
string name;
name = pair.second;
2、生成新的pair对象
可以使用make_pair对已存在的两个数据构造一个新的pair类型:
int a = 8;
string m = "James";
pair<int, string> newone;
newone = make_pair(a, m);
3、Pair类型作为哈希表的key
// 1、首先实现hash function
struct hash_pair {
template <class T1, class T2>
size_t operator()(const pair<T1, T2>& p) const
{
auto hash1 = hash<T1>{}(p.first);
auto hash2 = hash<T2>{}(p.second);
return hash1 ^ hash2;
}
};
// 2、接下来把这个hash函数传给unordered_map就OK了!
unordered_map<pair<int,int>, int, hash_pair> um;
// 因为map容器并不需要hash函数,所以将key设置为pair是不会报错的。在数据量不大的情况下,也可以考虑使用map替代unordered_map,性能并不会有太大差异。
9、Priority_queue优先队列
首先要包含头文件#include<queue>
, 他和queue
不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队。
1、常见方法
- top 访问队头元素
- empty 队列是否为空
- size 返回队列内元素个数
- push 插入元素到队尾 (并排序)
- emplace 原地构造一个元素并插入队列
- pop 弹出队头元素
- swap 交换内容
2、构造函数
//升序队列,小顶堆
priority_queue <int,vector<int>,greater<int> > q;
//降序队列,大顶堆
priority_queue <int,vector<int>,less<int> >q;
//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数)
3、元素是pair的priority_queue
priority_queue<pair<int, int> > a;
默认只按照第一个成员,即first来排序,如果相等按照第二个元素
4、自定义类型的优先队列
#include <iostream>
#include <queue>
using namespace std;
//方法1
struct tmp1 //运算符重载<
{
int x;
tmp1(int a) {x = a;}
bool operator<(const tmp1& a) const
{
return x < a.x; //大顶堆
}
};
//方法2
struct tmp2 //重写仿函数
{
bool operator() (tmp1 a, tmp1 b)
{
return a.x < b.x; //大顶堆
}
};
5、例子
一个可以使用优先队列求解的问题:使用的是pair优先队列,https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/
10、list
list:list就是数据结构中的双向链表(根据sgi stl源代码),内存空间是不连续的,没有提供[]操作符的重载。可以很好的效率支持任意地方的删除和插入。
1、构造函数
list() 声明一个空列表;
list(n) 声明一个有n个元素的列表,每个元素都是由其默认构造函数T()构造出来的
list(n,val) 声明一个由n个元素的列表,每个元素都是由其复制构造函数T(val)得来的
list(n,val) 声明一个和上面一样的列表
list(first,last) 声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素
2、常见函数
begin和end获取的是迭代器,front和back是元素
begin()和end():通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator,可以调用list容器的 end() 函数来得到list末端下一位置
push_back() 和push_front()
pop_back和pop_front():通过删除最后一个元素,通过pop_front()删除第一个元素;序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。
front()和back(): 通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。
insert():在指定位置插入一个或多个元素(三个重载):
l1.insert(l1.begin(),100); 在l1的开始位置插入100。
l1.insert(l1.begin(),2,200); 在l1的开始位置插入2个100。
l1.insert(l1.begin(),l2.begin(),l2.end());在l1的开始位置插入l2的从开始到结束的所有位置的元素。
erase():删除一个元素或一个区域的元素(两个重载)
l1.erase(l1.begin()); 将l1的第一个元素删除。
l1.erase(l1.begin(),l1.end()); 将l1的从begin()到end()之间的元素删除。
参考资料:
【1】《算法笔记》--胡凡
【2】《C++标准模板库(STL)—简介》--https://blog.csdn.net/qing101hua/article/details/70313550
最后
以上就是喜悦柜子为你收集整理的STL入门学习与STL总结--更新中1、STL介绍2、STL容器--vector2、STL容器 --set3、STL容器--string4、STL容器--map5、STL容器--queue(无迭代器)6、容器--Stack(无迭代器)7、STL常用算法8、Pair容器9、Priority_queue优先队列10、list的全部内容,希望文章能够帮你解决STL入门学习与STL总结--更新中1、STL介绍2、STL容器--vector2、STL容器 --set3、STL容器--string4、STL容器--map5、STL容器--queue(无迭代器)6、容器--Stack(无迭代器)7、STL常用算法8、Pair容器9、Priority_queue优先队列10、list所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复