一、容器的分类
- 序列式容器(每个元素有固定位置,取决于插入 时机和地点,和元素值无关)
vector(向量)list(列表)stack(栈)queue(队列)dequeue(双队列)
- 关联式容器(元素位置取决于特定的排序准则,和插入顺序无关)
set(集合) multiset(多重集合) map(映射) multimap(多重映射)
二、vector容器
1、简介
(1)将元素置于一个动态数组中加以管理
(2)随机存取(下标访问)
(3)尾部插入删除迅速O(1),中部和头部较费时
2、构造方法
int b[5] = {1, 2, 3, 4, 5};
//vector(begin,end)左闭右开
vector<int> v1(b + 1, b + 5);
for(int i = 0;i<4;i++){
cout<<v1[i];
}// v5元素为 2, 3, 4, 5
//vector(n,element)将n个ele拷贝给本身
// 声明一个长度为5,所有值为1的vector
vector<int> v2(5, 1);//v2为1 1 1 1 1
//拷贝构造函数,将v2的内容拷贝到v3
vector<int> v3(v2)//v6:1 1 1 1 1
3、赋值
int main() {
// 元素类型为int的vector,名称为v1
vector<int> v1;
// 声明一个长度为5的v2,
vector<int> v2(5);
// 另一种声明方式
vector<int> v3 = {4, 5, 6, 7};
vector<int> v2,v3,v4,v5;
//vector.assign(beg,end)左闭右开
int arr[]={0,1,2,3,4,5};
vector<int> v1;
v1.assign(arr,arr+6);
for(int i=0;i<v1.size();i++){
cout<<v1[i];
}//输出012345
//将v1复制到v2
v2.assign(v1.begin(),v1.end());//输出012345
//可以只复制某一区间
v3.assign(v1.begin()+2,v1.end()-1);//234
//将4个10赋值给本身
v4.assign(4,10);//10 10 10 10
//直接等于赋值
v5=v4;
}
4、vector大小
(1)vector.size()返回容器中元素的个数
(2)vector.empty()判空--返回 bool类型
(3) vector.resize()重新指定长度
vector<int> v1={1,2,3};
v1.resize(5);//12300
v1.resize(8,4);//12300444
5、vector元素的访问方式
//下标访问
vector<int> v1 = {0,1,2,3,4}
v1[1];//1
//循环遍历
for(int i = 0;i<vi.size();i++){
cout<<v1[i];
}
//迭代器
for(int x:v1){
cout<<x<<" ";
}
6、vector插入和删除push_back、pop_back、insert、erase
vector<int> v1 = {0,1,2,3,4}
//尾部的插入删除
//插入元素5
v1.push_back(5);//0 1 2 3 4 5
//删除末尾
v1.pop_back();//0 1 2 3 4
//其他位置的插入
v1.insert(v1.begin()+1,2);//注意第一个参数为指针,在下标为1的位置插入元素2
//打印:0 2 1 2 3 4
v1.insert(v1.begin()+1,2,1);//在下标为1的位置插入2个1
//打印:0 1 1 2 1 3 4
int b[]={40,50,60,70,80,90};
v1.insert(v1.begin()+1,b+1,b+5);//插入一个区间
//打印:0 50 60 70 80 1 1 2 1 3 4;
//删除
vector<int> v = {0, 1, 2, 3, 4, 5, 6};
v.erase(v.begin() + 1, v.begin() + 4); // 删除[1, 4)范围的下标,主要左闭右开即[1, 3]
for (int x : v) cout << x << ' '; // 输出为:0 4 5 6
7、交换两个vector
//交换v1和v2的内容
v1.swap(v2);
三、vector容器的iterator类型
vector<int>::iterator it;//变量名为it
vector容器的迭代器属于“随机访问迭代器”:迭代器依次可以移动多个位置
1、基本使用方法
int main(){
vector<int> v1;
int arr[] = {0,1,2,3,4};
v1.assign(arr,arr+5);
//构造一个迭代器对象
vector<int>::iterator it;
it = v1.begin();
//通过循环的方式使用迭代器遍历v1中的元素
for(it=v1.begin();it!=v1.end();it++){
cout<<*it<<" ";//*解引用
}//0 1 2 3 4 5
it=v1.begin();
it=it+2;
cout<<*it<<endl;//2
return 0;
}
四、string(最常用的容器之一)
1、基础声明
// 方式一
string s1;
// 方式二
string s2 = "123";
// 方式三,初始化为由3个c组成的字符串
string s3(3, 'c');
// 方式四 相当于方式二
string s4("123");
// 方式五,和方式四是等价的
char chr[] = "abc";
string s5(chr);
2、访问遍历方式(和vector差不多)
string s = "abc";
cout << s[2] << endl; // 输出:c
// 遍历
for (int i = 0; i < 3; ++i) cout << s[i] << ' ';
cout << endl;
// c++11方式
for (char c : s) cout << c << ' ';//注意式char
3、函数
(1)push_back和pop_back
(2)size函数,length函数(其效果和用法和size一样)resize函数
(3)clear函数
(4)empty函数
(5)begin和end函数
(6)各种比较运算符,string还多了+和+=的操作
(7)swap函数
(8)front和back函数
(9)find函数(从前往后找返回下标)refind(从后往前找)
int main(){
string s = "abcdef";
// 从下标为0开始找第一次出现的字符'e',返回下标
cout << s.find('e') << endl; // 输出为 4
// 从下标3开始找第一个字符'c',找不到返回size_t最大值
cout << s.find('c', 3) << endl;
// 但在判断是否找到可以用这种方式
//string::npos,是一个常量,其值可以理解为-1,但由于它是无符型,固真正意义表示的是无穷大
if (s.find('3', 3) == string::npos) {
cout << "not find!!!" << endl;
}
// 从下标0开始找字符串"bc"
cout << s.find("bc") << endl; // 输出为 1
// 从下标1开始找
cout << s.find("ef", 1) << endl; // 输出为 4
}
//参考https://blog.csdn.net/hao_6_6/article/details/118612536
(10)substr()用于截取string的一个子串,返回值为string
int main(){
string s = "abcdef";
//下标从2开始到末尾
cout<<s.substr(2)<<endl;//cdef
//截取下标从2开始长度为2
cout<<s.substr(2,2)<<endl;//cd
//下标从2开始长度为无穷
cout<<s.substr(2,-1)<<endl;//cdef
}
(11)replace函数:用于将字符串中的指定范围的子串来替换指定的子串,并返回替换后的结果
string s = "abcdef";
//从下标为2开始,长度为3的字串替换成ggg,注意一定要打“ggg“
cout<<s.replace(2,3,"ggg")<<endl;//abgggf
//从下标1开始长度为3的子串替换成 "123" 的下标从1开始长度为2的子串
cout<<s.replace(1,3,"123",1,2)<<endl;//a23gf
//从下标从1开始长度为3的子串替换成 5个 @,注意是单引号’@‘
cout<<s.replace(1,3,5,'@')<<endl;//a@@@@@f
(12)append()尾部添加字符串
string s = "abcdef";
// 在 s 串尾部插入 "123"
s.append("123");
cout << s << endl; // abcdef123
string x = "123456";
s = "abcdef";
// 此方法和上一种写法是等价的
s.append(x);
cout << s << endl; // abcdef123456
// 在上一种方法的基础上加个范围, 即 取 x 串下标从3开始长度为2的子串添加到 s 尾部
s = "abcdef";
s.append(x, 3, 2);
cout << s << endl; // abcdef45
(13)insert(插入任意位置)
string a = "abcdef";
string b = "123456";
// 从 a 串中下标2开始后面插入b串
a.insert(2, b);
cout << a << endl; // ab123456cdef
a = "abcdef";
// 从 a 串中下标2开始后面插入b串中下标从3开始长度为2的子串
a.insert(2, b, 3, 2);
cout << a << endl; // ab45cdef
(14)to_string函数
- 用于将整数类型转换成string类型
- 可传入的参数有int、long long、double等
(15)stoi函数:将string 转换成int类型
其类似的还有stol、stof、stod、stoll、stold、stoull等,分别对应返回值为long、double、long long、long double、unsigned long long
int a = 1;
long long b = 2;
double c = 3.1415926;
string x = to_string(a);
string y = to_string(b);
string z = to_string(c);
string s = "123";
int S = stoi(s);
(16)getline读入一行
string s;
// 值得注意的是,如果此前有换行符需要用getchar吃掉
while (getline(cin, s)) {
cout << s << endl; // 实现一行一行地读入
}
(17)stringstream流控制
int main(){
string a = "You make it !",sub;
stringstream b(a);//将流初始化
while(b>>sub){
cout<<sub<<endl;
}
return 0;
}
You
make
it
!
string str = "123 90.99";
stringstream str2;
str2<<str;//像流一样将str读入到str2
int x = 0;
double y = 0.0;
str2>>x>>y;//像流一样从str2读入到x和y
cout<<x<<" "<<y<<endl;//123 90.99
五、stack(栈)
1、出栈入栈(先进后出)
//声明
stack<int> st;
st.push(1);//从栈顶入栈1
st.push(2);//入栈2
//没有迭代器
cout<<st.top()<<endl;//返回2
st.pop();//出栈栈顶元素2
cout<<st.top();//返回1
//循环出栈
while(!st.empty()){
st.pop();
}
cout<<st.top();
2、拷贝
stack<int> s1;
s1.push(1);
s1.push(3);
s1.push(5);
//拷贝构造与赋值
stack<int> s2(s1);//将s1拷贝到s2
cout<<s2.top();//输出5
3、stack.empty()
4、stack.size()
六、queue(队列)
1、先进先出
queue<int> qu;
//队尾入队
qu.push(1);
qu.push(2);
qu.push(3);
cout<<qu.size();//3
//没有迭代器不能遍历
cout<<qu.front();//输出1
cout<<qu.back();//输出3
//队头出队
qu.pop();
cout<<qu.front();//输出2
//想要循环输出
qu.push(4);
while(!qu.empty()){
cout<<qu.front()<<" ";
qu.pop();//2 3 4
}
2、拷贝赋值
//接上一段代码的qu
queue<int>qu2(qu);
//或者
queue<int>qu3 = qu;
while(!qu2.empty()){
cout<<qu2.front()<<" ";
qu2.pop();//2 3 4
}
while(!qu3.empty()){
cout<<qu3.front()<<" ";
qu3.pop();//2 3 4
}
七、deque(双端队列 )
1、简介
- deque是双端数组而vector是单端的,两者许多操作很相似。
- deque可以随机存取元素,支持索引值直接存取【】或at()。
- deque头部尾部添加和删除元素很方便,在中部就比较费时。
2、deque.push_front()头部插入
3、deque.pop_front()头部删除
4、其他操作和vector容器的的操作差不多
八、list(列表)
1、简介
- list双向链表容器,可以高效地插入删除
- list不可随机存取元素
2、常用操作
- push_front(val):在头部插入
- pop_front():在头部删除
- push_back(val):尾部插入
- pop_back():尾部删除
- front()、back():返回头元素、尾元素的引用
list<int> lt(3,1);//长度为3,值全为1
lt.push_back(2);//尾部插入2
lt.push_front(1);
lt.pop_front();
//遍历
for(auto x:lt){
cout<<x<<" ";
}//1 1 1 2
//构造一个迭代器遍历
list<int>::iterator it;
for(it=lt.begin();it!=lt.end();it++){
cout<<*it<<" ";
}//1 1 1 2
cout<<endl;
//存取
cout<<lt.front()<<" "<<lt.back()<<endl;//1 2
- insert(iterator, val):在迭代器iterator前插入val
- insert(iterator, count, val):在迭代器iterator前插入count个val
//lt3:6 6 6
lt3.insert(lt3.begin(),8);//8 6 6 6
lt3.insert(lt3.end(),3,9);//8 6 6 6 9 9 9
list<int>::iterator it3 = lt3.begin();
for(it3=lt3.begin();it3!=lt3.end();it3++){
if(*it3 == 9)//让it3指向9的位置
break;
}
if(it3 != lt3.end()){//找到了9
lt3.insert(it3,7);//插入7
}
for(auto x:lt3){
cout<<x<<" ";//8 6 6 6 7 9 9 9
}
- begin()、end()、rebegin()、rend():返回头部和尾部下一位置的迭代器
- size():大小
- sort():升序排序
- clear():清空
- reverse():翻转链表
- merge(list2) :用第二个有序的 list 合并一个有序 list
- swap():lt1.swap(lt2)交换两个容器的内容
list<int>lt;
lt.push_front(5);
lt.push_front(9);
lt.push_front(1);
lt.push_front(3);
list<int>lt2(3,6);
//升序
lt.sort();
for(auto x:lt){
cout<<x<<" ";
}//1 3 5 9
//翻转reverse
lt.reverse();
for(auto x:lt){
cout<<x<<" ";
}//9 5 3 1
cout<<endl;
//交换
lt.swap(lt2);
for(auto x:lt){
cout<<x<<" ";//6 6 6
}
cout<<endl;
//赋值
list<int> lt3;
lt3.assign(5,8);//8 8 8 8 8
lt3=lt;//将lt的值赋给lt3 6 6 6
-
splice(list.iterator, list2, list2.iterator_start, list2.iterator_end):在本list的 iterator后插入list2的从 iterator_start 到 iterator_end, 后面两个可填可以不填,当填了iterator_start,可不填最后一个,时间复杂度O(1)
-
erase(iterator):删除iterator,返回删除前的下一个的迭代器
erase(iterator_start, iterator_end):删除[iterator_start, iterator_end)范围内的元素,返回删除前的iterator_end
九、set(集合)和multiset
1、简介
- set中所包含的元素是唯一的(即使你重复插入了),集合中的元素按一定的顺序排列,元素插入过程是按照排序规则插入。
- set采用红黑树(平衡二叉树),插入时候自动排序(logn),插入删除快于vector
- set不可以直接存取元素
- mutiset和set的区别:set支持唯一键值,每个元素只能出现一次;mutiset中同一个值可以出现多次。
- 不可以直接修改值,必须先删除原有数据,再插入新的元素。
2、insert()插入
//声明
set<int> s1;
//插入
s1.insert(1);
s1.insert(5);
s1.insert(3);
s1.insert(9);
s1.insert(-2);
//另一种插入
set<int> ass = {3, 4, 3, 2, 5};
ass.insert(1); // 插入一个 1 最终为1 2 3 4 5(自动排序)
//遍历
for(int x:s1){
cout<<x<<" ";
}
cout<<endl;
//迭代器遍历
//正向迭代器
set<int>::iterator it;
for(it=s1.begin();it!=s1.end();it++){
cout<<*it<<" ";//-2 1 3 5 9set默认升序
}
cout<<endl;
//反向迭代器
set<int>::reverse_iterator it2;
for(it2=s1.rbegin();it2!=s1.rend();it2++){
cout<<*it2<<" ";//9 5 3 1 -2
}
3、erase()删除
set<int> ass = {3, 4, 3, 2, 5, 1};
ass.erase(3);//1 2 4 5
ass.erase(ass.begin()); // 删除指点迭代器的元素
ass.erasse(ass.begin(), ass.begin() + 2); // 删除连个迭代器范围内的数
4、size()大小
由于set内部保证元素唯一,已有的相同元素无论插入几次都是不会改变size的
set<int> ass = {3, 4, 3, 2, 5};
//2 3 4 5
cout<<ass.size()<<endl;//4
ass.insert(4);
cout<<ass.size()<<endl;//4
5、empty()判空
set<int> ass = {3, 4, 3, 2, 5};
cout<<ass.empty();//bool类型 空返回1 非空返回0
6、count()计数
其实相当于查找某个元素是否在容器内,在则返回1,不在则返回0
set<int> ass = {3, 4, 3, 2, 5};
cout << ass.count(3) << endl; // 1
cout << ass.count(9) << endl; // 0
7、clear()清空
ass.clear();
cout<<ass.size()<<endl;//0
8、lower_bound()和upper_bound()
int main(){
set<int> ass = {1, 6, 4, 8};
//找到第一个大于等于指定元素
cout << *ass.lower_bound(3) << endl; // 4
cout << *ass.lower_bound(6) << endl; // 6
if (ass.lower_bound(9) == ass.end()) {
cout << "not found" << endl; // 被执行
}
//找到第一个大于指定元素
cout << *ass.upper_bound(3)<<endl;//4
cout << *ass.upper_bound(6)<<endl;//8
if(ass.upper_bound(8)==ass.end()){
cout<<"not fund"<<endl;//not fund
}
}
9、pair()将两个类型的数捆绑在一起
- set.equal_range(elem)返回容器中与elem相等的上下限的两个迭代器,上限是闭区间(就是lower_bound的值),下限是开区间(就是upper_bound的值)
- 函数返回两个迭代器,而这两个迭代器被封装在pair中
- pair<T1,T2>(对组),存放两个值的类型,可以不一样(比如一个int,一个char,也可以 是自定义类型)
- pair.first是pair里面的第一个值,是T1的类型
- pair.second是pair里面的第二个值,是T2的类型
10、swap()交换
//注意不同类型的set不能交换
set<char> ass1={'a','b','c','d'};
set<char> ass2={'e','f','g','h'};
ass1.swap(ass2);
set<char>::iterator it;
for(it=ass1.begin();it!=ass1.end();it++){
cout<<*it<<" ";//e f g h
}
set<char>::iterator it2;
for(it2=ass2.begin();it2!=ass2.end();it2++){
cout<<*it2<<" ";//a b c d
}
十、map(映射表)
1、insert()插入+遍历
map/multimap采用模板类实现,对象的默认构造形式
int main(){
//声明(key,value)
map<int,double> m1;
multimap<int,string> m2 = {
{1,"abc"},
{2,"def"},
{3,"ghi"},
};
//插入
m2.insert({4,"jkl"});
//m2.insert({{4,"jkl"},{5,"mn"}})多组插入
m2.insert(pair<int,string>(5,"mn"));//注意5是键,“mn”是值
m2[6]="o";
//遍历1
map<int,string>:: iterator it;
for(it=m2.begin();it!=m2.end();it++){
pair<int,string> p = *it;
int key = p.first;//first为第一个,即键
string value = p.second;//second为第二个,即值
cout<<key<<": "<<value<<endl;
}
//遍历2
for(pair<int,string> p2:m2){
cout<<p2.first<<": "<<p2.second<<endl;
}
//遍历3
for(auto p3:m2){
cout<<p3.first<<": "<<p3.second<<endl;
}
//遍历4
for(auto[a,b]:m2){
cout<<a<<": "<<b<<endl;
}
return 0;
}
2、erase()删除
传参传的是key键
m2.erase(3);
//遍历4
for(auto[a,b]:m2){
cout<<a<<": "<<b<<endl;
}
3、count()、size()、empty()、clear()lower_bound()、upper_bound()、find()使用方法和set一样。
map<int,string> m2 = {
{1,"abc"},
{2,"def"},
{3,"ghi"},
};
map<int,string>::iterator it2 = m2.find(3);
cout<<(*it2).second<<endl;//注意map内部是一个pair对组
//ghi