• C++ Primer学习笔记


    10.2 初识泛型算法

    10.2.1 只读算法

    1. find
      头文件algorithm
      find 在指定迭代器范围种,查找目标元素。返回第一个出现目标元素的迭代器。
      支持容器类型,也支持内置数组。要求元素支持“==”运算符。
    // 1. 在list中查找指定元素
    list<string> lst;
    // 向lst插入元素
    // lst.push_fron("...");
    
    // 利用find在lst中查找指定元素
    string val = "a value";
    find(lst.cbegin(), lst.end(), val);
    
    // 2. 在内置数组中查找指定元素
    int ia[] = {1,2,3,4,5,6,7};
    int val = 6;
    int* res = find(begin(ia), end(ia), val);
    
    1. accumulate
      头文件numeric
      accumulate 求累加和。返回求和结果。
      除了指定迭代器范围,还需要指定初值(第三个参数)。运算时,元素会转换为初值类型。
      要求元素支持“+”运算符。
    int sum = accumulate(vec.cbegin(), vec.cend(), 0); // 要求vec元素类型也是int,与第三个参数0类型一致
    // 字符串求和,accumulate会将每个字符串连接起来
    string sum = accumulate(v.cbegin(), v.cend(), string("");
    
    // 错误:因为const char*上没有定义 + 运算
    string sum = accumulate(v.cbegin(), v.cend(), ""); // 这里""会被当作const char*类型空串
    
    1. equal
      头文件algorithm
      比较2个容器保存的元素序列是否相同,只有所有指定范围元素都相当时,才返回true。返回比较结果bool类型结果。
      前2个参数是第一个序列的迭代器范围,第3个参数是第二个序列的首元素对应迭代器。
      要求:
      1)元素类型相同,能支持 == 运算符;
      2)第一个序列元素数目 >= 1第一个序列元素数目;
    // roster2元素数目 >= roster1元素数目
    equal(roster1.cbegin(0, roster1.cend(), roster2.cbegin());
    

    10.2.2 写容器的算法

    1. fill
      头文件algorithm
      在指定迭代器范围返回填充指定元素值。
      fill有2个版本:
      1)fill() 3个参数分别是起始迭代器(cbeging()),结束迭代器(cend()),初值
      2)fill_n() 3个参数分别是起始迭代器,元素个数,初值;
      第1)种是安全方式;
      第2)种方式,如果要填充元素个数 > 容器范围,会导致未定义行为
    vector<int> vec(10); // 构造10个元素的vector
    fill(vec.begin(), vec.end(), 1); // 将vec所有元素填充为1
    
    fill_n(vec.begin(), vec.size(), 0); // 将vec 10个元素都填充为0
    
    fill_n(vec.begin(), 11, 0); // 11 > vec.size(),将导致未定义行为
    
    1. back_inserter
      头文件iterator
      插入迭代器,一种像容器中添加元素的迭代器,值被赋予迭代器指向的元素。
    // 通过back_inserter插入元素 <=> push_back
    vector<int> vec; // 空向量
    auto it = back_inserter(vec); // it指向vec尾部
    *it = 42; // vec现在有一个元素,值为42
    
    // back_inserter结合fill_n,在指定位置 插入指定个数元素
    fill_n(back_inserter(vec), 10, 0); // 在vec末尾添加10个元素
    
    1. copy
      头文件algorithm
      拷贝算法,从一个指定迭代器范围的序列元素,拷贝到另外一个序列。copy返回的是目的位置迭代器(递增后)的值,而非起始拷贝的位置值。
    int a1[] = {0,1,2,3,4,5,6};
    int a2[sizeof(a1) / sizeof(a1[0])];
    
    // ret指向拷贝元素到a2后的尾元素之后位置
    auto ret = copy(begin(a1), end(a1), a2); // 将a1内容拷贝到a2
    
    1. replace
      头文件algorithm
      replace用指定值,替换指定迭代器范围内的值。无返回值。会修改原容器的值。
      replace_copy 先拷贝容器内容,用指定值,替换指定迭代器范围内的值。无返回值。不会修改原容器的值。
    replace(ilst.begin(), ilst.end(), 0, 42); // 替换ilst中值为0的元素为42。 因为要修改原容器的值,只能用begin, end版本,不能用cbegin, cend版本
    
    replace_copy(ilst.cbegin(), ilst.cend(), back_inserter(ivec), 0, 42); // il并未改变,ivec包含一份拷贝,原来值ilst中值为0的元素值ivec都变为42了
    

    10.2.3 重排容器元素的算法

    1. sort
      对指定迭代器范围元素进行排序,默认是递增顺序。
      stable_sort() 稳定排序,除了对元素序列进行排序,还能保持两个“相等”元素的原有顺序。
    vector<int> ivec = {8,2,78,11,5};
    sort(ivec.begin(), ivec.end()); // 排序
    
    // 改变排列顺序,由递增改为递减
    sort(ivec.begin(), ivec.end(), greater<int>()); // 从大到小排列
    
    sort(ivec.begin(), ivec.end(), less<int>());    // 从小到大排列
    
    // 指定比较函数 - 谓词
    // 按单词长短排序words
    bool isShorter(const string &s1, const string &s2) {
      return s1.size() < s2.size();
    }
    
    sort(words.begin(), words.end(), isShorter);
    
    
    1. unique
      unique算法排序序列,重复元素“删除”(实际上是放到容器末尾)。返回的是一个指向不重复值范围的下一个位置的迭代器。如果有重复元素,unique返回值相当于移动到末尾的第一个重复值元素的位置。
      注意:unique并不会排序。
    // 排序words,并删除重复元素
    void elimDups(vector<string>& words) {
      sort(words.begin(), words.end());
      auto end_unique = unique(words.begin(), words.end()); // end_unique是指向不重复区域之后一个位置的迭代器
      words.erase(end_unique, words.end()); // [end_unique, words.end() ) 都是重复元素
    }
    

    10.3 定制操作

    10.3.1 向算法传递参数

    1. 谓词
      sort接收的第3个参数,可以传入函数作为参数,函数返回值作为两个迭代器指向的元素的比较的结果。如上面的例子sort(words.begin(), words.end(), isShorter());
      谓词 predicate指一个可调用的表达式,其返回结果是一个能用作条件的值。
      标准库的谓词分为两类:一元谓词 unary predicate,只接收单一参数;二元谓词 binary predicate,意味着它们(表达式)有2个参数。
      sort的第3个参数,作为谓词,起到比较2个参数作用,也是二元谓词。

    10.3.2 lambda表达式

    可以向算法传递可调用对象(callable object)(可以理解成函数,或者函数指针)。
    一个lambda表达式表示一个可调用代码单元,可以理解成一个未命名的内联函数。
    一个lambda表达式类似于函数,具有一个返回类型,一个参数列表,一个函数体。lambda表达式形式:

    [capture list](parameter list) -> return type { function body}
    

    capture list 捕获列表,是一个lambda所在函数中定义的局部变量的列表,通常为空。
    parameter list 参数列表,return type 函数返回类型, function body 函数体,跟普通函数类似。不过,lambda必须使用尾置返回。
    参数列表、返回类型都可以忽略,但是必须包含捕获列表和函数体。

    如果只有一个return,没有包含具体返回值,编译器无法推断出具体返回类型, 则返回类型为void。

    auto f = []{ return 42; }
    cout << f() << endl; // 打印42
    

    向lambda传递参数

    • lambda不能有默认参数;
    • lambda调用的实参数目永远与形参数目相等;
    // 示例:将前面的isShorter函数转化成lambda表达式
    bool isShorter(const string& s1, const string& s2) {
      return s1.size() < s2.size();
    }
    
    // lambda表达式
    [](const string& s1, const string& s2) {
      return s1.size() < s2.size();
    }
    

    使用捕获列表
    lambda在函数中,可以使用其局部变量,不过需要先捕获(包含中捕获列表中)。
    如find_if第3个参数,可以用谓词来过滤出符合条件的元素

    [sz](const string& a) { // 捕获局部变量sz
      return a.size() >= sz;
    }
    
    // 错误使用示范
    [](const string& a) {
      return a.size() >= sz; // 错误:未捕获sz
    }
    
    // 调用find_if,返回一个迭代器,指向第一个长度不小于sz的元素
    // find_if 第三参数返回非0值,才能通过find_if的过滤
    auto wc = find_if(words.begin(), words.end(), [sz](const string& a) {
      return a.size() >= sz;
    }
    
    // 调用for_each算法,对指定迭代器范围每个元素,都调用lambda表达式
    for_each(wc, words.end(), [](const string& s) {
      cout << s << " ";
      cout << endl;
    })
    

    10.3.3 lambda 捕获和返回

    值捕获
    变量的捕获方式也分为值捕获和引用捕获。被捕获的变量的值,是在lambda创建时拷贝,而不是调用时。
    值捕获的变量值,值lambda函数结束后就不存在了。

    引用捕获
    需要确保引用捕获的对象值lambda执行的时候存在。

    // 示例:值捕获
    void fcn1() {
      size_t v1 = 42;
      auto f = [v1]{ return v1; }
      v1 = 0;
      auto j = f(); // j == 42,因为f lambda表达式捕获v1时,创建了临时拷贝
    }
    
    // 示例:引用捕获
    void fcn2() {
      size_t v1 = 42;
      auto f = [&v1]{ return v1; }
      v1 = 0;
      auto j = f(); // j == 0,因为f lambda表达式捕获了v1的引用
    }
    

    引用捕获有时是必要的。
    例如,希望biggies函数接受一个ostream的引用,用来输出数据,并接受一个字符作为分隔符。

    void biggies(vector<string> &words, vector<string>::size_type sz, ostream &os = cout, char c = ' ') {
      for_each(words.cbegin(), words.cend(), 
        [&os, c](const string& s){
          os << s << c;
        });
    }
    

    隐式捕获
    指示编译器推断捕获列表,可以值捕获列表中写一个&或=:
    & 告诉编译器采用捕获引用方式;
    = 采用值捕获方式;

    // sz为隐式捕获,值捕获方式,重写传递给find_if的lambda
    wc = find_if(words.begin(), words.end(), [=](const string& s){
      return s.size() >= sz;
    });
    
    // 混合隐式捕获和显式捕获
    void biggies(vector<string>& words, ostream& os = cout, char c = ' ') {
      for_each(words.begin(), words.end(), 
                [&, c](const string& s){ os << s << c; }); // os隐式捕获,c显示捕获
      
      for_each(words.begin(), words.end(), 
                [=, &os](const string& s){ os << s << c; }); // c隐式捕获,os显式捕获
    }
    

    可变lambda
    值拷贝的变量,默认情况下,lambda不会改变其值。如果改变被捕获变量的值,必须值参数列表首加上关键字mutable。
    引用捕获的变量,如果不是const类型,就可以值lambda中修改。

    // 示例:lambda修改值捕获变量,需要加mutable关键字
    void fcn3() {
      size_t v1 = 42; 
      auto f = [v1]() mutable { return ++v1; };
      v1 = 0;
      auto j = f(); // j为43
    }
    
    // 示例:lambda修改引用捕获变量,要求非const类型
    void fcn4() {
      size_t v1 = 42;
      auto f = [&v1] { return ++v1;};
      v1 = 0;
      auto j = f(); // j为1
    }
    

    指定lambda返回类型
    默认情况下,lambda如果包含除return语句以外的语句,编译器会假定此lambda返回void。
    如果需要包含return以外语句,需要使用尾置返回类型。

    // 下面的示例是让
    
    // 错误示范:lambda使用return以外语句
    transform(vi.begin(), vi.end(), vi.begin(), 
              [](int i){ 
                          if (i < 0) return -i ;
                          else return i; 
    });
    
    // 正确示范1:不包含return以外语句
    transform(vi.begin(), vi.end(), vi.begin(), [](int i){ return i < 0 ? -i : i; });
    
    // 正确示范2:使用尾置返回类型,包含return以外语句
    transform(vi.begin(), vi.end(), vi.begin(), 
              [](int i) -> int {                  // 注意这里的  -> int ,指名lambda返回int
                          if (i < 0) return -i ;
                          else return i; 
    });
    
    

    10.3.4 参数绑定

    lambda表达式对于在一两个地方使用简单操作很合适,但是需要在很多地方重复使用,还是(有名)函数更合适。但是对于lambda捕获的局部变量,用函数替换lambda的时候,如何进行呢?
    例如,下面的sz,是在上面的find_if的第三个参数接受的lambda表达式中捕获的局部变量。如果改用函数,如何传递给函数check_size?

    bool check_size(const string& s, string::size_type sz) {
      return s.size() >= sz;
    }
    

    标准库bind函数
    头文件functional
    可以看做一个通用的函数适配器,接收一个可调用对象(函数),生成一个新的可调用对象来适应原对象的参数列表。
    调用bind一般形式:

    auto newCallable = bind(callable, arg_list);
    

    newCallable 新生成的可调用对象
    callable 给定的可调用对象
    arg_list 参数列表。arg_list中的参数可能包含形如_n的名字,其中n是一个整数,称为“占位符” ,表示newCallable的参数,数字对应传递给newCallable形参的位置。
    _1表示newCallable的第一个参数,_2表示第二个参数...

    绑定check_size的sz参数

    #include <functional>
    #include <iostream>
    #include <string>
    #include <vector>
    
    // 为了使用_1, _2这些,需要声明使用placeholders命名空间
    using namepsace std::placeholders; // 声明使用placeholders命名空间
    // 也可以声明只使用_1
    using std::placeholders::_1;
    
    bool check_size(const string& s, string::size_type sz) {
    	return s.size() >= sz;
    }
    
    void fcn5() {
      vector<string> words = {"the", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle"};
      string::size_type sz = 6;
    
      auto check6 = bind(check_size, _1, sz); // check6 是一个可调用对象
      
      string s = "hello";
      bool b1 = check6(s); // check6(s)会调用check_size(s,sz)
    
      auto wc = find_if(words.begin(), words.end(), [sz](const string& a){ return a.size() >= sz; });
      // 等价于下面的语句
      wc = find_if(words.begin(), words.end(), bind(check_size, _1, sz));
    }
    

    bind参数

    auto g = bind(f, a, b, _2, c, _1);
    
    g(x, y);
    // 调用g(x, y)将映射为调用下面的
    f(a, b, y, c, x);
    

    用bind参数重排序*

    sort(words.begin(), words.end(), isShorter); // 按长度从小到大排序单词数组words
    sort(words.begin(), words.end(), bind(isShorter, _2, _1)); // 通过调整placeholders顺序,交互绑定的参数顺序,从而改变调用isShorter比较两个元素时返回的结果,达到按长度从大到小排序单词数组
    

    绑定引用参数
    使用ref(),通过bind(f, a, b, _1)传递a、b到可调用对象,都是拷贝,如果想传递引用,需要使用ref(a), ref(b)。如果要使用const 引用,需要用cref(a)。
    ref函数会返回给定对象的引用。

    char c = ' ';
    
    // 使用lambda的等价语句,打印每个words元素
    for_each(words.begin(), words.end(), [&os, c](const string& s) {os << s << c; });
    
    // 等价的bind语句
    for_each(words.begin(), words.end(), bind(print, ref(os), _1, c); // 这里必须使用ref(os),如果直接用os,传递给函数会发生拷贝,而我们知道ostream对象是无法拷贝的,会发生错误
    
    ostream &print(ostream &os, const string& s, char c) {
      return os << s << c;
    }
    

    10.4 再探迭代器

    头文件iterator

    • 插入迭代器 insert iterator : 迭代器被绑定到一个容器上,可用来向容器插入数据;
    • 流迭代器 stream iterator: 迭代器被绑定到输入或输出流上,可用来遍历所关联的IO流;
    • 反向迭代器 reverse iterator: 迭代器向后而不是向前移动。除了forward_list之外的标准容器库都有反向迭代器;
    • 移动迭代器 move iterator:迭代器不是拷贝其中的元素,而是移动它们。

    10.4.1 插入迭代器

    插入迭代器有3种,根据元素插入位置区分:

    • back_inserter 创建一个使用push_back的迭代器。只有容器支持push_back操作时,才能使用back_inserter。
    • front_inserter 创建一个使用push_front的迭代器。同样需要容器支持push_front。
    • inserter 创建一个使用insert的迭代器。接受2个参数,第1个是容器,第2个是迭代器。

    我们知道,insert(pos, args)会将元素插入到pos位置之前,所以inserter(c, iter)也会将元素插入到iter之前,并返回新插入元素位置(iter的前一个位置)。

    // 如果it是通过inserter获取的迭代器
    // 那么下面2条语句等价
    *it = val;
    // <=>
    it = c.insert(it, val); // it指向新加入的元素
    ++it; // 递增it,指向原来的元素
    
    // front_inserter, inserter使用示例
    list<int> lst = {1, 2, 3, 4};
    list<int> lst2, lst3;
    
    copy(lst.cbegin(), lst.cend(), front_inserter(lst2)); // lst2 == 4,3,2,1
    copy(lst.cbegin(), lst.cend(), inserter(lst3, lst3.begin())); // lst3 == 1,2,3,4
    

    10.4.2 iostream迭代器

    iostream类型容器,而是输入输出流,标准库定义了可以用于这些IO类型对象的迭代器。
    istream_iterator 读取输入流,ostream_iterator向一个输出流写数据。通过流迭代器,可以用泛型算法从流对象读取数据以及向其写入数据。

    istream_iterator操作
    输入流迭代器istream_iterator使用 >> (输入运算符)读取流,要读取的的类型必须定义了输入运算符。
    默认初始化迭代器,可以当作尾后值使用的迭代器。

    // 示例1: 通过istream_iterator从cin读入数据int数据, 直到输入结束或者遇到导致输入结束的非数字字符, 将读取到的数据存入vector并打印
    istream_iterator<int> int_it(cin);
    istream_iterator<int> int_eof;
    vector<int> vec;
    
    while(int_it != int_eof) {
    	vec.push_back(*int_it++);
    }
    
    for (const auto &d : vec) {
    	cout << d << " ";
    }
    cout << endl;
    
    // 示例2: 通过istream_iterator从ifstream读入string数据, 并打印
    ifstream in("records.txt");
    istream_iterator<string> str_it(in); // 从"afile"读取字符串
    istream_iterator<string> str_eof;
    while (str_it != str_eof) {
    	cout << *str_it++ << endl;
    }
    

    ostream_iterator操作
    ostream_iterator跟istream_iterator类似,必须指定要写到输出流的元素类型。ostream_iterator out对象,*out, ++out, out++等价(都不对out做任何事情),都返回out。

    vector<int> vec = {1,3,5,7,9,11};
    
    // 下面2个示例效果一样,都是将数组vec通过流迭代器打印出来
    // 示例1:通过for循环,将数组内容写到流迭代器指向位置(标准输出流cout)
    ostream_iterator<int> out_iter(cout, " ");
    for (auto e : vec) {
      *out_iter++ = e; // <=> out_iter = e; 
    }
    cout << endl;
    
    // 示例2:通过copy和vec迭代器范围,将数组内容写到流迭代器指向位置(标准输出流cout)
    copy(vec.begin(), vec.end(), out_iter);
    cout << endl;
    

    10.4.3 反向迭代器

    正向迭代器
    vec.cbegin() ... vec.cend()
    vec.crend() ... vec.crbegin()
    反向迭代器

    反向迭代器是在容器中从尾元素向首元素反向移动的迭代器。

    // 示例1:逆序打印vector
    vector<int> vec = {1,2,3,4,5,6,7,8};
    // 从容器末尾向前开始打印,打印结果:8 7 6 5 4 3 2 1
    for (auto r_iter : vec.crbegin(); r_iter != vec.cend(); ++r_iter) {
      cout << *r_iter << "" ;
    }
    cout << endl;
    
    // 示例2:逆序排序
    sort(vec.begin(), vec.end()); // 递增排序
    sort(vec.rbegin(), vec.rend()); // 递减排序
    

    反向迭代器需要递减运算符
    除了forward_list和流迭代器不支持递减运算,其他标准容器都支持递减运输,也就支持反向迭代器。此时,如果需要将反向迭代器转化成普通迭代器,需要使用.base()函数进行转换。

    反向迭代器和其他迭代器之间的关系
    直接使用反向迭代器,会导致每个元素之间的顺序也是反向的。

    注意:在普通迭代器和反向迭代器的转换过程中,要非常小心,仔细观察位置是否与预期一致。

    string line = "hello, this is martin zhang, I'm 18 years old, who are you?";
    // 打印','前第一个单词
    auto comma = find(line.cbegin(), line.cend(), ',');
    cout << string(line.cbegin(), comma) << endl; // 打印hello
    
    // 打印','后最后一个单词,但是单词本身也会反序打印
    auto rcomma = find(line.crbegin(), line.crend(), ',');
    cout << string(line.crbegin(), rcomma) << endl; // 打印?uoy era ohw 
    
    // 打印','后最后一个单词,单词本身正序打印
    // 使用.base()将反向迭代器转化成普通迭代器,注意.base()返回的是当前迭代器位置的下一个位置,也就是说,当前位置是',',下一个位置是' '(空格)
    cout << string(rcomma.base(), line.cend()) << endl; // 打印 who are you?
    

    10.5 泛型算法结构

    10.5.1 5类迭代器

    • 输入迭代器 input iterator
      只读不写,单遍扫描,只能递增。还支持相等性 判定运算符(== , !=),支持解引用运算符()(只出现在赋值语句右侧)和箭头运算符(->,等价于(it).member,解引用迭代器)。
      只能用于顺序访问,典型应用:find, accumulate算法,istream_iterator输入流迭代器

    • 输出迭代器 output iterator
      输入迭代器的补集,只写不读,单向扫描,只能递增。支持解引用(*)(只出现在赋值语句左侧。
      典型应用:copy算法,ostream_iterator输出流迭代器

    • 前向迭代器 forward iterator
      可读写,多遍扫描,只能递增,支持所有输入、输出迭代器的操作。
      典型应用:replace算法,forward_list的迭代器

    • 双向迭代器 bidirectional iterator
      可正反读写序列中元素,多遍扫描,可递增递减,支持所有前向迭代器。
      典型应用:除forward_list外,其他标准库都提供符合要求双向迭代器

    • 随机访问迭代器 random-access iterator
      可读写,多遍扫描,可递增递减,支持全部迭代器操作。支持常量时间访问任意元素。支持<, <=, >, >=, +,+=,-,-=,下标运算等。支持两个迭代器-,得到距离。
      典型应用:sort算法,array, deque, string, vector迭代器

    10.5.2 算法形参模式

    大多数算法具有下面4种形式之一:

    alg(beg, end, other args);
    alg(beg, end, dest, other args);
    alg(beg, end, beg2, other args);
    alg(beg, end, beg2, end2, other args);
    
    alg: 算法名;
    beg, end: 算法所操作的输入范围;
    dest, beg2, end2, 都是迭代器参数,指定目的第二个范围的角色;
    args: 额外的非迭代器参数
    

    10.5.3 算法命名规范

    // 重新整理给定序列,将相邻重复元素删除
    unique(begin, end); // 使用 == 比较元素
    unique(begin, end, comp); // 使用comp比较元素,当comp为真时,删除第二个元素
    
    // _if版本算法,接受一个谓词代替元素值
    find(beg, end, val); // 查找输入范围中val第一次
    find_if(beg, end, pred); // 查找输入范围中,第一个令谓词pred为真的元素
    
    // 反转序列
    reverse(beg, end); // 反转输入范围中的序列元素
    reverse_copy(beg, end, dest); // 反转序列,拷贝到dest
    
    // 删除元素
    remove_if(v1.begin(), v1.end(), [](int i){ return i % 2; }); // 从v1中移除奇数值元素
    remove_copy_if(v1.begin(), v1,end(), back_inserter(v2), [](int i){ return i % 2; }); // 将偶数元素拷贝到v2
    

    10.6 特定容器算法

    list, forward_list特定成员函数算法

    // 都返回void
    
    list<XXX> lst;
    forward_list<XXX> flst; 
    
    // 合并链表
    lst.merge(lst2); // lst2合并到lst。要求lst和lst2有序,元素从lst2删除(lst2合并后为空)。使用运算符 <
    lst.merge(lst2, comp); // ... 使用谓词comp
    
    // 删除元素
    lst.remove(val); // 调用erase删除与给定值相等(==)的元素
    lst.remove_if(pred); // ...满足谓词pred的元素
    
    lst.reverse(); // 反转lst元素顺序
    lst.sort(); // 链表排序,使用<
    lst.sort(comp); // ..,使用comp进行比较
    lst.unique(); // 调用erase删除连续的重复元素(==)
    lst.unique(pred); // (满足pred)
    
    // splice
    lst.splice(p, lst2);  // p是一个指向lst中元素迭代器,splice函数将lst2所有元素移动到lst中p之前。元素从lst2删除,lst2类型必须与lst相同,且不能是同一个链表
    flst.splice_after(p, lst2); // ...lst2所有元素移动到lst中p之后...
    
    lst.splice(p, lst2, p2); // p2是一个指向lst2中位置的有效迭代器。将p2指向的元素移动到lst中 (包含p2及以后的元素)。lst2可以与lst相同链表
    flst.splice_after(p, lst2, p2); // ...将p2之后的元素移动到lst中(不包含p2)。lst2可以与flst相同链表
    
    lst.splice(p, lst2, b, e); // b和e必须表示lst2中的合法范围。将给定范围元素从lst2移动到lst。lst2跟lst可以相同链表,但p不能指向给定范围中的元素
    flst.splic_after(p, lst2,) // ...将给定范围元素从lst2移动到flst。llst2跟flst可以相同链表...
    
  • 相关阅读:
    POJ3041Asteroids(最小点覆盖+有点小抽象)
    POJ 2240Arbitrage(Floyd)
    POJ1860Currency Exchange(Bellman + 正权回路)
    POJ3259Wormholes(判断是否存在负回路)
    TCL V7300A-3D升级教程
    “一生所爱“一首一听就很想落泪的歌曲
    一生所爱 怀念那段旧时光~
    文艺小青年
    又是一年中秋节
    luogu1080 国王游戏(贪心+高精度)
  • 原文地址:https://www.cnblogs.com/fortunely/p/14463614.html
Copyright © 2020-2023  润新知