浅谈C++ 之STL
浅谈C++之STL
一、sort
sort使用方便,效率较高,底层实现是用快排的方式进行排序
要使用该算法,需要#include 头文件(算法头文件)
sort底层实现用的是快速排序
1. sort 用法一
对基本类型的数组从小到大排序:
sort(数组名+n1,数组名+n2);
n1和n2都是int类型的表达式,可以包含变量
如果n1=0,则 + n1可以不写
将数组中下标范围为[n1,n2)的元素从小到大排序。下标为n2的元素不在排序 区间内
程序样例:对无序数组进行递增排序
using namespace std;
int main(){int a[10]={12,23,423,2,1,53,65,10,32,45};sort(a, a+10);for(int i=0; i<10; i++){cout << a[i] << " ";}return 0;
}
结果:1 2 10 12 23 32 45 53 65 423
2. sort 用法二
对元素类型为T的基本类型数组从大到小排序:
sort(数组名+n1,数组名+n2,greater());
**greater()**是从大到小排序规则,<>中的T是数据类型,例如int,float,double等等
泛型概念:
①.泛型:就是不使用具体数据类型,而是使用一种通用类型 T 来进行程序设计;T 只是一个占位符,实际在 T 的位置真实的数据类型取决于用户的需求;占位符的替换由编译器在编译阶段完成。
②.泛型编程:为了避免因数据类型的不同,而被迫重复编写大量相同业务逻辑的代码,因此发展了泛型及泛型编程技术;泛型编程就是独立于任何特定类型的方式编写代码,常用到STL容器、迭代器、和算法都是泛型编程的例子。
程序样例:对数组进行从大到小排序
#include<bits/stdc++.h>
using namespace std;
int main(){int a[10]={12,23,423,2,1,53,65,10,32,45};sort(a, a+10,greater<int>());for(int i=0; i<10; i++){cout << a[i] << " ";}return 0;
}
结果:423 65 53 45 32 23 12 10 2 1
3. sort 用法三
用自定义的排序规则,对任何类型T的数组排序
sort(数组名+n1,数组名+n2,排序规则结构名());
排序规则结构的定义方式:
struct 结构名{bool operator()(const T & a1, const T & a2){//若a1应该在a2前面,则返回true, 否则返回false}
};
程序样例:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct Student { char name[20]; //姓名int id; //学号double gpa;//绩点
};
Student students [] = { {"Jack",112,3.4},{"Mary",102,3.8},{"Mary",117,3.9}, {"Ala",333,3.5},{"Zero",101,4.0}};
struct StudentRule1 { //按姓名从小到大排 bool operator() (const Student & s1,const Student & s2) { if( stricmp(s1.name,s2.name) < 0)return true; return false; }
};
struct StudentRule2 { //按id从小到大排 bool operator() (const Student & s1,const Student & s2) { return s1.id < s2.id; }
};
struct StudentRule3 {//按gpa从高到低排 bool operator() (const Student & s1,const Student & s2) { return s1.gpa > s2.gpa; }
};
void PrintStudents(Student s[],int size){ for(int i = 0;i < size;++i) cout << "(" << s[i].name << "," << s[i].id <<"," << s[i].gpa <<")"; cout << endl;
}
int main() { int n = sizeof(students) / sizeof(Student); sort(students,students+n,StudentRule1()); //按姓名从小到大排 PrintStudents(students,n); sort(students,students+n,StudentRule2()); //按id从小到大排 PrintStudents(students,n); sort(students,students+n,StudentRule3()); //按gpa从高到低排 PrintStudents(students,n); return 0;
结果:(Ala,333,3.5) (Jack,112,3.4) (Mary,102,3.8) (Mary,117,3.9) (Zero,101,4) (Zero,101,4) (Mary,102,3.8) (Jack,112,3.4) (Mary,117,3.9) (Ala,333,3.5) (Zero,101,4) (Mary,117,3.9) (Mary,102,3.8) (Ala,333,3.5) (Jack,112,3.4)
}
4. sort 例题:奖学金
共5行,每行是两个用空格隔开的正整数,依次表示前55名学生的学号和总分
#include<bits/stdc++.h>
using namespace std;
struct Students {int id; // 学号int c; // 语文成绩int m; // 数学成绩int e; // 英语成绩int sum;
} S[305];
struct cmp {bool operator()(const Students & s1, const Students & s2) {if(s1.sum < s2.sum) { // 总成绩高的排在前面return 0;} else if(s1.sum > s2.sum) { return 1;} else { // 总成绩相等,按语文成绩排名if(s1.c > s2.c) { // 语文成绩相等,学号小的排在前面return 1;} else if(s1.c < s2.c) {return 0;} else {if(s1.id > s2.id)return 0;elsereturn 1;}}}
};
int main() {int n;cin >> n;for(int i=1; i<=n; i++) {S[i].id = i; // 学号cin >> S[i].c >> S[i].m >> S[i].e;S[i].sum = S[i].c + S[i].m + S[i].e;}sort(S+1, S+1+n, cmp());for(int i=1; i<=5; i++) {cout << S[i].id << " " << S[i].sum << endl;}return 0;
}
二、string类(字符串)
使用string类要包含头文件 #include
string对象的初始化:
– string s1(“Hello”);
– string month = “March”; //常用方法
– string s2(8,’x’);//初始化8个x字符
可以将字符赋值给string对象
– string s;
– s = ‘n’;
程序样例:
#include<bits/stdc++.h>
using namespace std;
int main(){string s1("hello worle");cout << s1 << endl;string s2(8,'x');cout << s2 << endl;string month = "March";cout << month << endl;string s;s = 'n';cout << s << endl;return 0;
}
运行结果:
hello worle
xxxxxxxx
March
n
1. 成员函数 length 用法
- string 对象的长度用成员函数 length() 读取
#include<bits/stdc++.h>
using namespace std;
int main(){string str = "hello world";cout << str.length();return 0;
}
运行结果:11
2. string 的赋值和连接
- 单个字符复制
s2[5] = s1[3] = ‘a’;
- 逐个访问 string 对象中的字符
string s1(“hello”);
for(int i=0; i<s1.length(); i++){
cout << s1.at(i) << endl; //可以改成s1[i] 数组的方式使用
}
成员函数 at() 会做范围检查,如果超过范围,会抛出 out_of_range 异常,而下标运算符 [] 不会做范围检查。
用 + 运算符连接字符串
string s1("good "), s2(“morring!”);
s1 += s2;
cout << s1; //结果是:good morring!
用成员函数 append() 连接字符串
string s1("good "), s2(“morring!”);
s1.append(s2);
cout << s1; //结果是:good morring!
s2.append(s1, 3, s1.size()); //s1.size()和s1.length()的功能一样
cout << s2; //下标为3开始,s1.size()个字符,如果字符串没有足够字符,则复制到字符串最后一个字符
//结果是:morring!d 。
3. 比较string
用关系运算符比较 string 的大小:== , > , >= , < , <= , != 返回值是bool 类型,成立返回 true,否则返回 false
例如:
string s1(“hello”), s2(“hello”), s3(“hell”);
bool b = (s1 == s2); //结果:1
b = (s1 == s3); //结果:0
b = (s1 > s3); //结果:1
用成员函数 compare() 比较 string 的大小
string s1(“hello”), s2(“hello”), s3(“hell”);
int f1 = s1.compare(s2); //结果:0 hello == hello
int f2 = s1.compare(s3); //结果:1 hello > hell
int f3 = s3.compare(s1); //结果:-1 hell < hello
int f4 = s1.compare(1,2,s3,0,3); //结果-1 注:前面两个数字表示从下标1到下标2之间的范围 el < hell
int f5 = s1.compare(0, s1.size(), s3); // 结果:1 hello > hell
4. 子串
成员函数 substr()
string s1(“hello world”), s2;
s2 = s1.substr(4, 5); //从下标4开始5个字符
cout << s2 << endl; //结果:o wor
5. 交换 string
成员函数swap()
string s1(“hello world”), s2(“really”);
s1.swap(s2);
cout << s1 << endl; // 结果:really
cout << s2 << endl; // 结果:hello world
6. 删除 string 中的字符
成员函数erase()
string s1(“hello world”);
s1.erase(5); //删除下标及之后的字符
cout << s1 << endl; // 结果:hello
cout << s1.length() << endl; // 结果:5
cout << s1.size() << endl; //结果:5
7. 在 string 中插入字符
成员函数 insert()
string s1(“hello world”);
string s2(“show insert”);
s1.insert(5, s2); //将s2插入s1下标5的位置
cout << s1 << endl; //结果:helloshow insert world
s1.insert(2, s2, 5, 3); //将s2中下标5开始的3个字符插入s1下标2的位置
cout << s1 << endl; //结果:heinslloshow insert world
8. 转换成 C 语言式 char* 字符串
成员函数 c_str()
string s1(“hello world”);
printf("%s\n", s1.c_str()); // 结果:hello world
//s1.c_str() 返回传统的const char * 类型字符串,且该字符串以 ”\0“ 结尾
三、容器概述
可以用于存放各种类型的数据(基本类型的变量,对象等)的数据结构,都是类模板分为三种:
- 顺序容器
- vector deque list
- 关联容器
- set multiset map multimap
- 容器适配器
- stack queue priority_queue
1. 顺序容器简介
容器并非排序的,元素的插入位置同元素的值无关。有vector,deque,list 三种。
- vector 头文件 < vector >
动态数组。元素在内存连续存放,随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能(大部分情况下是常数时间)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P6c4LdyV-1623129092557)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcew0MMU0eSu9cfMaefaEz0xxUfYMY4eK7QiRYWPCFWQ.wVf2PSpJjGtJNuf*OrsMDeKGbxUqfPcZH2b3J.81n6I!/b&bo=3wKPAAAAAAABF2I!&rf=viewer_4)]
deque 头文件< deque >
双向队列,又称循环队列。元素在内存连续存放。随机存取任何元素都能在常数时间完成(但次于vector )。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0hppDtC-1623129092558)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcTETrniJEJk6qSq5aeUuVO5tSro5JxNC5rX1OyGso9YmrEosJ85R3.PfsJY*kpWS9TSxmBzPVI8PU0h2CT6HXTA!/b&bo=iQJjAQAAAAABF9k!&rf=viewer_4)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8r5yn0gB-1623129092559)(http://m.qpic.cn/psc?/V13qV41h30gptO/ruAMsa53pVQWN7FLK88i5nlcCQty89Je2.AvthoGKeDGuEp.pTWX56hbDmvgK.gDY90GX8vNsrSx6eLdmIklI2fl2hdCawiP.U3hIqyqo!/mnull&bo=agKHAQAAAAABB84!&rf=photolist&t=5)]
list 头文件< list >
双向链表,又称循环连边。元素在内存不连续存放,在任何位置增删元素都能在常数时间完成。不支持随机存取。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZhAigG3f-1623129092560)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mceM3f.ytj6DYAVwT5EzlojRHEgcCFvihB9ysQah3GE2aajsiUaJKpnWwEMMtKCjZZoFEXlsy.lCtNaaV5GfwaxU!/b&bo=1wKwAAAAAAABF1U!&rf=viewer_4)]
2. 容器适配器简介
stack 头文件< stack>
栈,是项的有限序列,并满足序列中别删除、检索和修改的项只能是最近插入序列的项(栈顶的项)。后进后出。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iY3e8muJ-1623129092561)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcSmBFaw6P8B304YTPFWWCu4Qu3jjIKz8dlYat46FDxeQFz7qVPrGraQpOzfWV.7H5qKfPCxm6wm8lvIpAqvgI!/b&bo=YgEXAQAAAAABF0U!&rf=viewer_4)]
queue 头文件< queue >
队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。先进先出。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mr7D8YT5-1623129092561)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcX.HqYrjI5VotswnVkKCON3KbAqiPYyzYXF0ZKyd3VgO9cNFtSUutqEZooahpeM4c*3k5yHUzbfcH6UZKqjHOoU!/b&bo=XQGlAQAAAAABF8g!&rf=viewer_4)]
3. 顺序容器和关联容器中都有的成员函数
- begin 返回指向容器中第一个元素的迭代器
- end 返回指向容器中最后一个元素后面的位置的迭代器
- rbegin 返回指向容器中最后一个元素的迭代器
- rend 返回指向容器中第一个元素前面的位置的迭代器
- clear 从容器中删除所有元素
- erase 从容器中删除一个或几个元素
- front 返回容器中第一个元素的引用
- back 返回容器中最后一个元素的引用
- push_back 在容器末尾添加新元素
- pop_bakc 删除容器末尾的元素
4. 迭代器
- 用于指向顺序容器和关联容器中的元素
- 迭代器用法和指针类似
- 有const 和非 const 两种
- 通过迭代器可以读取它指向的元素
- 通过非const迭代器能 修改器指向的元素
定义一个容类的迭代器的方法:
容器类型::iterator 变量名 或者 容器类名:: const_iterator 变量名
访问一个迭代器指向的元素:
*** 迭代器变量名**
迭代器上可以执行 ++ 操作,以使其指向容器中的下一个元素。如果迭代器到达了容器中的最后一个元素的后面,此时在使用它,就会出错,类似与使用 NULL 或
未初始化的指针一样。
迭代器的的方法如何使用,后面结合其他容器一起介绍
(1)双向迭代器
若 p 和 q 都是双向迭代器,则可对 p、q 可进行一下操作:
- ++p,p++ 使p指向容器中下一个元素
- –p,p-- 使p指向容器中上一个元素
- *p 取p指向的元素
- p = q 赋值
- p == q,p != q 判断是否相等、不等
(2)随机访问迭代器
若 p 和 q 都是随机访问迭代器,则可对 p、q 进行一下操作:
- p += i 将 p 向后移动 i 个元素
- p -= i 将 p 向前移动 i 个元素
- p + i 指向 p 后面的第 i 个元素的迭代器
- p - i 指向 p 前面的第 i 个元素的迭代器
- p[i] p 后面的第 i 个元素的引用
- p - q p 和 q 之间的元素的个数
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lSbEelMm-1623129092562)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcZ1.En9mR8sx6OGYc10yxu8Sy.YBATywfplDx36.sJ60OK4Ti6SFBCKCtXBWgJNcqmeUKp1N6V2nDFpyJMxBWiI!/b&bo=RQLsAQAAAAABF5o!&rf=viewer_4)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ws1UwhSR-1623129092562)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcTETrniJEJk6qSq5aeUuVO53CIt6drhkJFa*ZZFG8RBSoWjv3W9lYuIrnS.56TqImauCsPZZfMzbvVnxOry5wHg!/b&bo=NQLqAQAAAAABF.w!&rf=viewer_4)]
四、动态数组vector
1. vector数组定义
头文件:#include
定义:vector v;
2. vector 常用的成员函数有
插入元素 v.push_back(n)
检查这个容器是否为空 v.empty()
容器所容纳的元素数 v.size()
清空容器的所有元素 v.clear()
擦除当前元素 v.erase(地址)
移除末尾的元素 v.pop_back()
3.程序代码
#include<bits/stdc++.h>//万能头文件
using namespace std;
int main(){vector<int> v; //一个存放 int 元素的数组,一开始容器里为空v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); vector<int>::const_iterator it; //常量迭代器//遍历vector容器中的元素 for(it = v.begin(); it != v.end(); it++){cout << *it << " "; } cout << endl;vector<int>::iterator i;//非常量迭代器for(i = v.begin(); i != v.end(); i++){*i = 100; //赋值 } for(i = v.begin(); i != v.end(); i++){cout << *i << " ";} cout << endl;v.pop_back(); //删除容器中最后一个元素for(i = v.begin(); i != v.end(); i++){cout << *i << " ";}return 0;
} 运行结果:
1 2 3 4 5
100 100 100 100 100
100 100 100 100
4. vector 实现二维数组
#include<bits/stdc++.h>//万能头文件
using namespace std;
int main(){vector<vector<int> > v(3);// v 有3个元素,每个月元素都是vector<int>容器for(int i=0; i<v.size(); i++){for(int j=0; j<4; j++){v[i].push_back(j);}} // vector二维数组的遍历和一般的二维数组相似 for(int i=0; i<v.size(); i++){for(int j=0; j<4; j++){cout << v[i][j] << " ";}cout << endl;}return 0;
}
运行结果:
0 1 2 3
0 1 2 3
0 1 2 3
5. vector 例题:询问学号
#include<bits/stdc++.h>
using namespace std;
vector<int> v;
int main() {int n, m;cin >> n >> m;for(int i=1; i<=n; i++) {int n1;cin >> n1;v.push_back(n1);}auto it = v.begin();for(int j=0;j<m; j++) {int m1;cin >> m1;cout << *(it+m1-1) << endl;}return 0;
}
五、链表 list
1. 链表定义
listlst1; //创建空list
list<int> lst2(5); //创建含有5个元素的list
2. list 常用的成员函数
在list容器末尾插入或删除元素 l.push_back / l.pop_back()
在list容器头部插入或删除元素 l.push_front / l.pop_front()
判断list容器是否为空 l.empty()
对元素进行排序 l.sort()
返回元素的个数 l.size()
3. 程序代码
#include<bits/stdc++.h>
#include<list>
using namespace std;
int main() {list<int> l;cout << "在list容器末尾插入元素:" ;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);list<int>::iterator it;for(it = l.begin(); it != l.end(); it++) {cout << *it << " ";}cout << endl;cout << "在list容器末尾删除元素:";l.pop_back();l.pop_back();l.pop_back();for(it = l.begin(); it != l.end(); it++) {cout << *it << " ";}cout << endl;cout << "在list容器头部插入元素:";l.push_front(6);l.push_front(7);l.push_front(8);for(it = l.begin(); it != l.end(); it++) {cout << *it << " ";}cout << endl;cout << "在list容器头部删除元素:";l.pop_front();l.pop_front();for(it = l.begin(); it != l.end(); it++) {cout << *it << " ";}cout << endl;cout << "判断list容器是否为空(为空返回1,否则返回为0):";cout << l.empty() << endl; cout << "对元素进行排序:";l.sort();for(it = l.begin(); it != l.end(); it++) {cout << *it << " ";}cout << endl;cout << "返回元素的个数:";cout << l.size() << endl;return 0;
}运行结果:
在list容器末尾插入元素:1 2 3 4 5
在list容器末尾删除元素:1 2
在list容器头部插入元素:8 7 6 1 2
在list容器头部删除元素:6 1 2
判断list容器是否为空(为空返回1,否则返回为0):0
对元素进行排序:1 2 6
返回元素的个数:3
4. list 例题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vKXChWCX-1623129092563)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcVQh3VkWFHeE5WUCezq*zRJJo6hMtFJ7cSLJdgYPPcmr.OljWjn90hlwzlO36kA26Nru2WOLjSmD1MH0bbxhJrQ!/b&bo=CAKBAwAAAAABF7g!&rf=viewer_4)]
代码实现:
#include<bits/stdc++.h>
using namespace std;
list<int> s;
int main() {int M,N;cin >> M >> N;int count = 0;for(int i = 0; i < N; i++) {int m;cin >> m;auto t = s.begin();int temp = 1;while(t != s.end()) {if(*t == m)temp = 0;t++;}if(temp) {count++;if(s.size() == M) {s.pop_front();s.push_back(m);} elses.push_back(m);}}cout << count << endl;return 0;
}
六、栈 stack
1. 栈的介绍
头文件:#include
定义: stack s;
限定仅在表尾进行插入或删除操作的线性表,表尾—栈顶,表头—栈底,不含元素的空表称空栈。
特点:先进后出(FILO)或后进先出(LIFO)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhri4S9V-1623129092564)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcZTGs76.T6ZGKlGm8SChHPOiNU*jlV7hG8RmPAqxpsnB2qo3cAaXQlxWMjPXxHmj3vpEyoR2MSFWsaRp1R7x56g!/b&bo=3gIoAQAAAAABF8U!&rf=viewer_4)]
2. 图解stack
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmANO4ja-1623129092564)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcZ1Oetqsu2a4GPZ06YxLA4KHtQaeJjZ8Dztmus.dKBJtdb7It2p3FldtDpN.inLdu4Tjs*KB0cW9uow95H29M!/b&bo=gQN2AgAAAAABF8Y!&rf=viewer_4)]
3. stack常用成员函数
- 栈为空返回真 s.empty()
- 移除栈顶元素 s.pop()
- 在栈顶增加元素 s.push()
- 返回栈中元素个数 s.size()
- 返回栈顶元素 s.top()
4. 程序代码
#include<bits/stdc++.h>
#include<stack>
using namespace std;
int main(){stack<int> s;//在栈顶增加元素s.push(12);s.push(32);s.push(33);s.push(122);cout << "栈顶元素:" << s.top() << endl;//从栈顶弹出两个元素 s.pop();s.pop();cout <<"栈顶元素:" << s.top() << endl;cout << "判断stack容器是否为空(为空返回1,否则返回为0):" << s.empty() << endl;cout << "返回元素的个数:" << s.size() << endl; return 0;
}
运行代码:
栈顶元素:122
栈顶元素:32
判断stack容器是否为空(为空返回1,否则返回为0):0
返回元素的个数:2
5. stack 例题: 括号序列
#include<bits/stdc++.h>
using namespace std;
stack<int>q;//定义一个栈
string s,b;//s是输入字符串,b是配对的字符串
int main() {cin>>s;//输入int l=s.size();for (int i=0; i<s.length(); i++) {if (s[i]=='(') {q.push(i); //入栈b[i]=')';//相应的括号匹配上}if (s[i]=='[') {q.push(i); //同理b[i]=']';}if (s[i]==')' || s[i]==']') //如果是后半边括号if (q.empty() || b[q.top()]!=s[i]) { //这里一定是q.empty不要写错了if (s[i]==')')b[i]='(';elseb[i]='[';//相应的配对} elseb[q.top()]=' ',q.pop();}for (int i=0; i<l; i++) {if (b[i]=='(' or b[i]=='[')cout<<b[i];//输出配对cout<<s[i];//输出原来的字符if (b[i]==')'||b[i]==']')cout<<b[i];}cout<<endl; return 0;
}
七、队列 queue
1. 队列的介绍
头文件:#include
定义:queue q;
队列是一种特殊的线性表; 插入位置只有1个,限制在表尾进行;删除位置也只有1个,限制在表头进行。
特点:先进先出FIFO(First In First Out)
2. 图解队列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WG47Rp8K-1623129092565)(http://m.qpic.cn/psc?/V13qV41h30gptO/45NBuzDIW489QBoVep5mcVZ4hN8rtLRvYSIKvaTW.mIJTxgEJl4GfnKOiVemB6fZOWh7dPVblFLGN.CMziLMbjbym5yJaF1TXLOxWOKGA1c!/b&bo=2gPIAQAAAAABFyA!&rf=viewer_4)]
3. queue常用成员函数
back() | 返回最后一个元素 |
---|---|
empty | 如果队列空则返回真 |
front() | 返回第一个元素 |
pop() | 删除第一个元素 |
push() | 在末尾加入一个元素 |
size() | 返回队列中元素的个数 |
4. 程序代码
#include<bits/stdc++.h>
#include<queue>
using namespace std;
int main() {queue<int> q;//向空队列添加元素q.push(23);q.push(12);q.push(2);cout << "返回队列中元素的个数:";cout << q.size() << endl;cout << "返回最后一个元素:";cout << q.back() << endl;cout << "返回第一个元素:";cout << q.front() << endl;//删除第一元素q.pop();cout << "返回队列中元素的个数:"; cout << q.size() << endl;cout << "判断stack容器是否为空(为空返回1,否则返回为0):";cout << q.empty() << endl;return 0;}
运行结果:
返回队列中元素的个数:3
返回最后一个元素:2
返回第一个元素:23
返回队列中元素的个数:2
判断stack容器是否为空(为空返回1,否则返回为0):0
5. queue 例题:约瑟夫问题
#include<bits/stdc++.h>
using namespace std;
queue<int> q;
int main() {int n, m;cin >> n >> m;for(int i=1; i<=n; i++) { // 将元素入队q.push(i);}int sum=0;while(!q.empty()) { // 从头开始,如果不是被点到的人,就把该序号进入队列,然后出队 sum++; // 否则,就输出并出队 if(sum==m) {cout << q.front() << " ";q.pop();sum=0;}else{q.push(q.front());q.pop();}}return 0;
}
八、优先队列 priority_queue (不常用)
1. 优先队列的介绍
头文件:#include
定义:priority_queue p;
优先队列是队列的一种延伸,优先队列时一种比较重要的数据结构,它是有二项队列编写而成的,可以以O(log n) 的效率查找一个队列中的最大值或者最小值,其中是最大值还是最小值是根据创建的优先队列的性质来决定的。
2. 优先输出大数据
priority_queue<Type, Container, Functional>Type为数据类型, Container为保存数据的容器,Functional为元素比较方式。如果不写后两个参数,那么容器默认用的是vector,比较方式默认用operator<,也就是优先队列是大顶堆,队头元素最大。
示例:
#include<iostream>
#include<queue>
using namespace std;int main(){priority_queue<int> p;p.push(1);p.push(2);p.push(8);p.push(5);p.push(43);for(int i=0;i<5;i++){cout<<p.top()<<endl;p.pop();}return 0;
}
运行结果:
43
8
5
2
1
3. 优先输出小数据
(1)方法一
priority_queue<int, vector, greater > p;
示例:
#include<iostream>
#include<queue>
using namespace std;int main(){priority_queue<int, vector<int>, greater<int> >p;p.push(1);p.push(2);p.push(8);p.push(5);p.push(43);for(int i=0;i<5;i++){cout<<p.top()<<endl;p.pop();}return 0;
}
运行结果:
1
2
5
8
43
(2)方法二:自定义优先级,重载默认的 < 符号 (重载先不用理解)
示例:
#include<iostream>
#include<queue>
#include<cstdlib>
using namespace std;
struct Node{int x,y;Node(int a=0, int b=0):x(a), y(b) {}
};struct cmp{bool operator()(Node a, Node b){if(a.x == b.x) return a.y>b.y;return a.x>b.x;}
};int main(){priority_queue<Node, vector<Node>, cmp>p;for(int i=0; i<10; ++i)p.push(Node(rand(), rand()));//随机生成整数while(!p.empty()){cout<<p.top().x<<' '<<p.top().y<<endl;p.pop();}return 0;
}
运行结果:
491 9961
5436 4827
11942 2995
15724 19169
16827 23281
18467 41
24464 26962
26500 6334
28145 5705
29358 11478
九、集合 set
1. 集合的介绍
头文件:#include
定义:set s;
在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。set中元素的值不能直接被改变。set内部采用的是一种非常高效的平衡检索二叉树:红黑树,也称为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树。
特点:
- set中的元素都是排序好的
- set中的元素都是唯一的,没有重复的
2. set 常用成员函数
begin() | 返回指向第一个元素的迭代器 |
---|---|
clear() | 清除所有元素 |
count() | 返回某个值元素的个数 |
empty() | 如果集合为空,返回true |
end() | 返回指向最后一个元素的迭代器 |
erase() | 删除集合中的元素 |
find() | 返回一个指向被查找到元素的迭代器 |
insert() | 在集合中插入元素 |
lower_bound() | 返回指向大于(或等于)某值的第一个元素的迭代器 |
max_size() | 返回集合能容纳的元素的最大限值 |
rbegin() | 返回指向集合中最后一个元素的反向迭代器 |
rend() | 返回指向集合中第一个元素的反向迭代器 |
size() | 集合中元素的数目 |
swap() | 交换两个集合变量 |
upper_bound() | 返回大于某个值元素的迭代器 |
value_comp() | 返回一个用于比较元素间的值的函数 |
3. 程序代码
#include<bits/stdc++.h>
#include<set>
using namespace std;
int main()
{set<int> s;s.insert(1);s.insert(2);s.insert(3);s.insert(1);s.insert(9);s.insert(7);cout<<"set 的 size 值为 :"<<s.size()<<endl;cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;cout<<"set 中的第一个元素是 :"<<*s.begin()<<endl;cout<<"set 中的最后一个元素是:"<<*s.end()<<endl;//end()就是sizeset<int>::iterator it;for(it=s.begin ();it!=s.end ();it++){cout << *it << " ";}cout << endl;s.clear();if(s.empty()){cout<<"set 为空 !!!"<<endl;}cout<<"set 的 size 值为 :"<<s.size()<<endl;cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;return 0;
}
运行结果:
set 的 size 值为 :5
set 的 maxsize的值为 :461168601842738790
set 中的第一个元素是 :1
set 中的最后一个元素是:5
1 2 3 7 9
set 为空 !!!
set 的 size 值为 :0
set 的 maxsize的值为 :461168601842738790
十、map
1. map 介绍
Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据 处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的。map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。
2. map 的功能
自动建立Key - value的对应。key 和 value可以是任意你需要的类型。
根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
快速插入Key -Value 记录。
快速删除记录
根据Key 修改value记录。
遍历所有记录。
3. map 的使用
头文件:#include
定义:map<T1, T2> m T1表示关键字的数据类型, T2表示值的数据类型
4. map常用成员函数
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
insert() 插入元素
lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
5. 数据的插入
(1)用insert函数插入pair数据
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main(){map<int, string> mapStudent;mapStudent.insert(pair<int, string>(1, "student_one"));mapStudent.insert(pair<int, string>(2, "student_two"));mapStudent.insert(pair<int, string>(3, "student_three"));map<int, string>::iterator iter;for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)cout<<iter->first<<' '<<iter->second<<endl;return 0;
}
运行结果:
1 student_one
2 student_two
3 student_three
(2)用insert函数插入value_type数据
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() { map<int, string> mapStudent; mapStudent.insert(map<int, string>::value_type (1, "student_one")); mapStudent.insert(map<int, string>::value_type (2, "student_two")); mapStudent.insert(map<int, string>::value_type (3, "student_three")); map<int, string>::iterator iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) cout<<iter->first<<' '<<iter->second<<endl; return 0;
}
运行结果:
1 student_one
2 student_two
3 student_three
(3)用数组方式插入数据(常用)
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {map<int, string> mapStudent;mapStudent[1] = "student_one";mapStudent[2] = "student_two";mapStudent[3] = "student_three";map<int, string>::iterator iter;for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)cout<<iter->first<<' '<<iter->second<<endl;return 0;
}
运行结果:
1 student_one
2 student_two
3 student_three
以上三种用法,虽然都可以实现数据的插入,但是它们是有区别的,当然了第一种和第二种在效果上是完成一样的,用insert函数插入数据,在数据的 插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式就不同了,它可以覆盖以前该关键字对 应的值,用程序说明。
mapStudent.insert(map<int, string>::value_type (1, "student_one"));mapStudent.insert(map<int, string>::value_type (1, "student_two"));
上面这两条语句执行后,map中1这个关键字对应的值是“student_one”,第二条语句并没有生效,那么这就涉及到我们怎么知道insert语句是否插入成功的问题了,可以用pair来获得是否插入成功,程序如下
pair<map<int, string>::iterator, bool> Insert_Pair;insert_Pair = mapStudent.insert(map<int, string>::value_type (1, "student_one"));
通过pair的第二个变量来知道是否插入成功,它的第一个变量返回的是一个map的迭代器,如果插入成功的话Insert_Pair.second应该是true的,否则为false。
(4)验证插入函数的作用效果
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {map<int, string> mapStudent;pair<map<int, string>::iterator, bool> Insert_Pair;Insert_Pair = mapStudent.insert(pair<int, string>(1, "student_one"));if(Insert_Pair.second == true)cout<<"Insert Successfully"<<endl;elsecout<<"Insert Failure"<<endl;Insert_Pair = mapStudent.insert(pair<int, string>(1, "student_two"));if(Insert_Pair.second == true)cout<<"Insert Successfully"<<endl;elsecout<<"Insert Failure"<<endl;map<int, string>::iterator iter;for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)cout<<iter->first<<' '<<iter->second<<endl;return 0;
}
运行结果:
Insert Successfully
Insert Failure
1 student_one
(5)验证数组形式插入数据的效果
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {map<int, string> mapStudent;mapStudent[1] = "student_one";mapStudent[1] = "student_two";mapStudent[2] = "student_three";map<int, string>::iterator iter;for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)cout<<iter->first<<' '<<iter->second<<endl;return 0;
}
运行结果:
1 student_two
2 student_three
6. 数据的遍历
(1)应用前向迭代器,上面举例程序中到处都是了,略过不表
(2)利用反向迭代器
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {map<int, string> mapStudent;mapStudent.insert(pair<int, string>(1, "student_one"));mapStudent.insert(pair<int, string>(2, "student_two"));mapStudent.insert(pair<int, string>(3, "student_three"));map<int, string>::reverse_iterator iter;for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++)cout<<iter->first<<" "<<iter->second<<endl;return 0;
}
运行结果:
3 student_three
2 student_two
1 student_one
(3):用数组方式
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {map<int, string> mapStudent;mapStudent.insert(pair<int, string>(1, "student_one"));mapStudent.insert(pair<int, string>(2, "student_two"));mapStudent.insert(pair<int, string>(3, "student_three"));int nSize = mapStudent.size(); //map中元素的个数
//此处应注意,应该是 for(int nindex = 1; nindex <= nSize; nindex++)
//而不是 for(int nindex = 0; nindex < nSize; nindex++)for(int nindex = 1; nindex <= nSize; nindex++)cout<<mapStudent[nindex]<<endl;return 0;
}
运行结果:
student_one
student_two
student_three
7. 查找并获取map中的元素
在这里我们将体会,map在数据插入时保证有序的好处。
要判定一个数据(关键字)是否在map中出现的方法比较多,这里标题虽然是数据的查找,在这里将穿插着大量的map基本用法。
这里给出三种数据查找方法
第一种:用count函数来判定关键字是否出现,其缺点是无法定位数据出现位置,由于map的特性,一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1,出现的情况,当然是返回1了
第二种:用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器。
查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,
分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.
程序代码:
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() { map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, "student_one")); mapStudent.insert(pair<int, string>(2, "student_two")); mapStudent.insert(pair<int, string>(3, "student_three")); map<int, string>::iterator iter; iter = mapStudent.find(1); if(iter != mapStudent.end()) cout<<"Find, the value is "<<iter->second<<endl; else cout<<"Do not Find"<<endl; return 0;
}
运行结果:
Find, the value is student_one
8. 从map中删除元素
移除某个map中某个条目用erase()
该成员方法的定义如下:
iterator erase(iterator it);//通过一个条目对象删除
iterator erase(iterator first,iterator last)//删除一个范围
size_type erase(const Key&key);//通过关键字删除
clear()就相当于enumMap.erase(enumMap.begin(),enumMap.end());
这里要用到erase函数,它有三个重载了的函数,下面在例子中详细说明它们的用法
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main() {map<int, string> mapStudent;mapStudent.insert(pair<int, string>(1, "student_one"));mapStudent.insert(pair<int, string>(2, "student_two"));mapStudent.insert(pair<int, string>(3, "student_three"));//如果你要演示输出效果,请选择以下的一种,你看到的效果会比较好//如果要删除1,用迭代器删除map<int, string>::iterator iter;iter = mapStudent.find(1);mapStudent.erase(iter);//如果要删除1,用关键字删除int n = mapStudent.erase(1);//如果删除了会返回1,否则返回0//用迭代器,成片的删除//一下代码把整个map清空mapStudent.erase( mapStudent.begin(), mapStudent.end() );//成片删除要注意的是,也是STL的特性,删除区间是一个前闭后开的集合//自个加上遍历代码,打印输出吧return 0;
}
9. map中的sort的用法
map中的元素是自动按Key升序排序,所以不能对map用sort函数;
这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题的,因为上面的关键字是int 型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数在编译的时候过 不去,下面给出两个方法解决这个问题。
这里只解析第一种方法
(1)小于号重载
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef struct tagStudentinfo {int niD;string strName;bool operator < (tagStudentinfo const& _A) const { //这个函数指定排序策略,按niD排序,如果niD相等的话,按strName排序if(niD < _A.niD)return true;if(niD == _A.niD)return strName.compare(_A.strName) < 0;return false;}} Studentinfo, *PStudentinfo; //学生信息int main() {int nSize; //用学生信息映射分数map<Studentinfo, int>mapStudent;map<Studentinfo, int>::iterator iter;Studentinfo studentinfo;studentinfo.niD = 1;studentinfo.strName = "student_one";mapStudent.insert(pair<Studentinfo, int>(studentinfo, 90));studentinfo.niD = 2;studentinfo.strName = "student_two";mapStudent.insert(pair<Studentinfo, int>(studentinfo, 80));for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++)cout<<iter->first.niD<<' '<<iter->first.strName<<' '<<iter->second<<endl;return 0;
}
运行结果:
1 student_one 90
2 student_two 80
mapStudent.erase(iter);
//如果要删除1,用关键字删除
int n = mapStudent.erase(1);//如果删除了会返回1,否则返回0
//用迭代器,成片的删除
//一下代码把整个map清空
mapStudent.erase( mapStudent.begin(), mapStudent.end() );
//成片删除要注意的是,也是STL的特性,删除区间是一个前闭后开的集合
//自个加上遍历代码,打印输出吧
return 0;
}
### 9. map中的sort的用法map中的元素是自动按Key升序排序,所以不能对map用sort函数;这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题的,因为上面的关键字是int 型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数在编译的时候过 不去,下面给出两个方法解决这个问题。**这里只解析第一种方法**#### (1)小于号重载
#include
#include
#include
using namespace std;
typedef struct tagStudentinfo {
int niD;
string strName;
bool operator < (tagStudentinfo const& _A) const { //这个函数指定排序策略,按niD排序,如果niD相等的话,按strName排序
if(niD < _A.niD)
return true;
if(niD == _A.niD)
return strName.compare(_A.strName) < 0;
return false;
}
} Studentinfo, *PStudentinfo; //学生信息
int main() {
int nSize; //用学生信息映射分数
map<Studentinfo, int>mapStudent;
map<Studentinfo, int>::iterator iter;
Studentinfo studentinfo;
studentinfo.niD = 1;
studentinfo.strName = "student_one";
mapStudent.insert(pair<Studentinfo, int>(studentinfo, 90));
studentinfo.niD = 2;
studentinfo.strName = "student_two";
mapStudent.insert(pair<Studentinfo, int>(studentinfo, 80));
for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++)cout<<iter->first.niD<<' '<<iter->first.strName<<' '<<iter->second<<endl;return 0;
}
运行结果:
1 student_one 90
2 student_two 80
_______________________________________________________________________
浅谈C++ 之STL相关推荐
- python竞赛_浅谈Python在信息学竞赛中的运用及Python的基本用法
浅谈Python在信息学竞赛中的运用及Python的基本用法 前言 众所周知,Python是一种非常实用的语言.但是由于其运算时的低效和解释型编译,在信息学竞赛中并不用于完成算法程序.但正如LRJ在& ...
- 浅谈C++的智能指针
一转:http://www.cppblog.com/yearner/archive/2008/11/09/66447.html 浅谈C++的智能指针 内存泄露是C++程序员都头疼的大问题.C++缺乏像 ...
- muduo网络库浅谈(一)
muduo网络库浅谈(一) 序言 第一章 muduo的关键结构 class EventLoop class Channel class Poller 番外 定时任务 class Timestamp c ...
- Java开发的B/S程序生成并向客户端发送excel文件:浅谈MIME
Java开发的B/S程序生成并向客户端发送excel文件:浅谈MIME 1.定义 MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定 ...
- 浅谈对SprutCAM学习认识
SprutCAM简介 SprutCAM软件在国内被称为司普禄(我猜是音译的),是由俄罗斯开发团队研发,国内昆山司普禄科技公司代理,这个软件十分强大,可以仿真模拟市面上的绝大部分的工业机器人,相对于四大 ...
- 春招/秋招面试前必看一文。如何找到 BAT 的实习机会。找实习中的一些困惑,如何解决?。浅谈秋招。
春招/秋招面试前必看一文 春节过完,不管是大三/研二.还是大四/研三,就要投入到最激烈的春招当中去了,各大公司将会正式招聘,由元旦期间拉开序幕(1 - 2 月),到彻底的进入白热化阶段(3 - 4 月 ...
- 浅谈MySQL存储引擎-InnoDBMyISAM
浅谈MySQL存储引擎-InnoDB&MyISAM 存储引擎在MySQL的逻辑架构中位于第三层,负责MySQL中的数据的存储和提取.MySQL存储引擎有很多,不同的存储引擎保存数据和索引的方式 ...
- 【大话设计模式】——浅谈设计模式基础
初学设计模式给我最大的感受是:人类真是伟大啊!单单是设计模式的基础课程就让我感受到了强烈的生活气息. 个人感觉<大话设计模式>这本书写的真好.让貌似非常晦涩难懂的设计模式变的生活化.趣味化 ...
- 学校计算机机房好处,浅谈学校计算机机房维护
浅谈学校计算机机房维护 现在的学校机房都配置了数量较多的计算机,而且机房的使用非常频繁.对于怎样维护好计算机,特别是计算机软件系统,对广大计算机教师来说是一个很重要且非常现实的问题.下面就本人在 ...
最新文章
- python有关迭代器和生成器的面试题_【面试题 | Python中迭代器和生成器的区别?】- 环球网校...
- 百练OJ:2713:肿瘤面积
- tensorflow中name_scope和variable_scope变量的使用
- 压缩vmware中的ubuntu系统(虚拟机瘦身大法)
- centos7与centos6区别
- 如何把winform图片背景换成透明颜色_如何用photoshop更换图片背景颜色?
- 去除UINavigationBar的下边框
- 在django中使用vue.js需要注意的地方
- vm安装diagram
- [NOIP2013D2]
- 数字签名的生成和验证
- 某天的零点时刻0:0:0 和截至时刻23:59:59
- CS5801HDMI转EDP转换器芯片参考资料|CS5801HDMI转EDP转换方案说明
- 2022年行研行业研究报告
- iPhone6 像素 分辨率
- 华语金曲30年30歌
- 什么是HTTPS,与HTTP的区别?
- 中国铁路 12306 网站的高并发架构带来的思考?研究分析后,果然超牛逼…
- 应届毕业生北京租房经验
- 洛谷——P3906 Geodetic集合
热门文章
- 使用谷歌浏览器控制台提示[DOM] Password field is not contained in a form:
- 完全用Linux工作,作者王垠
- Python爬虫随笔:爬取iciba上的单词发音文件
- 配置路由器接口使用PPP协议封装
- The fourth,fifth,sixth,seventh episode of Crazily Speak English
- FM知名芯片商芯略总裁因侵权被警方拘留
- 大数据技术特点及优势有哪些
- USTC科研 7.1 and 7.3 配置环境的学习
- LaTeX排版常用字体和格式设置
- CSS Grid 网格布局完整教程