本周主要学习了字符串(string)、栈(Stack)、队列(queue)、动态数组(vector)、优先队列(priority_queue)、set和multiset、map和multimap以及sort函数、去重(unique)、生成排列、upper_bound 和 lower_bound。学的比较多,主要是了解相关简单用法,熟悉基本操作,并学会在解题中用STL知识优化解题步骤。刚开始接触STL,发现许多容器的用法有一定的相似之处,之前做了一些题,也不太能分清楚STL里各种容器等的用途及用法,现将它们放在一起做一些简单汇总,以下为知识点的简单整理回顾。(心得体会在最后)
字符串string类
1.头文件#include<string>
常用操作 | 说明 |
---|---|
os<<s | 将s写到输出流os中,返回os |
is>>s | 从输入流is读取字符串赋给s,字符串以空白分隔,返回is |
getline(is,s) | 从输入流is中读取一行赋给s,返回is |
s.empty() | s为空返回true,否则返回false |
s.size() | 返回s中字符的个数 |
s[n] | 返回s中第n个字符的引用,位置n从0开始计 |
s.c_str() | 转换,返回s中内容对应的c风格字符串首地址 |
s1=s2 | 赋值,用s2的副本替换s1原来的内容 |
s1+s2 | 连接,返回s1和s2连接后的结果 |
s1+=s2 | 追加,把s2的内容追加到s1后面 |
s1==s2 | 如果s1和s2长度相同且字符完全一样,则相等; |
s1!=s2 | string对象的比较对字母区分大小写 |
<,<=,>,>= | 利用字符在字典中的顺序进行比较,宇母区分大小写 |
2.string的创建
string s1,s2; //创建两个空字符串对象
string s3="Hello,Word!"; //创建s3,并初始化
string s4("I am"); //创建s4,并初始化
s2="Today"; //对对象赋值
3.读写string对象
- 使用标准库中iostream可以读写string对象
- 可用循环读取未知数量的string对象
- getline()函数
两个参数:输入流对象和string对象
遇到换行符为止,空格可被读入。
返回参数输入流对象
string line; while(getline(cin, line)) cout << line << endl;
栈(Stack)
1.说明:栈是一种后进先出的数据结构,在STL的stack中只能通过top()来访问栈顶元素。栈只能在某一端插入和删除数据,先进的数据被压入栈底,最后进入的数据在栈顶(即允许进行插入删除操作的一端称为栈顶,另一端称为栈底)
2.定义:头文件#include <stack>
stack<data_type> stack_name;
如:stack <int> s;
3.操作:
empty() -- 返回bool型,表示栈内是否为空 (s.empty() )
size() -- 返回栈内元素个数 (s.size() )
top() -- 返回栈顶元素值 (s.top() )
pop() -- 移除栈顶元素(s.pop(); )
push(data_type a) -- 向栈压入一个元素a (s.push(a); )
4.常见用途
用栈来模拟实现一些递归,防止程序对栈内存的限制而导致程序运行出的错。一般来说, 程序的栈内存空间很小,对有些题目来说,如果用普通的函数来进行递归,一旦递归层数过深(则会导致程序运行崩溃。如果用栈来模拟递归算法的实现,则可以避免这一方面的问题。
队列(queue)
1.说明:队列是一种先进先出的数据结构,在STL中只能通过front()访问队首元素,通过back()访问队尾元素,从底端加入元素,从顶端取出元素。
2.定义:头文件#include <queue>
queue <data_type> queue_name
如:queue <int> q
3.操作:
empty() -- 返回bool型,表示queue是否为空 (q.empty() )
size() -- 返回queue内元素个数 (q.size() )
front() -- 返回queue内的下一个元素 (q.front() )
back() -- 返回queue内的最后一个元素(q.back() )
pop() -- 移除queue中的一个元素(q.pop(); )
push(data_type a) -- 将一个元素a置入queue中(q.push(a); )
4.常见用途
当需要实现广度优先搜索时,可以不用自己手动实现一个队列,而是用队列作为代替,以提高程序的准确性。
注意:使用front()和pop()函数前,必须用empty()判断队列是否为空,否则可能因为队空而出现错误。
延伸:STL的容器中还有两种容器跟队列有关,分别是双端队列(deque)和优先队列(priority_queue),前者是首尾皆可插入和删除的队列,后者是使用堆实现的默认将当前队列最大元素置于队首的容器。
优先队列(priority_queue)
1.说明:优先队列底层是用堆来进行实现的。在优先队列中,队首元素一定是当前队列中优先级最高的那一个。
可以在任何时候往优先队列里面加入(push)元素,而优先队列底层的数据结构堆(heap)会随时调整结构,使得每次的队首元素都是优先级最大的。
2.定义:头文件: #include <queue>
priority_queue <data_type> priority_queue_name;
如:priority_queue <int> q;//默认是大顶堆
3.操作:
q.push(elem) 将元素elem置入优先队列
q.top() 获得队首元素
q.pop() 移除队首元素
q.size() 返回队列中元素的个数
q.empty() 返回优先队列是否为空
4.注意:和队列不一样的是,优先队列没有front()函数与back()函数,而只能通过top()函数来访问队首元素,也就是优先级最高的元素。
5.priority_queue<int, vector<int>, less<int>> q;
这种定义多了两个参数:一个是vector,另一个是less。其中vector(也就是第二个参数)填写的是来承载底层数据结构堆(heap)的容器,第三个参数less则是对第一个参数的比较类,less表示数字大的优先级越大,而greater表示数字小的优先级越大。
如果想让优先队列总是把最小的元素放在队首,只需进行如下定义:
priority_queue<int, vector<int >, greater<int>>q;
# include < stdio.h>
#include <queue>
using namespace std;
int main ()
{
priority_queue<int, vector<int>, greater<int>> q;
q.push (3);
q.push (4);
q.push (1);
printf ("d\n", q.top ());
}
输出结果为1
6.常见用途
优先队列可以解决一些贪心问题,注意,使用top()函数前,必须用empty()判断优先队列是否为空,否则可能因为队空而出现错误。
Vector-动态数组
1.说明:变长数组,长度根据需要而自动改变的数组。
2.定义:头文件#include<vector>
vector <data_type> vector_name
如:vector <int> v
数组定义:vector<typename> Arrayname[arraysize]
如:vector<int> vi[100]
3.操作:
empty() -- 返回bool型,表示vector是否为空 (v.empty() )
size() -- 返回vector内元素个数 (v.size() ),返回unsigned类型
push_back(data_type a) --将元素a插入最尾端(v.push_back())
pop_back()-- 将最尾端元素删除(v.pop_back())
v[i]-- 类似数组取第i个位置的元素(v[0] )
clear()--清空vector中所有元素(v.clear())
insert()--insert(it,x)向vector的任意迭代器it处插入元素x (如:v.insert(v.begin() + 2 , -1 );将-1插入v[2]的位置)
erase()--两种用法:删除单个元素erase(it)、删除一个区间内的所有元素erase(first, last)即删[first, last)
v.erase(v.begin() , v.end())
通过迭代器访问:
1)定义:vector<typename>::iterator it
如:vector<int>::iterator it
可用* it来访问vector里的元素
2)v[i]等价于*(v.begin() + i)
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;
set 和 multiset
1.说明:set为集合,是一个内部自动有序且不含重复元素的容器。multiset内部自动有序可以允许元素重复。
2.头文件: #include <set>
定义:set <data_type> set_name
如:set <int> s;//默认由小到大排序
数组定义:set<typename> Arrayname[arraysize]
如:set<int> a[100]
如果想按照自己的方式排序,可以重载小于号。
关于运算符重载https://blog.csdn.net/weixin_34023863/article/details/85886339?utm_source=app&app_version=4.5.3
struct new_type
{
int x, y;
bool operator < (const new_type &a)const
{
if(x != a.x) return x < a.x;
return y < a.y;
}
}set <new_type> s;
3.操作:
s.insert(elem) -- 安插一个elem副本,返回新元素位置。
s.erase(elem) -- 移除与elem元素相等的所有元素,返回被移除 的元素个数。
s.erase(pos) -- 移除迭代器pos所指位置上的元素,无返回值。
s.find(value)--返回set中对应值为value的迭代器
s.clear() -- 移除全部元素,将整个容器清空。
s.size() -- 返回容器大小。
s.empty() -- 返回容器是否为空。
s.count(elem) -- 返回元素值为elem的元素的个数。
s.lower_bound(elem) -- 返回元素值>= elem的第一个元素位置。
s.upper_bound(elem) -- 返回元素值 > elem的第一个元素的位置。
以上位置均为一个迭代器。
s.begin() -- 返回一个双向迭代器,指向第一个元素。
s.end() -- 返回一个双向迭代器,指向最后一个元素的下一 个位置
4.实例用法
#include<iostream>
#include<set>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
set<string>sl;
set<string>::iterator iterl;//迭代器
sl.insert("abc");
sl.insert("abc");
sl.insert("abc");
sl.insert("bca");
sl.insert("aa");
cout<<"ITERATE:"<<endl;
for(iterl=sl.begin(); iterl!=sl.end(); iterl++)
cout << (*iterl) <<endl;
cout<<"FIND:"<<endl;
iterl=sl.find("abc");//查找
if(iterl!=sl.end())
{
cout<<*iterl<<endl;
}
else
{
cout<<"NOT FOUND"<<endl;//查找到第一个无效位
}
return 0;
}
ITERATE:
aa
abc
bca
FIND:
abc
5.注意:
- set只能通过迭代器(iterator)访问
- 除vector和string外STL不支持*(it+i)的访问方式,只能枚举。
set元素自动递增。
6.set常见用法
最主要的作用是自动去重并按升序排序,因此碰到需要去重但是却不方便直接开数组的情况,可以尝试用set解决
map和multimap
1.说明:map是映射,可以将基本类型映射到任何基本类型,如:字典,字符串->页码类似于映射。所有元素都会根据元素的键值从小到大自动排序,map的所有元素都是pair,pair的第一个元素被视为键值,第二个元素为实值。map不允许两个元素有相同的键值,但multimap可以。
2.头文件:#include <map>
定义:map <data_type1, data_type2> map_name
如:map <string, int> m//默认按string由小到大排序
3.操作:
m.size() 返回容器大小
m.empty() 返回容器是否为空
m.count(key) 返回键值等于key的元素的个数
m.lower_bound(key) 返回键值等于key的元素的第一个可安插 的位置
m.upper_bound(key) 返回键值等于key的元素的最后一个可安插的位置
m.begin() 返回一个双向迭代器,指向第一个元素。
m.end() 返回一个双向迭代器,指向最后一个元素的下一个位置。
m.clear() 讲整个容器清空。
m.erase(elem) 移除键值为elem的所有元素返回个数,对于map来说非0即1。
m.erase(pos) 移除迭代器pos所指位置上的元素。
m.insert(elem) 插入一个元素elem
a)运用value_type插入
map<string, float> m;
m.insert(map<string, float>:: value_type ("Robin", 22.3));
b) 运用pair<>
m.insert(pair<string, float>("Robin", 22.3));
c) 运用make_pair()
m.insert(make_pair("Robin", 22.3));
直接元素存取:
m[key] = value;
查找的时候如果没有键值为key的元素,则安插一个键值为key的新元素,实值为默认(一般0)。
4.map元素的访问
1)下标访问,类似数组
2)迭代器访问map<typename1,typename2>::iterator it;
用it->first访问键,用it->second访问值
5.map用途
- 建立字符(或字符串)与整数之间映射的题目,使用map可以减少代码量。
- 判断大整数或者其他类型数据是否存在的题目,可以把map当bool数组用。
- 字符串和字符串的映射也有可能会遇到。
去重函数(unique)
去除容器或者数组中相邻元素的重复出现的元素
- 去除并非真正意义的erase,而是将重复的元素放到容器的末尾,返回值是去重之后的尾地址。
- unique针对的是相邻元素,需要先进行排序,sort().
iterator unique(iterator begin,iterator);//对区间[it_1,it_2)内进行去重
iterator unique(iterator begin,iterator end,bool MyFunc);//最后一个参数是元素是否相等的判定函数。返回值是指向最后一个元素的下一个元素的迭代器
生成排列
头文件: #include <algorithm>
bool next_permutation(begin, end);
改变区间内元素的顺序,产生下一个排列。
bool prev_permutation(begin, end);
产生前一个排列。
end为最后一个元素的下一个位置。
upper_bound 和 lower_bound
upper_bound(begin, end, value);
返回>value的元素的第一个位置。
lower_bound(begin, end, value);
返回>=value的元素的第一个位置。
另外
学习宏定义
#define pow2(a) ((a)*(a))
#define dist2(x, y) (pow2(x) + pow2(y))
#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair
心得体会:
本周学习了STL的一些简单用法,结合假期里自学的一点相关知识,对STL有了更多了解,在目前阶段的学习中,STL是一种比较简便的工具可以帮助我们快速解决一些问题,之前在做一些问题的时候用普通的方式解决问题又复杂又难构思,不如借助STL工具更加方便快捷,比如用两个对应数组解决不如用map方便,其他一些题就不列举了。STL里的容器的使用方式有一定的相似之处,可以对比着去记忆,目前我用STL工具还不够熟练,还需要在做题中反复尝试使用。