南山网站公司,小程序推广计划怎么赚钱,如何修改asp网站,分销平台软件哪个好5.3 迭代器
前置式递增比后置式递增效率更高#xff0c;因为后者需要一个额外的临时对象#xff0c;因为他需要存储一个迭代器原本的位置并将其进行返还#xff0c;因此最好使用pos#xff0c;而不是pos#xff1b;
5.3.1 关联式容器的运用实例
修改map默认的递增的方式…5.3 迭代器
前置式递增比后置式递增效率更高因为后者需要一个额外的临时对象因为他需要存储一个迭代器原本的位置并将其进行返还因此最好使用pos而不是pos
5.3.1 关联式容器的运用实例
修改map默认的递增的方式将内部排序修改为 递减方式 std::mapint,int,std::greaterintmap{};greater是一个预先定义的仿函数关联式容器使用自己的默认规则进行元素位置的存放因此相较于序列式容器取消了push_back()和push_front()函数std::greater - C中文 - API参考文档
#include list
#include iostream
#include set
#include mapint main(){std::mapint,int,std::greaterintmap{};map.insert(std::make_pair(1,1));map.insert(std::make_pair(2,2));map.insert(std::make_pair(3,3));map.insert(std::make_pair(4,4));for (auto tempmap.begin();temp!map.end();temp) {std::cout temp-first temp-second std::endl;}
}
multimap包含在map头文件内部允许key和value是1对多的关系
#include list
#include iostream
#include set
#include mapint main(){std::multimapint,int,std::greaterintmap{};map.insert(std::make_pair(1,1));map.insert(std::make_pair(1,1));map.insert(std::make_pair(1,1));map.insert(std::make_pair(1,1));map.insert(std::make_pair(2,2));map.insert(std::make_pair(3,3));map.insert(std::make_pair(4,4));for (auto tempmap.begin();temp!map.end();temp) {std::cout temp-first temp-second std::endl;}
}
迭代器访问 元素的时候可以使用 迭代器-first 或者 (*迭代器).first 使用*解除引用再对元素进行访问类名 变量名将创建一个对象将其存储在栈上使用 变量名.成员 进行使用类名 变量名 new 类名(); 将创建一个对象将其存储在堆上使用 变量名-成员 进行使用map 键值/实值 所形成的群集中如果所有的键值是唯一的将其作为一个关联式数组;这里想表达的意思是我们可以像使用数组一样进行元素的访问数组通过数组下标访问对应的数值map可以通过指定key访问对应的value。通过map[key]访问对应的数值
5.3.2 迭代器分类
双向迭代器 Bidirectional iterator:双向行进采用递增进行前进运算使用递减进行后退运算list、set、multiset、map和undered_map 都使用这个迭代器随机存储迭代器Random access iterator在双向迭代器的基础上还具备了随机访问的特性因此可以对迭代器增加或者减少一个偏移量处理迭代器之间的距离或者使用和之类的relational相对关系的操作符来比较两个迭代器。vector、deque和string均采用此迭代器尽量使用 ! 这个的适配性更好但是如果pos位于了end的后面发生错误很难发现for(pos coll.begin();pos ! coll.end();pos){}operator !for(pos coll.begin();pos coll.end();pos){}//operator Random access iterator
5.4 算法
算法不是容器类别的成员函数而是搭配迭代器使用的全局函数采用的是泛型函数编程的思维数据和操作进行分离
5.4.2 处理多个区间
copy将第一区间的数据拷贝到目标区域第一区间的起点和第一区间的终点确定了第一区间的元素的数量因此第二区间只需要提供一个起点即可。但是copy函数使用的是覆写操作不是插入操作因此需要第二区间具备足够的内存空间如下例子所示会产生未定义的行为
#include list
#include iostream
#include set
#include map
#include string
#include vectorint main(){std::listintcoll1;std::vectorintcoll2;for (int i 1; i 9; i) {coll1.push_back(i);}std::copy(coll1.begin(),coll1.end(),coll2.begin());
}
对上述错误代码的修改1确认目标区域具备足够的内存2采用insert iteratorstd::listintcoll1;std::vectorintcoll2;for (int i 1; i 9; i) {coll1.push_back(i);}coll2.resize(coll1.size());std::copy(coll1.begin(),coll1.end(),coll2.begin());
5.5 迭代器配接器
Insert iterator 安插型迭代器Stream iterator 流迭代器reverse iterator 逆向迭代器
Insert iterator 安插型迭代器
采用安插方式而不是覆写的方式运作解决目标区域不足的问题 3种方式Back inserters 安插在容器的最尾端内部调用push_back() 采用追加的操作,只能适用于具备push_back()成员函数的容器中 适用于vector list deque std::copy(coll1.begin(),coll1.end(),std::back_inserter(coll2));Front inserters 安插在容器最前端内部调用的是push_front() 这种操作会逆转被插元素的次序比如插入1 再次插入 2输出的时候2会在1 的前面打印输出 这个适用于 list 和 deque std::copy(coll1.begin(),coll1.end(),std::insert_iterator(coll2));General inserters一般性安插器: 将元素插入到初始化时接受的第二个参数指向的前方。内部调用的是insert函数并按照新值和新的位置作为参数。适用于关联式容器流迭代器
stream iterator是一种用来读取stream流的迭代器。提供了必要的抽象性使得键盘的输入像一个群集使得程序员可以从中读取内容也可以把算法的输出重新导向某个文件或者屏幕代码没有跑通
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;
int main(){std::vectorstd::stringcoll{};copy(std::istream_iteratorstring(cin),istream_iteratorstring(),back_inserter(coll));sort(coll.begin(),coll.end());unique_copy(coll.begin(),coll.end(),ostream_iteratorstring(cout,\n));
} 5.5.3 reverse iterators 逆向迭代器
coll.rbegin()指向的是逆向遍历的起点也就是先前的end()-1 的位置
5.6.1 移除元素 remove移除元素是使用删除元素位置之后的元素对删除位置上的元素进行替代不会是将其所有的3全部删除但是群集末尾未被覆盖的元素原封不动但是从逻辑层面上讲他们已经不属于这个群集了
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;
int main(){std::listintcoll{};for(int i1;i6;i){coll.push_back(i);coll.push_front(i);}std::cout pre: ;copy(coll.begin(),coll.end(),ostream_iteratorint(cout, ));std::cout std::endl;std::remove(coll.begin(),coll.end(),3);std::cout post: ;copy(coll.begin(),coll.end(),ostream_iteratorint(cout, ));std::cout std::endl;
}
pre: 6 5 4 3 2 1 1 2 3 4 5 6post: 6 5 4 2 1 1 2 4 5 6 5 6 实际上 算法会产生一个新的终点需要更新新的终点的位置获得新的区间也就是缩减元素之后的容器的大小亦或是删除元素的个数改进如下 std::listint::iterator end std::remove(coll.begin(),coll.end(),3);这个end也就是经过删除之后逻辑上新的终点或者获取徐亚删除的元素的个数利用distance函数返回两个迭代器之间的距离
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;
int main(){std::listintcoll{};for(int i1;i6;i){coll.push_back(i);coll.push_front(i);}std::cout pre: ;copy(coll.begin(),coll.end(),ostream_iteratorint(cout, ));std::cout std::endl;std::listint::iterator end std::remove(coll.begin(),coll.end(),3);std::cout post: ;copy(coll.begin(),end,ostream_iteratorint(cout, ));std::cout std::endl;std::cout number of removed elements: std::distance(end,coll.end()) std::endl;coll.erase(end,coll.end());copy(coll.begin(),coll.end(),ostream_iteratorint(cout, ));std::cout std::endl;
}
5.6.2 更易型算法和关联式容器
更易型算法是指 移除、重排、修改元素的算法这些算法不适用于关联型算法因为这些操作会修改位置上的数值破坏排序因此关联式容器的所有迭代器都被声明为指向常量
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;
int main(){setintcoll{};for (int i 0; i 9; i) {coll.insert(i);}copy(coll.begin(),coll.end(),ostream_iteratorint(cout, ));std::cout std::endl;int num coll.erase(3);cout number os removed elements: num std::endl;copy(coll.begin(),coll.end(),ostream_iteratorint(cout, ));
}
5.6.3 算法 VS 成员函数
如果容器提供了功能相似但是性能更佳的成员函数优先使用成员函数成员函数 对其进行了优化相较于函数功能相似的算法成员函数 remove(coll.begin(),coll.end(),4)算法 coll.remove(4);
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;
int main(){listintcoll{};for (int i 1; i 6; i) {coll.push_front(i);coll.push_back(i);}coll.erase(remove(coll.begin(),coll.end(),3),coll.end());coll.remove(4);
}
5.8.1 以函数作为算法的参数
算法接收用户定义的辅助性函数 在算法的内部被调用for_each函数对coll的begin到end区间内的每一个元素都调用print函数进行输出
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;void print(int elem){std::cout elem ;
}
int main(){std::vectorintcoll{};for (int i 1; i 9; i) {coll.push_back(i);}std::for_each(coll.begin(),coll.end(),print);
}
算法以种态度来面对辅助函数1将其视为可有可无2视为必要利用他们指定搜寻的规则、排序的规则或者定义某种操作从而将某个容器内 的元素转换到另外一个容器
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;void print(int elem){std::cout elem ;
}int square(int value){return value*value;
}
int main(){std::setintcoll{};std::vectorintcoll2{};for (int i 1; i 9; i) {coll.insert(i);}std::transform(coll.begin(),coll.end(),std::back_inserter(coll2),square);std::for_each(coll2.begin(),coll2.end(),print);
} 5.8.2 判断式
潘端师就是返还结果是布尔数值的函数常用于指定排序准则和搜寻准则可能有一个或者两个操作数判断式 对于相同的输入返还相同的输出结果且程序执行不可以改变内部状态
一元判断式 二元判断式 5.9 仿函数
泛型编程强大威力和存粹抽象的一个例证。仿函数就是行为像函数比如定义一个对象他具备类似函数的一些特性就可以当做函数来使用比如使用小括号传递参数如果指望定义的对象也可以实现 使用小括号传递参数比如定义operator()
#include list
#include iostream
#include set
#include map
#include string
#include vectorusing namespace std;class X{
public:int operator()(int v1,int v2)const;
};
int X::operator()(int v1, int v2) const {std::cout v1 v2 std::endl;
}
int main(){X fo;fo(4,5);fo.operator()(4,5);
}
class PrintInt{
public:void operator()(int elem)const{std::cout elem std::endl;}
};
int main(){std::vectorintcoll{};for (int i 1; i 6; i) {coll.push_back(i);}std::for_each(coll.begin(),coll.end(),PrintInt());
} void add10(int elem){elem 10;
}
int main(){std::vectorintcoll{};for (int i 1; i 6; i) {coll.push_back(i);}for_each(coll.begin(),coll.end(),add10);std::for_each(coll.begin(),coll.end(),PrintInt());
}
如果需要数个不同的固定数值 而且他们在编译期 都已经确认可以使用template 使用模板传参需要在函数被调用之前将数值传递给函数 具体的代码如下面所示 for_each(coll.begin(),coll.end(),AddValue(10));这种方式使用AddValue(10)生成一个AddValue的组件并且赋予了初值为10构造函数就会把10保存在成员theValue中在for_each之内针对coll的每一个元素调用 () ,实际上就是对传入的那个AddValue对象 暂时调用 operator操作并以容器的元素作为参数
class AddValue{
private:int theValue;
public:AddValue(int v):theValue(v){};void operator()(int elem)const{elem theValue;}
};
class PrintInt{
public:void operator()(int elem)const{std::cout elem ;}
};
int main(){std::vectorintcoll{};for (int i 1; i 6; i) {coll.push_back(i);}for_each(coll.begin(),coll.end(),AddValue(10));std::for_each(coll.begin(),coll.end(),PrintInt());std::cout std::endl;for_each(coll.begin(),coll.end(),AddValue(*coll.begin()));std::for_each(coll.begin(),coll.end(),PrintInt());
} for_each(coll.begin(),coll.end(),AddValue(*coll.begin()5));这种方式传入的参数使用这个技术就可以实现先前所说的 一个函数两种状态的问题用两个不同的仿函数实现
class AddValue{
private:int theValue;
public:AddValue(int v):theValue(v){};void operator()(int elem)const{elem theValue;}
};
class PrintInt{
public:void operator()(int elem)const{std::cout elem ;}
};
int main(){std::vectorintcoll{};for (int i 1; i 6; i) {coll.push_back(i);}AddValue addx(4);for_each(coll.begin(),coll.end(),addx);std::for_each(coll.begin(),coll.end(),PrintInt());std::cout std::endl;AddValue addy(5);for_each(coll.begin(),coll.end(),addy);std::for_each(coll.begin(),coll.end(),PrintInt());
} 5.9.2 预先定义的仿函数
C标准库 包含了一些预定义的仿函数 涵盖了部分的基础运算比如排序默认的排序是从小到大也就是operator 的缺省排序准则就是 less默认的 std::setintcoll - setint,lessintcoll反向排列 setint,greaterintcollnegateint() 将传入的int数值设置为 负数transform()算法 将第一群集的所有元素处理之后转移到第二群集如果第二群集的起始地址是自身就相当于对第一群集的元素进行操作覆盖transform的另外一种形式按照某种特定的运算将两个群集内的元素处理之后将其结果写入到第三群集如下所示设定 第一群集、第二群集 将两个群集的元素进行计算将结果写回到第三群集class PrintInt{
public:void operator()(int elem)const{std::cout elem ;}
};
int main(){std::setint,std::greaterintcoll1;std::dequeintcoll2;for (int i 1; i 9; i) {coll1.insert(i);}std::for_each(coll1.begin(),coll1.end(),PrintInt());transform(coll1.begin(),coll1.end(), //sourceback_inserter(coll2), //destinationbind2nd(multipliesint(),10)); //operationstd::cout std::endl;std::for_each(coll2.begin(),coll2.end(),PrintInt());//replace value equals to 70 with 42replace_if(coll2.begin(),coll2.end(), //rangebind2nd(equal_toint(),70), //replace criterion42); //new valuestd::cout std::endl;std::for_each(coll2.begin(),coll2.end(),PrintInt());//remove all elements with values less than 50coll2.erase(remove_if(coll2.begin(),coll2.end(), //rangebind2nd(lessint(),50)), //remove criterioncoll2.end());std::cout std::endl;std::for_each(coll2.begin(),coll2.end(),PrintInt());transform(coll1.begin(),coll1.end(), //source back_inserter(coll2), //destination bind2nd(multipliesint(),10)); //operationbind2nd 就是 进行multipliesint()运算的时候将源群集的元素作为第一参数将10 作为第二参数所有的仿函数通常都声明为inline一方面使用类似函数的表示法或者抽象性一方面又可以获得出色的效能还有一些仿函数可以调用群集内的每个元素的成员函数 智能指针是一种对象有着类似指针的接口但是内部实现了一些额外的检查和处理工作