- 6.1 Vector常见用法详解
- 6.2 set的常见用法解析 (集合的原理)
- 6.3 String常见用法解析
- 6.4 map常用用法详解
- 6.5 queue常见用法解析(数据结构——队列)
- 6.6 priority_queue常见用法解析
- 6.7 stack常见用法详解 (数据结构——栈)
- 6.8 pair的常见用法解析(头文件:
) - 6.9 algorithm头文件下的常用函数
6.1 Vector常见用法详解
1. vector定义
ps: 头文件 #include
vector<typename> name;
**我们其实可以把vector理解为变长数组。长度可以根据需要进行变化。**
vector<vector<int> > vi;
2. vector内元素的访问
(1)下标访问(vi[0])(但是越界容易出问题,不常用)
(2)迭代器访问(important)
vector<int >::iterator it;
**这样就得到了迭代器it,并可以通过*it来访问vector里的元素。**
3. 常用函数
(1)push_back( ) (在后面加元素)
(2)pop_back( ) (删除尾元素) (不要参数)
(3)size( ) (获得vector中元素的个数)
(4)clear( ) (清空所有元素,size()变为0了)
(5) insert( )
**insert(it,x)用来向任意迭代器it处插入一个元素x,时间复杂度O(N)**
(6)erase( )
erase()既可以删除单个元素,也可以删除一个区间的元素,但是注意:区间还是左闭右开
下面的代码综合使用了上述几种函数:
#include <cstdio>#include <vector>using namespace std;int main(){vector<int> vi;vector<int>::iterator it;for(int i = 0; i < 10; ++i){vi.push_back(i);}vi.pop_back();for(it = vi.begin(); it != vi.end(); ++it){printf("%d ",*it);}printf("\n");printf("size: %d\n",vi.size());vi.insert(vi.begin()+2,-1);for(it = vi.begin(); it != vi.end(); ++it){printf("%d ",*it);}printf("\n");printf("size: %d\n",vi.size());vi.erase(vi.begin()+1);for(it = vi.begin(); it != vi.end(); ++it){printf("%d ",*it);}printf("\n");printf("size: %d\n",vi.size());vi.erase(vi.begin()+5,vi.begin()+7);for(it = vi.begin(); it != vi.end(); ++it){printf("%d ",*it);}printf("\n");printf("size: %d\n",vi.size());vi.clear();printf("size: %d ",vi.size());return 0;}
4. vector常见用途
(1)储存数据
(2)用邻接表存储图
6.2 set的常见用法解析 (集合的原理)
**set是一个内部自动有序且不含重复元素的容器。**
1. set的定义
set<typename> name;set<typename> Arrayname[arraysize] ;
2. set容器内元素的访问(only through 迭代器)
注意: 除了vector和string之外的STL容器都不支持*(it+i)的访问方式 !! 因此只能通过下列方式枚举。
#include <cstdio>#include <set>using namespace std;int main(){set<int> st;set<int>::iterator it;st.insert(2);st.insert(5);st.insert(4);for(it = st.begin(); it != st.end(); ++it){printf("%d ",*it);}return 0;}
尝试跑一下程序,输出为2 4 5,发现set内的元素自动递增排序,且自动去除了重复元素。
3. set常用函数
(1)insert()
(2)find()
find(value) 返回set中对应值为value的迭代器。
(3)erase() (单个 & 区间)
1)删除单个元素
(a) st.erase(it)
st.erase(st.find(100); //利用find函数找到100,然后用erase删除
(b) st.erase(value)
st.erase(100);
2)删除区间内所有元素
it = st.find(100);st.erase(it,st.end()); // 删除元素100至set末尾之间的所有元素
(4) size() (获得set内元素个数)
(5) clear( ) (清空set内所有元素)
6.3 String常见用法解析
1. string的定义
// 两种方法string s1;string s2 = "assdf";
2. string中内容的访问
(1)通过下标访问
#include <string>using namespace std;int main(){string str = "abcde";for(int i = 0; i < str.length(); ++i){printf("%c",str[i]);}return 0;}
(2)通过迭代器访问
首先来看一下string 的 迭代器的定义:
string::iterator it;
借此,可以通过*it来访问string的内容:👇
#include <string>using namespace std;int main(){string str = "abcde";string::iterator it;for(it = str.begin(); it != str.end(); ++it){printf("%c",*it);}return 0;}
3. 常用函数解析
(1) operator += (字符串拼接,b接到a的后面)
(2)compare operator (可以直接当数字比较,按照字典序比大小)、
(3)length( ) & size() (length返回字符串string的长度,即存放发字符数)
(4)insert( )
1) insert(pos,string)
#include <iostream>#include <string>using namespace std;int main(){string str1 = "abcde";string str2 = "ppp";str1.insert(1,str2); // str2的位置直接写"ppp"也行cout<<str1<<endl;return 0;}// 输出: apppbcde
2)insert(it,it2,it3),it为原字符串的欲插入位置,it2和it3为待插入字符串的收尾迭代器(左闭右开【it2,it3))
(5)erase()
1)删除单个元素
str.erase(it); // it是要删除元素的迭代器
2) 删除区间内所有元素 (两种方法如下:)
str.erase(it1,it2); // it1,it2是要删除元素的首尾迭代器(左闭右开)
str.erase(pos,length); // 删除从pos开始的length个字符
看个例子:
#include <iostream>#include <string>using namespace std;int main(){string str = "abcdefghi";string::iterator it = str.begin();for(it = str.begin(); it != str.end(); ++it){printf("%c",*it);}printf("\n");it = str.begin();str.erase(it+1,it+3);for(it = str.begin(); it != str.end(); ++it){printf("%c",*it);}printf("\n");it = str.begin();str.erase(4,2);for(it = str.begin(); it != str.end(); ++it){printf("%c",*it);}printf("\n");return 0;}//输出:abcdefghiadefghiadefi
(6) clear ()
(7) substr ( )
substr(pos,len)返回从pos号位开始,长度为len的子串。
#include <iostream>#include <string>using namespace std;int main(){string str = "abcdefghi";cout << str.substr(2,4)<<endl;return 0;}// 输出: cdef
(8)string::npos
string::npos作为find函数失配时的返回值(当成常数,unsigned_int类型)
(9)find()
1)str.find(str2),当str2是str的子串时,返回第一次出现的位置(索引);如果不是子串,返回string::npos
2)str.find(str2,pos),从str的pos号位开始匹配str2,返回值与上相同
(10)replace( )
1)str.replace(pos,len,str2)把str从pos号位开始,长度为len的子串替换为str2
2) str.replace(it1,it2,str2)把 [ it1, it2 ) 范围的子串替换为str2
4. Example : A1060
如果一台机器只能保存 3 位有效数字,则浮点数 12300 和 12358.9 被认为是相等的,因为它们都保存为 0.123×10^5
问题描述:
用简单的切碎。现在给定机器上的有效位数和两个浮点数,您应该知道它们在该机器中是否被认为相等。
输入规格:
每个输入文件包含一个测试用例,它给出三个数字 N、A 和 B,其中 N (<100) 是有效位数,A 和 B 是要比较的两个浮点数。每个浮点数都是非负数,不大于 10^100 , 并且其总位数小于 100。
输出规格:
对于每个测试用例,如果两个数字相等,则打印一行 YES,然后打印标准格式 0.d[1]…d[N]*10^k (d[1]>0除非数字是 0);或否,如果他们不被平等对待,然后是标准形式的两个数字。所有术语必须用空格分隔,行尾没有多余的空格。
注意:假设简单切碎,不进行四舍五入。
Sample Input 1:
Sample Output 1:
Sample Input 2:
Sample Output 2:
题解:
代码:
#include <iostream>#include <string>using namespace std;int n; // 精度数string change (string s,int& e) // e是指数{int k = 0;while (s.length() > 0 && s[0] == '0'){s.erase(s.begin()); // 去掉s的前导0}if(s[0] == '.'){ // 去掉前导0就是小数点,说明s是小于1的数s.erase(s.begin());while (s.length() > 0 && s[0] == '0'){s.erase(s.begin());--e; // 去掉一个0,e就--, 0.003 指数就是-2}}else{ // 去掉前导0后不是小数点,则找到后面的小数点并删除while (k < s.length() && s[k] != '.'){++k;++e;}if(k < s.length()){s.erase(s.begin()+k);}}if(s.length() == 0){ // 去掉前导0后长度变为0,则说明这个数就是0e = 0;}int num = 0;k = 0; // !!!!!!! 一定把k重新置0,significant!!!string res;while (num < n){if(k < s.length()){res += s[k++];}else{res += '0';}++num;}return res;}int main(){string s1,s2,s3,s4;int e1 = 0, e2 = 0;cin>>n>>s1>>s2;s3 = change(s1,e1);s4 = change(s2,e2);if(s3 == s4 && e1 == e2){cout<<"YES 0."<<s3<<"*10^"<<e1<<endl;}else{cout<<"NO 0."<<s3<<"*10^"<<e1<<" "<<"0."<<s4<<"*10^"<<e2<<endl;}return 0;}
6.4 map常用用法详解
1. map的定义:
map<typename1, typename2> mp;
2. map元素访问
(1)通过下标访问
我们先来看一组代码:
#include <map>using namespace std;int main(){map<char, int> mp;mp['c'] = 20;mp['c'] = 30;printf("%d",mp['c']);return 0;}// 输出:30
这段代码内部 不仅说明了map可以通过下标来访问,还说明了map中的键值是唯一的,上面代码中30就把20覆盖掉了。
(2)通过迭代器访问
用it->first访问键,用it->second访问值。
#include <map>using namespace std;int main(){map<char, int> mp;map<char, int>::iterator it;mp['m'] = 20;mp['r'] = 30;mp['a'] = 40;for(it = mp.begin(); it != mp.end(); ++it){printf("%c %d\n",it->first,it->second);}return 0;}//输出:a 40m 20r 30
我们看一下输出,就会发现输出中键已经被排好序了,从小到大,即a<m<r,这是因为map内部使用红黑树实现的(set也是),因此在建立映射的过程中实现从小到大排序的功能。
3. 常用函数解析
(1)find()
find(key)返回值为key的映射的迭代器。(一般用it接收一下)(参数是key!!!)
(2)erase()
1) 删除单个元素:
mp.erase(it)& mp.erase(key)
#include <map>using namespace std;int main(){map<char, int> mp;map<char, int>::iterator it;mp['m'] = 20;mp['r'] = 30;mp['a'] = 40;it = mp.find('m');mp.erase(it);for(it = mp.begin(); it != mp.end(); ++it){printf("%c %d\n",it -> first, it -> second);}printf("size: %d\n",mp.size());mp.erase('r');for(it = mp.begin(); it != mp.end(); ++it){printf("%c %d\n",it -> first, it -> second);}printf("size: %d\n",mp.size());return 0;}// 输出:a 40r 30size: 2a 40size: 1
2)删除区间内所有元素
(3)size()(获得映射的对数)
(4)clear()(清空map中所有元素)
4. map常见用途
①需要建立字符(或字符串)与整数之间映射的题目,使用map可以减少代码量。
②判断大整数或者其他类型数据是否存在的题目,可以把map当bool数组用。
③字符串和字符串的映射也有可能会遇到。
延伸:map的键和值是唯一的,而如果一个键需要对应多个值,就只能用multimap。另外,C++11标准中环广加了unordered_map,以散列代替map内部的红黑树实现,使其可以用来处理只映射而不按kev排序的需求,速度比map要快得多,有兴趣的读者可以自行了解,此处不多作说明。
6.5 queue常见用法解析(数据结构——队列)
1. queue的定义
queue<typename > name;
2. queue元素访问
队列,先进先出,访问方式唯一:front访问队首元素,back( )访问队尾元素。
3. 常用函数解析
(1) push( ) (入队)
(2)front()、back() (访问队首和队尾元素)
(3)pop() (队首元素出队)
(4)empty() (返回true则空,返回false则不空)
(5)size() (返回queue内元素的个数)
#include <iostream>#include <queue>using namespace std;int main(){queue<int> q;for(int i = 1; i <= 5; ++i){q.push(i*2); // 依次入队1、2、3、4、5}for(int i = 1; i <= 3; ++i){q.pop();}printf("front:%d\n",q.front());printf("size:%d\n",q.size());if(q.empty() == true){printf("Empty!\n");}if(q.empty() == false){printf("Not Empty!\n");}return 0;}//输出:front:8size:2Not Empty!
注意: 使用front( )和 pop( )函数前,必须用empty( )函数判断队列是否为空,否则可能因队空而出现错误。
4. queue常见用途(感兴趣可以了解deque双端队列)
6.6 priority_queue常见用法解析
priority_queue称为优先队列,底层用堆来实现。队首元素一定是优先级最高的。(可以定义数越小优先级越高,这个随意定义)
1. priority_queue的定义
priority_queue<typename > q;
2. priority_queue元素的访问
只能通过top( ) 来访问队首元素(也成为堆顶元素),也就是优先级最高的元素。
3. priority_queue常用函数解析
(1)push( ) (push(x)将令x入队)
(2)top( ) (获得队首元素)
(3)pop( ) (令队首元素出队)
(4)empty( ) (同上)
(5)size( ) (同上)
#include <iostream>#include <queue>using namespace std;int main(){priority_queue<int > q;q.push(3);q.push(4);q.push(1);printf("top_now: %d\n",q.top());q.pop();printf("top_now: %d\n",q.top());return 0;}//输出:top_now: 4top_now: 3
4. priority_queue内元素优先级设置
本章最开始我们说了优先级的设置可以自定义,不一定是数字越大优先级越高,接下来我们一起来看一下优先级的设置。
(1)基本数据类型的优先级设置
如果不做特殊的事情,对于基本数据类型,编译器默认数字越大优先级越高。下面两种写法其实是等价的:
priority_queue<int > q;
priority_queue<int, vector<int>, less<int> > q;
我们有必要解释一下后两个参数,第二个参数是来承载底层数据结构堆(heap)的容器,第一个参数是int型,这里类型就是int。第三个参数是优先级设置参数,less
因此,要想把数字最小的放在队首,只需如下定义:
priority_queue<int, vector<int>, greater<int> > q;
还需要说明一下,上面这行代码随后两个“>”要加空格,C++11会把两个连在一起的认为是位运算。
(2)结构体的优先级设置
核心:小于号“<”的重载 (不要重载>号,会有问题,重载<能解决全部问题了)
下面这段代码就实现了价格低的优先级高(在队首)(与sort的cmp的功能相反)
struct fruit{string name;int price;friend bool operator < (fruit f1, fruit f2){return f1.price > f2.price;}};
当然,也可以使用三个参数定义priority_queue,然后第三个蚕食换成cmp,就类似sort的用法。
最后指出,如果结构体内的数据较为庞大(例如出现了字符串或者数组),建议便用5用来提高效率,此时比较类的参数中需要加上“const”和“&”,如下所示:
5. priority_queue常见用途
(1)解决贪心问题,并对Dijkstra算法优化(本质是堆)
(2)使用top前,必须用empty判断是否为空
6.7 stack常见用法详解 (数据结构——栈)
1. stack的定义
stack<typename > name;
2. stack容器内元素的访问
3. stack常用函数介绍
(1) push( ) (入栈)
(2)top( ) (获得栈顶元素)
(3)pop( ) (弹出栈顶元素)
(4)empty( ) (同上)
(5)size( ) (同上)
4. stack常见用途
6.8 pair的常见用法解析(头文件:)
pair可以理解为内部有两个元素的结构体。
map头文件包含utility
1. pair的定义
pair有两个参数,分别对应first和second的数据类型:👇
pair<typeName1, typrName2> name;
想要在定义的时候即初始化,如下:👇
pair<string, int> p("hello",6);
2. pair元素访问
pair中一共有两个元素,分别是first和second,当作结构体来访问就OK了。
3. pair常用函数
(1)比较操作函数
两个类型相同的pair可以直接比大小,先比firsr,再比second。
4. pair常见用途
(1)代替二元结构体及其构造函数,节省时间
(2)作为map的键值进行插入,如下:
#include <map>#include <iostream>using namespace std;int main(){map<string, int> mp;map<string, int>::iterator it;mp.insert(make_pair("aa",5));mp.insert(pair<string, int>("bb",66)); // 直接初始化,不用起名字for(it = mp.begin(); it != mp.end(); ++it){cout << it->first << " " << it->second <<endl;}return 0;}// 输出:aa 5bb 66
6.9 algorithm头文件下的常用函数
1. max( ), min( ) ,abs( )
max和min参数必须是2个,可以嵌套。整型用abs( ),浮点型用fabs( )
2. swap( )
3. reverse( )
reverse(it1, it2)可以将数组指针或容器的迭代器在【it1,it2) 范围内的元素进行反转。
4. next_permulation( )
给出一个序列在全排列中的下一个序列,详见:https://blog.csdn.net/sgsyacm/article/details/80139089
5. fill( )
fill函数类似于我们之前学过的memset,但是比memset更好用,我们之前说过,memset只能把整体赋值为0或-1,但是fill可以赋为任意的值。
#include <map>#include <iostream>using namespace std;int main(){int a[5] = {1, 2, 3, 4, 5};fill(a, a + 5, 20);for(int i = 0; i < 5; ++i){printf("%d ",a[i]);}return 0;}
6. sort函数 (略)
7. lower_bound( ) 和 upper_bound( )
lower_bound(first,last,val) 寻找范围内第一个 >= val的位置,返回指针或迭代器 (不存在则返回应插入的位置)
upper_bound(first,last,val) 寻找范围内第一个 > val的位置,返回指针或迭代器 (不存在则返回应插入的位置)
直接调用返回的是指针或者迭代器,如果我们想得到数组元素的下标,那就用一个指针接收返回值,然后减首元素地址(数组名)即可。我们看下这个例子:👇
#include <cstdio>#include <algorithm>using namespace std;int main(){int a[10] = {1,2,2,3,3,3,5,5,5,5};int *lowerPos = lower_bound(a, a + 10, -1);int *upperPos = upper_bound(a, a + 10, -1);printf("%d, %d\n",lowerPos - a, upperPos - a);lowerPos = lower_bound(a, a + 10, 3);upperPos = upper_bound(a, a + 10, 3);printf("%d, %d\n",lowerPos - a, upperPos - a);lowerPos = lower_bound(a, a + 10, 10);upperPos = upper_bound(a, a + 10, 10);printf("%d, %d\n",lowerPos - a, upperPos - a);}//输出:0, 03, 610, 10

