C++复习 11 泛型算法

来源:互联网 发布:服务器udp优化加速 编辑:程序博客网 时间:2024/06/06 12:41


声明,所有的朋友,如果要转我的帖子,务必注明"作者:黑啤来源:CSDN博客"和 具体的网络地址http://blog.csdn.net/nx500/archive/2007/10/24/1842403.aspx,并且我的所有 博客内容,禁止任何形式的商业用途,请大家尊重我的劳动.谢谢!

目 录

十一.泛型算法.
  001 标准库没有为每种容器类型都定义实现各种操作的成员函数,而是定义了一组泛型算法.
      因为他们实现共同的操作,所以称为算法;因为他们可以操作在多种容器类型上,所以称为泛型.
      泛型算法从不执行容器的操作,只是单独依赖迭代器和迭代器操作实现.
      使用泛型算法必须先包含algorithm头文件.使用泛化的算术算法则必须包含numeric头文件.
        #include <algorithm>
        #include <numeric>
  002 find.在两个迭代器中搜索指定元素.
        int search_value = 42;
        vector<int>::const_iterator result = find(vec.begin(), vec.end(), search_value);
  003 累加指定范围元素的和,通过第三个元素,传递泛型算法针对的元素类型.
        int sum = accumulate(vec.begin(), vec.end(), 0);
      使用accumulate把string型的vector容器中的元素连接起来.
        string sum = accumulate(vStr.begin(), vStr.end(), string(""));
  004 将元素写入容器的算法.
      使用迭代器确定写入的范围,这样操作可以通过迭代器保证写入的范围是有效的.
        fill(vec.begin(), vec.end(), 0);  // 将vec的元素都设置为0.
      不检查写入范围的算法,可能越界,造成意想不到的后果.
        fill_n(vec.gegin(), 10, 0);
      使用插入迭代器防止越界,使用back_inserter必须包含iterator头文件.
        vector<int> vec; // 声明一个空容器.
        fill_n(back_inserter(vec), 10, 0); // fill_n每写入一个函数,都会通过back_inserter生成的插入迭代器实现.
      向目标迭代器写入未知个数的元素.
        vector<int> ivec;
        copy(ilist.begin(), ilist.end(), back_inserter(ivec)); // 将ilist中的元素copy到ivec中
        // 以上代码只是举例,更有效率的办法是初始化时赋值 vector<int> ivec(ilist.begin(), ilist.end());
      改变输入序列的算法.
        replace(ilst.begin(), ilst.end(), 0, 42); // 将ilst序列中0元素换为42.
        // 下面一行ilst容器中元素不变,在ivec中保存一份ilst的副本,但是ilst中的0,在lvec中都是42.
        replace(ilst.begin(), ilst.end(), back_inserter(ivec), 0 , 42);
  005.对容器元素重新排序.
        分析一组单词,求它们一共包含了多少个6个或6个以上字母组成的单词,每个单词只统计一次,不考虑重复情况.
        // 将words中的元素(单词)安字母顺序排序.
        sort(words.begin(), words.end());
        // 将排序后的words只保留一个单词的副本,也就是将重复的单词删除.
        // unique可以将没有重复的单词复制到容器的前端,比 "aa bb bb cc dd dd c" 变成"aa bb cc dd dd dd c".
        // 同时unique返回一个指针,指向最后一个不重复的单词的下一个元素,上边的例子就是指向倒数第三个元素.所以...
        vector<string>::iterator end_unique = unique(word.begin(), word.end());
        words.erase(end_unique, words.end());
        // stable_sort算法,排序后结果保留相等元素的原始相对位置,它支持谓词(自定义函数),自定义一个长度相等的函数替换元素的==操作符.
        // 这个函数必须带有两个实参,每个实参都是元素的类型,并且返回一个bool型结果.
        bool isShorter(const string& s1, const string& s2){
          return s1.size() < s2.size();
        }
        stable_sort(words.begin(), words.end(), isShorter);
        // count_if算法,比count算法多一个统计条件(谓词),这个谓词要求带一个元素类型的实参,返回一个bool的结果.
        class GT{
          std::string::size_type bound;
        public:
          GT(int sz = 0):bound(sz){}
          bool operator()(const string& s){
            return s.size() >= bound
          }
        };
        vector<string>::size_type wc = count_if(words.begin(), words.end(), GT(6));
        // 程序11005.cpp
        #include <iostream>
        #include 
<string>
        #include 
<vector>
        
using std::cin;
        
using std::cout;
        
using std::endl;
        
using std::string;
        
using std::vector;

        
// 创建复数形式
        string make_plural(size_t ctr, const string &word, const string &ending){
          
return (ctr == 1? word : word + ending;
        }


        
// 定义stable_sort算法的谓词函数.
        bool isShorter(const string& s1, const string& s2){
          
return s1.size() < s2.size();
        }


        
// 定义count_if算法的谓词函数类
        class GT{
          
string::size_type bound;
        
public:
          GT(
int sz = 0):bound(sz){}
          
bool operator()(const string& s){
            
return s.size() >= bound;
          }

        }
;

        
int main(){
        vector
<string> words;
        
string next_word;
          
// 从键盘终端读入待统计的单词
          while(cin >> next_word){
            words.push_back(next_word);
          }

          
// 将words中的元素(单词)按字母顺序排序.
          sort(words.begin(), words.end());
          
// 将排序后的words只保留一个单词的副本,也就是将重复的单词删除.
          vector<string>::iterator end_unique = unique(words.begin(), words.end());
          words.erase(end_unique, words.end());
          
// 将words按照单词长度排序, 经过部分验证,没有这一步不影响统计结果.
          stable_sort(words.begin(), words.end(), isShorter);
          
// 统计长度大于等于6的单词长度.
          vector<string>::size_type wc = count_if(words.begin(), words.end(), GT(6));
          cout 
<< wc << " " << make_plural(wc, "word""s")
               
<< " 6 characters or longer" << endl;
          
for(vector<string>::const_iterator it = words.begin(); it != words.end(); ++it){
            cout 
<< *it << " ";
          }

         
return 0;
       }


  006 除容器本身的迭代器之外,C++提供额外三种迭代器:插入迭代器/iostream迭代器/反向迭代器,他们都包含在<iterator>头文件中.
  007 三种插入迭代器.插入器其实是一个迭代器的适配器,带有一个容器的参数,生成一个迭代器,用于在指定的容器中插入元素.
        back_inserter,创建使用push_back实现插入的迭代器.
          vector<int> vec; // 声明一个空容器.
          fill_n(back_inserter(vec), 10, 0); // fill_n每写入一个函数,都会通过back_inserter生成的插入迭代器实现.
        front_inserter,是push_front实现插入,所以vector是不能使用这个插入器的.
        inserter,使用insert是实现插入操作,除了所关联的容器作为第一个参数外,还有一个指向插入起始位置的迭代器参数.
          // 在ilst容器中元素为42前插入ivec的全部元素,并将ivec中值为100的元素替换为0.
          list<int>::iterator it = find(ilst.begin(), ilst.end(), 42);
          replace_copy(ivec.begin(), ivec.end(), inserter(ilst, it), 100, 0);
        inserter和front_inserter的行为有很大差别.在使用front_inserter时,元素始终在容器的第一个元素前面插入.
        而使用inserter,元素则在指定位置前面插入.如果这个位置是容器的第一个元素,插入一个新元素后,它就不在是第一个元素了.
          #include <iostream>
          #include 
<list>
          #include 
<algorithm>
          
#define SIZE 4

          
using std::list;
          
using std::cout;
          
using std::endl;
          
using std::front_inserter;
          
using std::inserter;

          
// 输出指定迭代器之间的元素
          void printList(list<int>::const_iterator begin, list<int>::const_iterator end){
            
while (begin != end){
              cout 
<< *begin << " ";
              
++begin;
            }

            cout 
<< endl;
          }


          
// 11007.cpp 验证front_inserter和inserter之间的不同.
          int main(void){
          list
<int> ilst, ilst2, ilst3;
            
// 创建原始数据序列 3 2 1 0.
            for(list<int>::size_type i = 0; i != SIZE; ++i){
              ilst.push_front(i);
            }

            
// 使用front_inserter插入器,形成0 1 2 3 序列.
            copy(ilst.begin(), ilst.end(), front_inserter(ilst2));
            
// 使用inserter在ilst3.begin()这个位置插入,这个位置是指第一次插入前固定的位置.
            
// 不是每插入一个元素都运行一次ilst3.begin(),所以形成3 2 1 0序列.
            copy(ilst.begin(), ilst.end(), inserter(ilst3, ilst3.begin()));
            printList(ilst.begin(), ilst.end());
            printList(ilst2.begin(), ilst2.end());
            printList(ilst3.begin(), ilst3.end());

            
return 0;
          }


  008 虽然iostream类型不是容器,但是标准库同样提供了在iostream对象上使用的迭代器.这些迭代器将它们所对应的流视为特定类型的元素序列.
        istream_iterator<T> it(strm);         创建从输入流strm中读入T类型对象的istream_iterator对象.
        istream_iterator<T> it;               创建istream_iterator对象的超出末端迭代器.
        ostream_iterator<T> it(strm);         创建将类型T的对象写到流ostream_iterator对象.
        ostream_iterator<T> it(strm, delim);  创建将类型T的对象写到流strm的ostream_iterator对象,写入过程中用delim分割.
      流迭代器定了基本的迭代器操作,自增/解引用/赋值,两istream可以比较是否相等,但ostream迭代器不能比较.
      定义流迭代器.
        istream_iterator<int> cin_it(cin);   // 从cin中读入int类型对象.
        istream_iterator<int> eof;           // 输入流的末端指示迭代器.
        // 创建一个Sales_item类型对象写入到ofstream流中的迭代器.
        ofstream outfile;
        ostream_iterator<Sales_item> output(outfile, " ");
      istream_iterator对象上的操作.
        // 将流上的对象逐个添加到容器中.
        istream_iterator<int> cin_it(cin);   // 从cin中读入int类型对象.
        istream_iterator<int> eof;           // 输入流的末端指示迭代器.
        list<int> ilst;
        while(cin_it != eof)
          ilst.push_back(*cin_it++);
        // 使用初始化的方式将流中的元素放到容器中.
        vector<int> ivec(cin_it, eof);
      ostream_iterator对象的操作.
        // 写一个字符串字面值到cout流中.
        ostream_iterator<string> out_it(cout, "hello heipi!");
        // 读入cin流中的元素,并逐一写到cout流中去
        istream_iterator<string> cin_it(cin), eof;
        while(cin_it != eof)
          *out_it++ = *cin_it++;
      在类类型上使用istream_iterator.只要类型提供了输入操作符,就可以创建istream_iterator对象.
        // 11008.cpp
        #include <iostream>
        #include 
<iterator>
        #include 
"Sales_item.h"
        #include 
"Sales_item.cpp"

        
using std::cin;
        
using std::cout;
        
using std::endl;
        
using std::istream_iterator;

        
int main(void){
        
// 定义Sales_item类型的输入流迭代器和超出末端迭代器.
        istream_iterator<Sales_item> item_iter(cin), eof;
        Sales_item sum;
          
// 从迭代器中读入第一个元素
          sum = *item_iter++;
          
// 循环读入元素,如果不是同一本书,则输出前边的统计结果,然后开始统计新书的数据.
          while(item_iter != eof){
            
if(item_iter ->same_isbn(sum))
              sum 
+= *item_iter;
            
else{
              cout 
<< sum << endl;
              sum 
= *item_iter;
            }

            
++item_iter;
          }

          cout 
<< sum << endl;
          
return 0;
        }


        //编译及运行结果
        heipi@Linux:~/Documents/CPP> g++ -o o Sales_item.cpp 11008.cpp
        heipi@Linux:~/Documents/CPP> ./o
        9-99-999-8898 2 398
        9-99-999-8898 3 453
        9-88-888-8989 1 23
        9-99-999-8898   5       2155    431
        ^d9-88-888-8989   1       23      23
        heipi@Linux:~/Documents/CPP>
  009 迭代器的限制.
        1.不能从ostream_iterator对象读入,也不能写到istream_iterator.
        2.一旦写入ostream_iterator对象,就不能从中删除了.
        3.ostream_iterator没有->操作.
  010 将流迭代器与算法一起操作.
        // 11010.cpp 将输入流中的整形元素排序,并去掉重复项输出.
        #include <iostream>
        #include 
<iterator>
        #include 
<algorithm>
        #include 
<vector>

        
using std::cin;
        
using std::cout;
        
using std::endl;
        
using std::vector;
        
using std::istream_iterator;
        
using std::ostream_iterator;

        
int main(void){
          
// 从输入段读入元素,放到容器中.
          istream_iterator<int> cin_it(cin), eof;
          vector
<int> vec(cin_it, eof);
          
// 排序,输出.
          sort(vec.begin(), vec.end());
          ostream_iterator
<int> cout_it(cout, " ");
          unique_copy(vec.begin(), vec.end(), cout_it);
          cout 
<<endl;
          
return 0;
        }


        // 编译运行
        heipi@Linux:~/Documents/CPP> g++ -o o 11009.cpp
        heipi@Linux:~/Documents/CPP> ./o
        1 2 3 43213 5625 5463 24134 676 13423 76356 211 2 3 4 5625
        1 2 3 4 211 676 5463 5625 13423 24134 43213 76356
        heipi@Linux:~/Documents/CPP>
  011 反向迭代器(reverse_iterator),是一种反向遍历容器的迭代器.也就是从最后一个元素到第一个元素遍历容器.
      注意反向迭代器标识的范围,特别是在输出上,小心陷阱.反向迭代提供一个成员函数base(),返回该迭代器按照正向方向的下一个元素的迭代器.
  012 五种迭代器的操作.
        1.输入迭代器只能顺序使用,一旦迭代器自增,就无法再用它检查之前的元素.
        2.输出迭代器,对于指定的迭代器值因该使用一次*运算,而且只能使用一次.一般输出迭代器作为算法的第三个参数.
        3.前向迭代器用于读写指定的容器,只会以一个方向遍历序列.可复制前向迭代器来记录序列的一个位置,以便将来返回此处.
        4.双向迭代器.
        5.随机访问迭代器,迭代器支持+/-n操作,下标[]操作.
      map/set/list类型提供双向迭代器,而string/vector/deque容器定义的迭代器都是随机访问迭代器,用作访问内置数组元素的指针也是随机的.
      istream_iterator是输入迭代器,而ostream_iterator是输出迭代器
      尽管map和set类型提供双向迭代器,但关联容器只能使用算法的一个子集.因为关联容器的键值是const对象.
      因此关联容器不能使用任何写序列元素的算法,只能使用与关联容器绑定在一起的迭代器来提供用于读操作的实参.
      向算法传递无效的迭代器类别所引起的错误,编译时无法保证能发现.
原创粉丝点击