django做网站怎样/国内最大的搜索引擎
顺序型容器使用中一些注意的地方
vector的push_back与emplace_back
- 相对于
push_back
,emplace_back
在添加元素时不会进行额外的复制或者拷贝工作 - 参考链接:http://en.cppreference.com/w/cpp/container/vector/emplace_back
- 上面的特点是
左值引用(&)
与右值引用(&&)
造成的。C++11中引入的右值引用,主要有2个优点(https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/):
- 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
- 能够更简洁明确地定义泛型函数。
代码
class A { public:A(int val, int type) : val_(val), type_(type) {cout << "I am being constructed." << endl;}A(A&& other) : val_(other.val_), type_(other.type_){cout << "I am being moved.\n";} private:int val_;int type_; };void test() {cout << "push_back :" << endl;vector<A> vec1;vec1.push_back(A(1, 2));cout << "emplace_back :" << endl;vector<A> vec2;vec2.emplace_back(1, 2); }
forward_list删除符合条件的节点
forward_list
(单向链表)中可以得到一个节点及其前驱节点,erase_after
用于删除这个节点之后的节点,因此我们需要记录当前节点的前驱节点- 删除特定值时,其前驱节点的信息也会发生改变(iter指向下一个节点)
代码:删除列表中所有的奇数
void test() {forward_list<int> lst;for (int i = 0; i < 10;i++)lst.push_front(i);auto curr = lst.begin();auto prev = lst.before_begin();while (curr != lst.end()){if (*curr % 2 == 1){curr = lst.erase_after( prev );}else{prev = curr;++curr;}}for (auto it = lst.begin(); it != lst.end(); it++)cout << *it << endl; }
迭代器
- 注意:在使用迭代器的时候,尽量不要对容器进行操作,除非十分清楚迭代器的动作或者操作,否则容器操作可能会使得迭代器变得无效。
泛型算法
概述
- 泛型算法本身不会执行容器的操作,它们只会运行于迭代器之上,执行迭代器的操作。因此:泛型算法永远不会改变底层容器的大小。但是一些特殊的迭代器(inserter)会改变底层容器。
一些常用的泛型算法
accumulate
accumulate(begin, end, val)
:第三个参数是和的初值,他的类型决定了函数中使用哪个加法运算符以及返回值的类型(因此必须要求第三个参数的类型实现了加法运算符操作)。code
void test() {vector<int> nums = {1,2,3,4};cout << accumulate( nums.begin(), nums.end(), 0 ) << endl;vector<string> strs = {"123", "456", "789"};//cout << accumulate(strs.begin(), strs.end(), "") << endl; // 报错,因为const char* 没有提供加法操作cout << accumulate(strs.begin(), strs.end(), string("")) << endl; }
fill
- 将给定范围的迭代器内的内容填充为给定数据
code
void test() {vector<int> nums = {1,2,3,4};fill(nums.begin(), nums.end(), 0);for (auto &n : nums)cout << n << endl;fill_n( nums.begin(), 2, 4 ); // 要保证填充的个数小于容器的sizefor (auto &n : nums)cout << n << endl; }
replace
,replace_copy
- replace会修改原始数组,而replace_copy不会修改原始数组,会将调整后的数组保存在另外一个地方
code
void test() {vector<int> nums = {1,2,3,4, 1,2};replace( nums.begin(), nums.end(), 1, 23 ); // 替换cout << "nums : ";for (auto &num : nums)cout << num << " ";cout << endl;vector<int> cpy;replace_copy( nums.cbegin(), nums.cend(), back_inserter(cpy), 23, 44 ); // 不改变原始数组,而是添加到新的列表中去cout << "nums : ";for (auto &num : nums)cout << num << " ";cout << endl;cout << "cpy : ";for (auto &num : cpy)cout << num << " ";cout << endl; }
unique
- 功能:可以与
erase
结合,去除容器中的连续重复元素 code
// 输出一个迭代器范围内的数据,最后以换行结束 template<typename iter> void printVec(iter &start, iter &end, ostream &os = cout, string &split = string(" ")) {while (start != end){os << *start << split;++start;}os << endl;} void test() {vector<int> nums = {1,1,2,3,4,4, 1,2};//将唯一的元素放在前面,在这之后的元素都需要删除,这个只会删除相邻的重复元素,即不检查不相邻的元素的值是否相等auto it = unique(nums.begin(), nums.end());nums.erase( it, nums.end() );printVec( nums.begin(), nums.end() ); }
lambda表达式
- 一个lambda表达式表示一个可以调用的代码单元,可以将其理解为一个
未命名的内联函数
,对于有些较为短小的代码段可以使用这种方法 - 形式:
[](){}
,[]
中主要是写lambda表达式内部需要使用的变量()
,被称为捕获,如果是采用引用的方式,则是引用捕获;主要是传参;{}
是函数功能实现部分。 code
template<typename iter> void printVec(iter &start, iter &end, ostream &os = cout, string &split = string(" ")) {while (start != end){os << *start << split;++start;}os << endl;} void test() {vector<int> nums = {1,1,2,3,4,4, 1,2};auto f = [](){return 42; };cout << f() << endl;std::sort(nums.begin(), nums.end(), [](const int& a, const int& b){return a > b; });printVec( nums.begin(), nums.end() );int base = 3;auto it = find_if(nums.begin(), nums.end(), [base](const int& a){ return a < base; }); // 返回第一个满足条件的元素所在的迭代器位置printVec( it, nums.end() ); }
for_each
对于容器中的每个元素,都进行特定的操作
code
void test() {vector<int> nums = {1,1,2,3,4,4, 1,2};for_each(nums.begin(), nums.end(), [](const int& a){cout << a*5 << " "; });cout << endl; }
transform
- 按照某种方法对元素进行变换,需要给定转换后存储的位置
code
void test() {vector<int> nums = {1,1,2,3,4,4, -5,-6};vector<int> result;transform(nums.begin(), nums.end(), back_inserter(result), [](int a) {return a < 0 ? -a : a; });transform(nums.begin(), nums.end(), nums.begin(), [](int a) -> int {return a < 0 ? -a : a; }); // ->int是指定返回值类型for_each(result.begin(), result.end(), [](const int& a){cout << a << " "; });cout << endl;for_each(nums.begin(), nums.end(), [](const int& a){cout << a << " "; });cout << endl; }
参数绑定bind
- bind:用占位符绑定数据,可以实现参数位置替换或者参数简化的功能
code
void test() {vector<int> nums = {1,1,2,3,4,4, -5,-6};vector<int> result;std::sort( nums.begin(), nums.end(), less<int>() );std::for_each(nums.begin(), nums.end(), [](const int& a){std::cout << a << " "; });std::cout << endl;// 使用bind函数与占位符,将less中第二个参数与第一个参数位置对调,实现从大到小排序的效果。// 也可以直接绑定第几个参数为定值等,实现少于原始函数参数个数的运算std::sort(nums.begin(), nums.end(), bind(less<int>(), std::placeholders::_2, placeholders::_1));std::for_each(nums.begin(), nums.end(), [](const int& a){std::cout << a << " "; });std::cout << endl;// 固定第二个参数为3,表示找到一个小于3的数,并记录当前位置auto it = find_if(nums.begin(), nums.end(), bind(less<int>(), std::placeholders::_1, 3) );std::for_each(it, nums.end(), [](const int& a){std::cout << a << " "; });std::cout << endl; }
- 注意事项:如果出现
IntelliSense: "for_each" is ambiguous
的问题,可以在函数前加上命名空间std::
。
back_inserter
,front_inserter
,inserter
back_inserter
是创建一个使用push_back
的迭代器front_inserter
是创建一个使用push_front
的迭代器- ‘inserter’:接受2个参数,分别是容器与迭代器的一个位置iter,所有的元素都会被插入到这个iter之前(依次)
输入输出流迭代器
- 输入输出流迭代器是可以从流中读取数据或者将数据写入流中
代码
void test() {vector<int> nums;vector<int> result;// 输入流迭代器istream_iterator<int> in_iter(cin);istream_iterator<int> eof; // istream尾部迭代器while (in_iter != eof) // ctrl+z结束输入{nums.push_back( *in_iter++ );}// 输出流迭代器ostream_iterator<int> os_iter(cout, " ");for (auto &e : nums)*os_iter++ = e;cout << endl;copy( nums.begin(), nums.end(), os_iter );cout << endl; }
一些泛型算法的特殊情况(list与forward)
list
与forward
都是链表类型,无法做到随机访问迭代容器,因此在对这两种容器进行操作时(sort,remove,reverse,unique
等),优先使用其成员函数的算法,而非泛型算法