STL容器特征总结
竞赛重点:底层、内存、增删查复杂度、迭代器、优缺点、适用场景
序列式容器(元素按存放顺序排列,可存重复)
关联容器(红黑树,自动有序,<algorithm>的sort不需要再排)
无序关联容器(哈希表,C++11)
容器适配器(包装别的容器,没有迭代器!不能begin() end()遍历)
1.string字符串
-
底层:连续char数组,和vector几乎一样
-
支持
[]随机访问,+拼接 -
迭代器:随机访问迭代器
#include
// 数字转字符串
string s1 = to_string(123);
string s2 = to_string(3.14);// 字符串转数字
int num = stoi("123");
double dou = stod("3.14");
long long ll = stoll("123456");/string 头尾/
str.front(); //第一个元素
str.back(); //最后一个元素/string 分割/
str.substr(2, 5); //返回从索引2开始的五个元素组成的字符串/string 插入/
str.push_back('a'); //在尾部插入一个字符
str.insert(str.begin(), 'a'); // 在开头前插入 'a'/string 容量/
str.size()
str.length()/string 遍历/
for(int i = 0; i < str.size(); i ++ ) //索引遍历
for(string::iterator iter = str.begin(); iter != str.end(); iter ++ ) //迭代器遍历
for(auto &x : str) //迭代器另一种便捷方法/string 排序/
sort(str.begin(), str.end());/sting 查找/
int pos = s.find("world"); // 正向查找
s.find(str,index); //返回从index开始str第一次出现的位置, 找不到就返回
用find查找重复或不重复的连续目标字符串
string target="2020";
string s;
cin>>s;
int ans=0;
size_t pos=s.find(target);
while(pos!=string::npos)
{
ans++;
pos=s.find(target,pos+1/n);
}
cout<<ans<<endl;/string 删除/
str.pop_back(); //删除最后一个元素
s.erase(unique(s.begin(), s.end()), s.end()); //删除排序后的重复字符
str.erase(str.begin()); //删除迭代器指向元素
str.erase(str.begin()+1, str.end()-2); //删除指定区间的元素
str.erase(1, 6); //删除从索引(1)开始的n(6)个字符/string 替换/
str.replace(str.begin(), str.begin() + 5, "boy"); //替换迭代器指定的区间
str.replace(6, 5, "girl"); //替换索引指定的区间,从下标6开始的五个元素/string 判空/
str.empty() //返回布尔值/string 清空/
str.clear();/string 迭代器/
string::iterator iter //一个string的迭代器
str.begin() //指向str第一个元素位置的迭代器
str.end() //指向str最后一个元素后一个位置的迭代器/string 比较/
str1 < str2 //字典序比较,<、<=、==、>、>=都可以用
str1.compare(str2) //相等为0,str1>str2为1,反之-1/string 拼接/
str1.append(str2); //str1str2
str1 = str1 + str2; //str1str2/string 生成/
string str("123"); //"123"
string str(3,'1'); //"111"
string str = "123"; //"123"
2. vector<T> 动态数组
-
底层:连续内存数组
-
访问:支持下标
[]随机访问, ( O ( 1 ) ) (O(1)) (O(1)) -
尾部push_back/pop_back: ( O ( 1 ) ) (O(1)) (O(1))
-
中间/头部插入删除: ( O ( n ) ) (O(n)) (O(n)),需要搬移元素
-
迭代器:随机访问迭代器 ,支持
it+5、it-2、< > -
会扩容,扩容会拷贝数据,迭代器会失效
-
✅适合:大量随机访问,尾部增删;不适合频繁中间插入删除
#include
/vector 头尾/
vct.front(); //第一个元素
vct.back(); //最后一个元素/vector 遍历/
for(int i = 0; i < vct.size(); i ++ ) //索引遍历
for(vector::iterator iter = vct.begin(); iter != vct.end(); iter ++ ) //迭代器遍历
for(auto &x : vct) //迭代器另一种便捷方法/vector 排序/
sort(vct.begin(), vct.end());/vector 插入/
vct.push_back(2); //在尾部插入一个2
vct.insert(vct.begin(), 2); //在指定位置前面插入一个元素/vector 删除/
vct.pop_back();
vct.erase(vct.begin());
vct.erase(vct.begin()+1, vct.end()-2);
v.erase(unique(v.begin( ),v. end( )), v.end( )); //对vector进行排重v.erase(remove(v.begin( ), v.end( ), value), v.end( )); //删除vector中值为value的元素
/vector 迭代器/
vector::iterator iter //一个vector的迭代器
vct.begin() //指向vct第一个元素位置的迭代器
vct.end() //指向vct最后一个元素后一个位置的迭代器/vector 容量/
vct.size()/vector 判空/
vct.empty() //返回布尔值/vector 清空/
vct.clear();
vector二维
vector<vector<int>> v;//空二维 vector(先定义再赋值)
vector<vector<int>> v(3);// 3行,每行都是空vector
vector<vector<int>> v(3, vector<int>(4, 10));// 3行4列,所有元素 = 10
vector<vector<int>> v(3, vector<int>(4, 10));// 3行4列,所有元素 = 10
int n = 3, m = 4;
vector<vector<int>> v(n, vector<int>(m, 0));//统一初始化 N 行 M 列
//遍历方式
for(int i=0; i<v.size(); i++){
for(int j=0; j<v[i].size(); j++){
cout << v[i][j] << " ";
}
cout << endl;
}
3. deque<T> 双端队列
-
底层:分段数组,不整体连续
-
访问:支持下标随机访问 ( O ( 1 ) ) (O(1)) (O(1))
-
头部、尾部插入删除都很快 (O(1))
-
中间插入删除 ( O ( n ) ) (O(n)) (O(n))
-
迭代器:随机访问迭代器
-
✅适合:两头频繁增删,比如滑动窗口单调队列
#include
/deque 生成/
dequedq; /deque 头尾/
dq.front();
dq.back();/deque 迭代器/
dq.begin()
dq.end()/deque 插入/
dq.push_front(2); //头插入
dq.push_back(2); //尾插入/deque 删除/
dq.pop_front(); //头删除
dq.pop_back(); //尾删除/deque 容量/
dq.size();/deque 判空/
dq.empty()/deque 清空/
dq.clear();
4. set<T>
-
底层:红黑树
-
元素自动升序、去重,不能存重复值
-
查找、插入、删除: O ( log n ) O(\log n) O(logn)
-
迭代器:双向迭代器,只可
++ --,不能it+k -
❗迭代器指向的值不能修改(
*it=5编译报错) -
.find(x)找不到返回.end()#include
/set 生成/
setst; // 整数集合
setst2; // 字符集合
setst3; // 字符串集合
setst4; // 浮点数集合 /set 迭代器/
set::iterator iter
st.begin()
st.end()/set 某元素个数/
st.count(2); //判断存在/set 插入/
st.insert(2); //插入一个元素/set 容量/
st.size()/set 删除/
st.erase(st.begin()); //删除迭代器指向元素
st.erase(2); //删除所有为2的元素/set 查找/
st.find(2) //从前往后找,若找到,返回指向该处的迭代器;反之,返回迭代器st.end()
st.lower_bound(x) //二分查找大于等于x的元素中最小的一个,并返回指向该元素的迭代器。
st.upper_bound(x) //二分查找大于x的元素中最小的一个,并返回指向该元素的迭代器。/set 判空/
st.empty() //返回布尔值/set 清空/
st.clear();
5. map<K,V>
-
底层:红黑树,存
pair<K,V> -
key自动排序,key不允许重复
-
查找插入删除
-
迭代器:双向迭代器
-
✅可以修改
it->second;不能修改key(it->first只读)#include
/map 生成/
map<key_type, value_type> name;
map<int, int> mp;/map 迭代器/
map<int, int>::iterator iter
mp.begin()
mp.end()#include
/map 生成/
map<key_type, value_type> name;
map<int, int> mp;/遍历/
for (auto p : mp)
{
// p.first 是 key
// p.second 是 value
cout << p.first << " " << p.second << endl;
}/map 插入/
mp[2] = 5; //直接添加
mp.insert(pair<int, int>(2, 5)); //insert一个pair/删除/
mp.erase(iter); //删除迭代器所指的键值对/map 容量/
mp.size()/map 查找/
mp.find(2) //从前往后找,若找到,返回指向该处的迭代器;反之,返回迭代器mp.end()/map 某元素个数/
mp.count(2); //返回key为2的个数(map中只可能是0或者1)/map 判空/
mp.empty() //返回布尔值/map 清空/
mp.clear();
unordered_map<K,V>
无序,无迭代器
7. queue<T> 队列(默认底层deque)
-
先进先出 FIFO
-
push() pop() front() back() -
❌没有迭代器
#include
/queue 生成/
queueq; /queue 头尾/
q.front();
q.back();/queue 插入/
q.push(2); //在队尾插入一个元素/queue 删除/
q.pop(); //在队首删除一个元素/queue 容量/
q.size();/queue 判空/
q.empty()
8. priority_queue<T>优先队列(堆,默认大根堆,底层vector)
-
堆,每次取最大元素
-
top()取堆顶;pop()弹出堆顶 -
❌没有迭代器,不能遍历全部元素
#include
/priority_queue 生成/
priority_queueq; //大根堆
priority_queue<int, vector, greater > q; //小根堆 /priority_queue 插入/
q.push(2); //把一个元素插入堆/priority_queue 删除/
q.pop(); //删除堆顶的元素/priority_queue 堆顶/
q.top(); //返回堆顶元素/priority_queue 容量/
q.size();/priority_queue 判空/
q.empty()
9. stack<T> 栈(默认底层deque)
-
后进先出 LIFO
-
接口:
push() pop() top() empty() size() -
❌没有迭代器,不能遍历
#include <stack>
/*stack 生成*/
stack<int> sk;
/*stack 插入*/
sk.push(2); //把一个元素放入栈
/*stack 删除*/
sk.pop(); //删除栈顶的元素
/*stack 栈顶*/
sk.top(); //返回栈顶元素
/*stack 容量*/
sk.size();
/*stack 判空*/
sk.empty()
算法简介
今天介绍的成员函数,有assign,insert,count,erase,lower_bound,upper_bound
1.assign
用法1:assign(个数,值),表示生成n个相同的元素,覆盖原有的内容。
vector<int> v;
v.assign(5, 8);
// 结果:5个8 → [8,8,8,8,8]
//同样的他能用于其他类型的,比如string类型的话可以是s.assign(4,'x') 表示对s清空并且开一个4个单位的x,结果是"xxxx"
用法2:assign(起始迭代器,结束迭代器) 把另一个容器的区间内容复制过来,覆盖自己
vector<int> a = {1,2,3,4};
vector<int> b;
b.assign(a.begin(), a.end());// 把 a 全部复制给 b
b.assign(a.begin(), a.begin()+3);// 只复制前3个
string s1 = "hello";
string s2;
s2.assign(s1.begin(), s1.end());
2:insert
能用容器:vector,string,deque,set,map,(stack,queue不能用)
vector<int> v = {1,2,3};
v.insert(v.begin() + 1, 99);// 变成:1,99,2,3
string s = "abc";
s.insert(s.begin()+1, 'x');// 变成 a x b c
set<int> st;
st.insert(5);
st.insert(2);
st.insert(5); // 重复,自动丢掉
map<int, string> mp;
mp.insert({1, "小明"});
mp.insert({2, "小红"});
3.count
**作用:**统计某个值在容器里出现的个数
对集合/映射来说,只能来判断有没有这个元素
哪些容器能用:set,map
vector,deque,string无自带count但是可以用算法
stack,queue完全没有count
在set用法
set<int> st;
st.insert(5);
cout << st.count(5); // 1
cout << st.count(9); // 0
在map用法
map<string,int> mp;
mp["张三"] = 18;
cout << mp.count("张三"); // 1
cout << mp.count("李四"); // 0
在vector/deque/string用法
#include <algorithm>
vector<int> v = {1,2,2,3,2};
// 统计2出现几次
int cnt = count(v.begin(), v.end(), 2);
cout << cnt; // 3
string s = "aabcc";
int cnt = count(s.begin(), s.end(), 'c');
4:erase
哪些容器能用:vector,string,deque,set,map(stack,queue不能用)
1:vector/string/deque用法
vector<int> v = {10,20,30,40};
v.erase(v.begin() + 1); // 删除第 1 个位置 → 删掉 20
2:set
set<int> st;
st.insert(5);
st.erase(5); // 直接删掉 5
3:map
map<int, string> mp;
mp[1] = "小明";
mp.erase(1); // 删掉 key=1
5:lower_bound和upper_bound
其前提是只能用在有序的东西上
适用于:vector(有序),set(本身有序),map(本身有序)
假如你找的数是x
lower_bound(起点,终点,x)//找到第一个""大于等于x"的位置
upper_bound(起点,终点,x)//找到第一个"大于x"的位置
举个例子:1,3,5,5,5,7,9找x=5;
lower_bound->指向第一个5
upper_bound->指向7
vector<int> v = {1,3,5,5,5,7,9};
auto it1 = lower_bound(v.begin(), v.end(), 5); 找>=5 的第一个位置
auto it2 = upper_bound(v.begin(), v.end(), 5);找 >5 的第一个位置
在set/map里怎么用呢?
由于他们自带成员函数
auto it = st.lower_bound(x);
auto it = st.upper_bound(x);