感觉自己记性真的不行,很多之前用过,查过的知识点都忘掉了,开个博客记一下吧。
迭代器
基本格式: 容器类名::iterator 迭代器名;
举两个例子
vector<int>::iterator ite;
map<int,int>::iterator ite;
迭代器又分四种,常用的是正向迭代器(上面那个)和反向迭代器,正弦迭代器指向容器头从前往后遍历,反向迭代器指向容器尾从后往前遍历。
迭代器类型 | 定义 |
---|
正向迭代器 | 容器类名::iterator 迭代器名; | 常量正向迭代器 | 容器类名::const_iterator 迭代器名; | 反向迭代器 | 容器类名::reverse_iterator 迭代器名; | 常量反向迭代器 | 容器类名::const_reverse_iterator 迭代器名; |
浅测一下正向和反向
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
vector<int>::iterator itez = v.begin();
while (itez != v.end()) {
cout << *itez << endl;
itez++;
}
cout << endl;
vector<int>::reverse_iterator itef = v.rbegin();
while (itef != v.rend()) {
cout << *itef << endl;
itef++;
}
return 0;
}
这边注意一下:
-
容器.end()指向的是容器中最后一个元素的下一个,所有不要尝试让正向迭代器指向容器.end(),通过这样配合迭代器–逆向遍历,这是不可行的,哒咩!!! 同理.容器.rend()指向的是容器第一个元素的上一个位置!! -
迭代器其实和指针很像,指向的是一片地址空间,不是存储的内容(值)。通过迭代器可以读取它指向的元素,*迭代器名就表示迭代器指向的元素。通过非常量迭代器还能修改其指向的元素。常量迭代器不允许修改指向的元素。 -
迭代器都可以进行++操作。反向迭代器和正向迭代器的区别在于:对正向迭代器进行++操作时,迭代器会指向容器中的后一个元素(正序遍历);而对反向迭代器进行++操作时,迭代器会指向容器中的前一个元素。(逆序遍历) -
一个不被注意的知识:写++ite相比于写ite++,程序的执行速度更快。因为后置++要多生成一个局部对象 tmp,因此执行速度比前置的慢。 -
容器适配器 stack、queue 和 priority_queue 没有迭代器。
不同容器的迭代器的功能
容器 | 迭代器功能 |
---|
vector | 随机访问 | deque | 随机访问 | list | 双向 | set / multiset | 双向 | map / multimap | 双向 | stack | 不支持迭代器 | queue | 不支持迭代器 | priority_queue | 不支持迭代器 |
-
正向迭代器。支持以下操作:++ite,ite++,*ite。此外,两个正向迭代器可以互相赋值,还可以用==和!=运算符进行比较。 -
双向迭代器。除++ite,ite++,*ite之外,还可以–ite,ite–。–ite使得 ite朝和++ite相反的方向移动。 -
随机访问迭代器。正向反向都行。而且可以随机访问。 p+=i,p-=i,p+i,p-i还有p[i]:返回 p 后面第 i 个元素的引用,比如p指向容器vector<int>v的开头,那么p[i]就是v数组的第i个元素。
lower_bound,upper_bound
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,const T& val);
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,const T& val);
二分查找 lower_bound找的是第一个比val大于等于的数 upper_bound找的是第一个比val大于的数 查找结束,函数返回一个正向迭代器,当查找成功时,迭代器指向找到的元素;反之,如果查找失败,迭代器的指向和 指向容器end()迭代器相同。 如果要返回元素的位置,记得要将查找结果与容器.begin()相减。
int divG = lower_bound(onlyGrades.begin(), onlyGrades.end(), G)-onlyGrades.begin();
其实还有equal_range() 以及 binary_search(),但我好像没用过。 这四个函数底层实现采用的都是二分查找的方式。
这里补充一下我之前没注意过的关于lower_bound的一个知识点,upper_bound同理: 上面那种语法格式其实也有设定有比较规则,只不过此规则无法改变,即使用 < 小于号比较 [first, last) 区域内某些元素和 val 的大小(这块可以理解为比较范围内的元素从小到大排序),直至找到一个不小于 val 的元素。这也意味着,如果使用第一种语法格式,则 [first,last) 范围的元素类型必须支持 < 运算符。
其实我们手写二分查找也是要求元素顺序排序。 第一种语法规则要求数据必须从小到大排列
可以忽略,我暂时没发现用处
然后我们看一下第二种语法规则,第二种语法规则可以使数据内元素不受从小到大的排序限定。
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,const T& val, Compare comp);
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last,const T& val, Compare comp);
其中,first 和 last 都为正向迭代器,[first, last) 用于指定函数的作用范围;val 用于指定目标元素;comp 用于自定义比较规则,comp作为参数可以接收一个包含 2 个形参(第二个形参值始终为 val)且返回值为 bool 类型的函数,可以是普通函数,也可以是函数对象。
举个例子
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class mycomp {
public:
bool operator()(const int& i, const int& j) {
return i > j;
}
};
int main() {
vector<int> myvector{ 4,5,3,1,2 };
vector<int>::iterator iter = lower_bound(myvector.begin(), myvector.end(), 3, mycomp());
cout << "*iter = " << *iter;
return 0;
}
这段代码中,val=3作为mycomp的第二个参数j传入,也就是说这段代码的作用就是找到没有排序规律的容器myvector中第一个不满足元素大于3(j)的元素的位置。 如果myvector{ 4,5,3,1,2 }变成myvector{ 1,5,3,1,2 }结果还是3,因为这玩意的基本实现是二分查找!!咱也不懂这玩意有啥用,我本来是想找实现反向二分查找的…
这个比较有用:不同容器的lower_bound
前提,元素从小到大排序
1.vector,数组
int pos=lower_bound(Vector.begin(),Vector.end(),val)-Vector.begin();
int pos=lower_bound(Arr,Arr+数组的大小,val)-Arr.begin();
2.set,map(本身是按照key从小到大排序)
set<int>::iterator it;
it=Set.lower_bound(val);
map<int,int>::iterator it;
it=Map.lower_bound(val);
暂时就知道这两种
这边再补充一下pair作为vector的元素类型时候如何使用lower_bound: 前置知识: 1.pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。实质上就是一个结构体。初始化一个pair可以使用构造函数,也可以使用std::make_pair函数。
make_pair{first_ele,second_ele}
pair+lower_bound
2.pair作为vector的数据类型进行sort排序,默认排序是先比较first再比较second。
按照前置知识2看来,lowwer_bound和pair的联合使用可能使先判断first元素再判断second元素
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
int main() {
vector<pair<int, char>>v;
v.push_back({ 1,'a'});
v.push_back({ 2,'b'});
v.push_back({ 3,'c'});
v.push_back({ 4,'d'});
v.push_back({ 5,'e'});
int pos = lower_bound(v.begin(), v.end(), pair<int, char>{ 2, 'a'}) - v.begin();
cout << pos;
pos=lower_bound(v.begin(), v.end(), pair<int,char>{ 2,'b'})-v.begin();
cout << pos;
pos = lower_bound(v.begin(), v.end(), pair<int, char>{ 2, 'k'}) - v.begin();
cout << pos;
return 0;
}
来解释一下如何比较的。 第一个{ 2, ‘a’},{1,‘a’}比}他小,{2,’b’}比它大,所有是1。 第二个不用说。 第三个{2,‘k’},找第一个大于等于的,{2,‘b’}小于,{3,‘c’}大于,所以是2。
所以说,如果我们对于一个pair类型要进行二分查找,让要进行比较的元素类型放在第一位,然后对val(pair类型的)的第二位最小就能够实现只对第一位进行比较。 如果pair内有字符串,且不作为比较的元素类型,字符串的话你弄个空作为第二位。
测试一下 完美!
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
int main() {
vector<pair<int, string>>v;
v.push_back({ 1,"12345"});
v.push_back({ 2,"12fsd" });
v.push_back({ 2,"sd" });
v.push_back({ 3,"dxfghjihgfcxd" });
v.push_back({ 4,"12bbbbajskf345" });
v.push_back({ 5,"12dhjk345" });
int pos = lower_bound(v.begin(), v.end(),(pair<int, string>)make_pair(2, "")) - v.begin();
cout << pos;
return 0;
}
数字转字符串,字符串转数字
后一个倒是记得,前一种好像没怎么用过
数字转字符串
头文件:<stdlib.h> 这个属于c语言的放到c++就换成头文件:<cstdlib>
函数名 | 函数作用 |
---|
itoa() | 将整型值转换为字符串 | itoa() | 将长整型值转换为字符串 | ultoa() | 将无符号长整型值转换为字符串 | ecvt() | 将双精度浮点型值转换为字符串,转换结果中不包含十进制小数点 | fcvt() | 以指定位数为转换精度,余同ecvt() | gcvt() | 将双精度浮点型值转换为字符串,转换结果中包含十进制小数点 |
用itoa举例一下这个函数的使用
char *itoa (int value, char *str, int base );
int value 被转换的整数,char *string 转换后储存的字符数组,是字符数组!!int radix 转换进制数,如2,8,10,16 进制等,大小应在2-36之间。
#include <iostream>
#include <algorithm>
#include<cstdlib>
using namespace std;
int main() {
int value = 1234;
char str[5];
cout << itoa(value, str, 10) << endl;
cout << itoa(value, str, 16) << endl;
return 0;
}
字符串转数字
c++字符串使用的,这个针对的就是字符串string了。c里面也有,把s换成a,那个针对的是字符数组(c的字符串),如果要把c的用在c++里还要把string转换成char[],等会演示一下。
#include <string>
函数 | 函数作用 |
---|
stod() | 字符串转double | stof() | 字符串转float | stoi() | 字符串转int | stol() | 字符串转long | stold() | 字符串转double | stoll() | 字符串转long long | stoul() | 字符串转unsigned long | stoull() | 字符串转unsinged long long |
注意!没有unsigned double和unsigned float!!! 没有 (unsigned+浮点数) 这种类型!!!
语法规则: stoi/l(字符串,起始位置,待转换字符串中的进制(原字符串),n进制),将 n 进制的字符串转化为十进制 stof/d(字符串,起始位置) 总结就是可以带小数点的不存在原始字符串进制,不带的可以定义原始字符串的进制。
我们小小测试一下
#include <iostream>
#include <algorithm>
#include<string>
using namespace std;
int main() {
string str = "123";
cout << stoi(str, 0, 10) << endl;
str = "123.23";
cout << stoi(str, 0, 10) << endl;
cout << stof(str, 0) << endl;
cout << stod(str, 0) << endl;
str = "123--2";
cout << stoi(str, 0, 10) << endl;
str = "123--";
cout << stoi(str, 0, 10) << endl;
str = "123";
cout << stoi(str, 0, 8) << endl;
return 0;
}
再展示一下如何用c的atoi/f
#include <iostream>
#include <algorithm>
#include<cstdlib>
using namespace std;
int main() {
string str = "123.12";
cout << atoi(str.c_str()) << endl;
cout << atof(str.c_str()) << endl;
str = "--123.12";
cout << atoi(str.c_str()) << endl;
cout << atof(str.c_str()) << endl;
str = "123.12--";
cout << atoi(str.c_str()) << endl;
cout << atof(str.c_str()) << endl;
str = "123.--12";
cout << atoi(str.c_str()) << endl;
cout << atof(str.c_str()) << endl;
return 0;
}
|