目录
所在位置
入门篇:
STL
STL(Standard Template Library)是C++的标准模板库,很多竞赛常用的数据结构、算法在STL中都有,熟练掌握能极大简化编程。
一、STL容器
STL的容器分为两类
①顺序式/序列容器(底层主要采用向量和链表)
常见的有:vector、list、stack、queue、deque、priority_queue等
vector与list优缺点正好相反
②关联式/关联容器(底层主要采用平衡二叉搜索树结构)
常见的有:set、map、multiset、multimap等
简要特性
- stack
①先进后出
②离自己最近的符合某条件的->单调栈 - queue
先进先出 - list
通用操作
//迭代器
x.begin();//返回容器首个元素的迭代器
x.end();//*返回容器尾元素的后一个位置的迭代器
//反向迭代器
x.rbegin();//返回容器尾元素的迭代器
x.rend();//返回容器首元素的前一位置的迭代器
x.size();//返回容器元素数量
x.empty;//判断容器是否为空
//非通用
x.clear();//删除所有元素,仅vector、map、set...
d[];//像数组一样,支持随机访问,仅vector、map...
接下来先具体介绍几种常见的容器。
1.1 vector——向量
STL中的vector向量是一种动态数组(可变长数组),在运行时能根据需要自动改变数组大小。
特点:可随机访问,但插入删除较慢
需要掌握
-
定义vector
v #include <bits/stdc++.h>//加入相关头文件:万能头,包含<vector> vector <int> v;
-
插入 push_back();
v.push_back(i);//加入至尾部 v.insert(v.begin() + i, value);//加入至v[i]
-
访问
//支持随机访问 for(int i = 0; i < v.size(); i++) cout << v[i] << " "; //迭代器访问 for(auto it = vi.begin(); it!=vi.end(); it++) cout<<*it<<' '<<endl; //查找 v.find(value);//返回其迭代器
-
删除
v.pop_back();//弹出尾部 v.erase(iterator it)//删除某个迭代器 v.erase(iterator first, iterator end);//删除区间[begin,end) v.clear();//删除所有元素
1.2 stack——栈
栈是一种先进后出的容器(可以理解为泡腾片的拿入拿出)
栈顶添加,栈顶弹出
需要掌握
-
定义stack
s #include <bits/stdc++.h>//万能头,作用等同于#include <stack> stack <int> s;
-
添加 push
s.push(key);//入栈至栈顶
-
访问 top
s.top();//只能访问栈顶
-
删除 pop
s.pop()//只能弹出栈顶
1.3 queue——队列
queue是一种先入先出的容器。
队尾添加,队首弹出
需要掌握
-
定义queue
q #include <bits/stdc++.h>//万能头,等同于#include <queue> queue <int> q;
-
添加 push
q.push(key);//入队至队尾
-
访问 front、back
q.front();//访问队首 q.back();//访问队尾
-
删除 pop
q.pop()//只能弹出队首
1.4 list——双向列表
STL的list是数据结构中的双向链表,内存空间不连续,通过指针来访问
特点:可高效率在任意地方删除与插入,但不支持随机访问(访问较慢)
需要掌握
-
定义
list<int> list1;
-
插入
list1.push_front(value);//头插 list1.push_back(value);//尾插 list1.insert(pos,num);//在pos迭代器位置插入元素num。 list1.insert(pos,n,num)//在pos迭代器位置插入n个元素num。 list1.insert(pos,beg,end)//在pos迭代器位置插入区间为[beg,end)的元素。
-
访问
list1.front();//返回第一个元素 list1.back();//返回最后一个元素 for (auto it = list1.begin(); it != list1.end(); it++)//迭代访问 cout << *it << " ";
-
删除
list1.pop_back();//尾删 list1.pop_front();//头删 list1.erase(pos);//删除pos迭代器位置的元素 list1.clear();//删除所有
2.1 set
set是一个自动实现无重且按一定规则排序的集合
需要掌握
-
定义 set
s; #include <bits/stdc++.h>//万能头,包含<queue> set <int> s;
-
插入 insert
s.insert(value);//插入元素进集合(自动去重)
-
查找 find
//查找值为value的迭代器find(value) auto it=s.find(value); //查找set中是否含有value if(s.find(value) != s.end()) //可使用upper_bound()、lower_bound()等
-
遍历输出 *it
//迭代器访问 for(auto it=s.begin();it!=s.end();it++){ cout<<*it<<endl; }
-
删除某个值 erase
//删除某值 s.erase(value); //删除某迭代器 s.erase(iterator it); //删除某迭代器区间 s.erase (iterator first, iterator end);
2.2 map
map是一个无重有序的不同类型之间映射的集合
是一组键值对的组合,按键排序,键和值可以是任意的类型。
需要掌握
-
定义 map<typename1,typename2> mp;
map<string, int> mp;
-
设置键值对
mp.insert(make_pair("haha",1));//先输入给一个pair mp("haha") = 1;//或者直接赋值
-
迭代访问输出键值
for(auto it=mp.begin();it!=mp.end();it++) cout<<it->first<<" "<<it->second<<endl;
-
查找
//查找键为key的迭代器 auto it = mp.find('a'); //可使用upper_bound()、lower_bound()等
-
删除
//删除某个迭代器 mp.erase(iterator it); //删除所有 mp.clear()
二、常用算法
1. lower_bound()、upper_bound()
lower_bound()、upper_bound()可以分别求出以数组中或容器中当前元素为下界/上界的下一个元素
但是前提是数组或容器本身已经是有序的!!【已排序的数组 或map以及set】
lower_bound(first, end, val)//找到有序容器或数组中第一个大于等于val的位置
upper_bound(first, end, val)//找到有序容器或数组中第一个小于等于val的位置
//first、end可以是容器的迭代器,或者数组的地址
2. next_permulation()
next_permulation()——生成比当前数组/字符串排列大的下一个排列
next_permulation(a,a+n);//根据数组a的排列找出下一个比它排列大的数组,并更新a
next_permulation(s.begin(),s.end());//根据字符串s的排列找出下一个比它排列大的字符串,并更新s
3.sort()
sort()——可以实现对数、字符串、二元组pair、结构体甚至STL容器的排序
默认升序排序,可自定义排序规则cmp
此处先简要介绍对基本类型以及字符串的排序
/* 整型数组的排序 */
bool cmp(int a, int b)//自定义整型的降序cmp
return a > b;
int a[N];
for(int i = 0; i < n; i++)
cin << a[i];
sort(a, a + n);//对数组a[0]-a[n-1]的元素升序排序![)
sort(a, a + n, cmp);//默认升序,我们可以写个降序的cmp
/* 字符串对字符的排序 */
string a;
//scanf("%s", &a[0]);//用scanf()输入只需要a[0]首地址
cin >> a;
sort(a.begin(), a.end());
printf("%s",a.c_str());//不能用cout输出字符串
以上都是sort(a, b)的形式,默认以升序排序
自定义排序规则,需要在使用sort时添加自定义的比较函数cmp()
/* 对整型 */
sort(a, a+n, cmp);
//默认升序
bool cmp(int a,int b)
return a<b;
//降序
bool cmp(int a,int b)
return a>b;
/* 对字符串 */
sort(a.begin(), a.end(), cmp)
//默认升序
bool cmp(char a,char b)
return a<b;
//降序
bool cmp(char a,char b)
return a>b;
4.bitset()位操作
bitset可以理解为一个存放二进制的数组,我们可以将整型、字符串存入bitset中。
//初始化与各类型的输出
bitset<5> b;//初始化5位的二进制位数组,默认均为0
cout << b << endl;;
int u1 = 1;
bitset<5> b1(u1);//将整型初始化为5位二进制,不足左边补0
cout << b1 << endl;//u1 = 1,则被初始化为00001
string s2 = "1101";
bitset<5> b2(s2);//将字符串初始化为5位二进制,不足左边补0
cout << b2 << endl;;//s2=”1101“,则被初始化为”01101“
string s3 = "110100";
bitset<5> b3(s3);//当字符串足够时,则取左边5个
cout << b3 << endl ;//s3为”1101“,则被初始化为”11010“
//bitset<5> b(s, pos, n); //取字符串的s[pos]开始,n位长度
bitset<5> b4(s3, 1, 2); //“10”—>00010
cout << b4 << endl;
cout << (b4 >> 1) << endl;//右移一位
//注意是逆序存储进下标的,下标低的表示低位
for(int i = 0; i< 5; i++)
cout<< b4[i];
cout << endl;
//其它操作
cout << endl << b.any();//b中是否存在1的二进制位?
cout << endl << b.none();//b中不存在1吗?
cout << endl << b.count();//b中1的二进制位的个数
cout << endl << b.size();//b中二进制位的个数
cout << endl << b.test(2);//测试b下标为2处是否二进制位为1
cout << endl << b4.test(1);//测试b4下标为2处是否二进制位为1
b.set(4);//下标4变为1
b.reset();//所有位归零
b.reset(3);//下标3处归零
b.flip();//b的所有二进制位逐位取反