map
- 定义
map<char, int> mp
- 用法:
映射,mp[key]==value(key -> value)
【key,value也可以是STL容器】 - 特性
map内部用红黑树实现(同set),map会以“key”从小到大的顺序自动排序(字母序)
①访问
map<char,int> mp;
mp['a']=100;
// 一、通过下标访问
cout<<mp['a']; //100
// 二、通过迭代器访问
for(map<char,int>::iterator it=mp.begin(); it!=mp.end(); it++)
printf("%c %d\n", it->first, it->second); //a 100
// map使用 it->first访问key it->second访问值
②find()
map<char,int>::iterator it=mp.find('b');
printf("%c %d", it->first, it->second);
③erase()
// 一、删除单个元素
// 法一:mp.erase(it),时间复杂度:O(1)
map<char, int>::iterator it=mp.find('b');
mp.erase(it);
// 法二:mp.erase(key),时间复杂度:O(logN)
mp.erase('b');
// 二、删除一个区间内所有元素
// mp.erase(first,last),时间复杂度:O(last-first)
map<char,int>::iterator it=mp.find('b');
mp.erase(it,mp.end());
④size() clear()
// 获得“映射的‘对’数” 时间复杂度:O(1)
cout<<mp.size() //若3对,即为3
// 清空,时间复杂度:O(1)
mp.clear();
map常见用途
- 建立字符(串)与证书之间的映射
- 判断大整数或其他类型数据是否存在
- 字符串->字符串的映射
- 备注:
map键值唯一,multimap单键对多值
c++11增加unordered_map,以散列代替红黑树,不用排序
queue
- 定义
queue<typename> q;
- 用法/特性
先进先出
①访问:front() back()
//时间复杂度:O(1)
q.front() //队头
q.back() //队尾
②push() pop()
//时间复杂度:O(1)
q.push(x); //x入队,队尾
q.pop(); //队头出队
③empty() size()
//检测队是否为空,时间复杂度:O(1)
if(q.empty())
//返回queue内元素个数,时间复杂度:O(1)
q.size();
queue常见用途
- 广度优先搜索,直接调用
- attention:访问前,先empty()判断是否队空!
- 同类容器
- 双端队列(deque)
首尾皆可插入和删除的队列 - 优先队列(priority_queue)
用堆实现的默认将当前队列最大元素置于队首的容器
- 双端队列(deque)
stack
- 定义
stack<typename> st;
- 用法 / 特性
栈:后进先出
①访问:top() / 出入栈:push(),pop()
//时间复杂度:O(1)
st.push(x); //入栈
x=st.top(); //访问
st.pop(); //出栈
②empty(), size()
//时间复杂度O(1)
if(st.empty()) //判空
st.size() //返回stack内元素个数
stack常见用途
- 模拟递归,防止“程序对栈内存的限制”而导致出错
若递归层过深,或导致溢出;用st模拟以避免(较少见)
pair
- 定义
两个元素捆绑为“一个合成元素”
#include<utility>
#include<map> //<map>也含pair,可二选一
struct pair{
typeName1 first;
typeName2 second;
};
pair<type1,type2> p;
①构建
pair<string,int> p;
pair<string,int> p("abc",5);
//构建临时pair
pair<string,int>("abc",5); //法一
make_pair("abc",5); //法二
②访问
printf("%s",p.first);
printf("%d",p.second);
③比较大小
先比较first,若相等则再比较second
if(p1<p2)
pair常见用途
- 替代二元结构体,节约时间
- 作为map的键值来进行插入
map<string,int> mp;
mp.insert(make_pair("aaa",5));
mp.insert(pair<string,int>("bbb",10));
for(map<string,int>::iterator it=mp.begin(); it!=mp.end(); it++)
printf("%s %d",it.first,it.second); //it->first, it->second
algorithm
max(), min(), abs(), fabs(), swap()
int x; float xx;
abs(x); //abs()用于“整型”
fabs(xx); //fabs()用于“浮点型”
reverse(a, a+△)
范围 [ it , it + △ )
int a[6]={1,2,3,4,5};
reverse(a,a+3); //3即△,表翻转自‘&a’起的△个元素
// 现在a为{3,2,1,4,5};
next_permutation(a, a+△)
给出一个序列在“全排列”中的“下一个序列”
int a[10]={1,2,3};
do{
printf("%d%d%d",a[0],a[1],a[2]);
}while(next_permutation(a,a+3));
//结果:123 132 213 231 312 321
```-
--
## fill(a, a+△, x)
把数组或容器中的某一段区间赋为某个相同的值
和memset不同,此处“赋值”可为数组类型对应范围中的任意值
```cpp
int a[5]={1,2,3,4,5};
fill(a,a+3,100);
//a为{100,100,100,4,5}
sort()
- 排序
不推荐用qsort(设计较多指针,用起来较繁琐) - 采用排序方法类似于“快速排序”?时间复杂度:O(n*log2(n))
规避了经典快速排序中可能的实际复杂度退化到O(n^2)的情况
sort(a, a+△)
默认从小到大排序
char为“字典序”(ASCII)【注意 A < B < a < b】
sort(a, a+△, cmp)
bool cmp(int a, int b) {
return a > b;
}
int main() {
int a[4] = { 2,3,1,4 };
sort(a, a + 4); // 1 2 3 4
sort(a, a + 4, cmp);// 4 3 2 1
return 0;
}
若带结构体
struct node {
int x, y;
};
struct node {
int x, y;
};
bool cmp(node a, node b) {
if (a.x != b.x)
return a.x > b.x;
return a.y > b.y;
}
按字符串长度从小到大排序
bool cmp(string str1, string str2){
return str1.length() < str2.length();
}
- 注意:STL中只有“vector, string, deque”可使用sort
因为像set, map元素本身有序(红黑树),不需sort排序
lower_bound() & upper_bound()
-
lower_bound(first, last, val)
寻找范围内第一个值大于等于val的元素的位置【>=】
如果是数组,返回该位置 指针
如果是容器,返回该位置 迭代器 -
upper_bound(first, last, val)
寻找范围内第一个值大于val的元素的位置【>】 -
注意:如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!
int a[10] = { 1,2,2,3,3,3 };
int* lowerPos1 = lower_bound(a, a + 6, 0);
int* lowerPos2 = lower_bound(a, a + 6, 2);
int* upperPos1 = upper_bound(a, a + 6, 2);
int* upperPos2 = upper_bound(a, a + 6, 3);
printf("%d,%d,%d,%d",
lowerPos1 - a, lowerPos2 - a, upperPos1 - a, upperPos2 - a);
输出结果:0,1,3,6
- 如只想获取欲查元素下标,也可直接返回地址差值
cout << upper_bound(a, a + 6, 2) - a;
vector
- 定义:
向量(变长数组)
vector<typename> vi;
vector<node> vi;
vector<vector<int>> vi; //二维vector数组
vector<int> vi[100];
- 访问
①下标访问
②迭代器访问
vector<typename_>::iterator it;
迭代器(iterator)可以理解为一种类似指针的东西,此it是一个vector<typename_>::iterator型的变量
注意是地址
⓪begin(), end()
vector.begin() :取vector的首元素地址
vector.end() :取尾元素地址的下一个地址
vi[i]
*(vi.begin()+i)
//二式等价
vector<int> vi;
for(vector<int>::iterator it=vi.begin(); it!=vi.end(); it++)
printf("%d ", *it);
①push_back(), pop_back()
- push:在vector尾添加,时间复杂度:O(1)
- pop:删除vector尾元素,时间复杂度:O(1)
②size(), clear()
- size():
获取vector元素个数,时间复杂度:O(1) - clear():清空vector所有元素,时间复杂度:O(N)
N为vector中元素的个数
③insert(it, x)
向任意迭代器it(address) 处插入一个元素,时间复杂度:O(N)
//vi={1,2,3}
vi.insert(vi.begin()+2,-1); //将-1插入vi[2]的位置
//vi={1,2,-1,3}
④erase()
- erase(it)
删除迭代器为it 处的元素
//vi={1,2,3,4}
vi.erase(vi.begin()+2)
//vi={1,2,4}
- erase(first, last)
删除 [ first, last ) 内的所有元素
//vi={1,2,3,4}
vi.erase(vi.begin(),vi.begin()+2)
//vi={4}
效果上,vi.clear() 与 vi.erase(vi.begin(), bi.end()) 同理
vector常见用途
- 动态储存数据,动态输入输出
- 用邻接表存储图
set
- 定义:集合,是一个内部自动有序且不含重复元素的容器
【自动去重&升序排序】
用迭代器it,通过【it】来访问set里的元素
由于除开vector和string之外的STL容器都不支持(it+i)的访问方式,所以只能枚举
for(set<int>::iterator it=st.begin();it!=st.end();it++)
printf("%d", *it);
①insert(x)
将x插入set容器中,并自动递增排序和去重,时间复杂度:O(logN)
②find(val)
返回set中对应值为val的迭代器,时间复杂度:O(logN)
set<int>::iterator it=st.find(2);
③erase()
- 删除单个元素
- 删迭代器对应元素
st.erase(it),时间复杂度O(1) - 删值对应元素
st.erase(value),时间复杂度O(logN)
- 删迭代器对应元素
//利用find()函数找到100,然后用erase删除它
st.erase(st.find(100));
//找value
st.erase(100);
- 删区间
st.erase(first, last)
删除 [ first, last )
④size(), clear()
set常见用途
- 需要去重但是不方便直接开数组的情况
- set 元素唯一
multiset 不唯一
c++11增加unordered_set,以散列代替set内红黑树实现,只去重但不排序,速度比set快得多
string
- 定义
string str;
string str="abc123";
- 访问
//直接访问
cin >> string;
cout << string;
cout << string[i];
printf("%s", str.c_str()); //将string型str使用c_str()变为字符数组
//迭代器访问
for (string::iterator it = str.begin(); it != str.end(); it++)
printf("%c", *it);
string也支持对迭代器加减数字,如str.begin()+2
①加, cmp
str3 = str1 + str2;
str1 += str2;
if(str1 < str2)
if(str1 != str2)
if( str4 >= str2)
length() / size()
时间复杂度O(1),基本相同
②insert()
时间复杂度O(N)
- insert(pos, string)
在pos号位置插入字符串string - insert(it, it2, it3)
it为原字符串的欲插入位置,it2和it3为待插字符串的首尾迭代器,用来表示串[it2, it3)将被插在it的位置
s1="abcxyz", s2="123";
s1.insert(3,s2); //法一
s1.insert(s1.begin()+3, s2.begin(), s2.end()); //法二
③erase()
- 删单个 erase(it)
- 但区间
- erase(first, last)
- erase(pos, len)
pos为需要开始删除的起始位置,len为删除的字符个数
s = "abc123456"
s.erase(3,3);
//s="abc456"
clear()
substr(pos, len)
返回从pos开始、长度为len的子串,时间复杂度O(len)
s = "Hello World!";
cout << s.substr(0,5); // Hello
cout << s.substr(6,6); // World!
string::npos()
常熟,本身值为-1,但因是unsigned_int类型,可认为是unsinged_int类型最大值
作为find函数失配时的返回值
等于 -1 或者 4294967295
find()
- s1.find(s2)
当s2是s1子串时,返回其在s1汇总第一次出现的位置
若不是,返回string::npos - s1.find(s2, pos)
从s1的pos号位开始匹配s2
其余同上
时间复杂度:O(nm), n,m分别为s1,s2的长度
s1="abc123123"; s2="123";
cout<<s1.find(s2); // 3
cout<<s1.find(s2,4); // 6
replace()
- s1.replace(pos, len, s2)
把s1从pos号位开始、长度为len的子串替换为s2 - s1.replace(it1, it2, it3)
把s1的迭代器 [it1, it2) 范围的自传替换为s2
时间复杂度:O(s1.length())
s="abc123"; s2="xyz";
//法一
cout << s.replace(0, 3, s2);
//法二
cout << s.replace(s.begin(), s.begin()+3, s2);
结果:s="xyz123"
参考资料:《算法笔记》