【c++ Primier】第十一章 泛型算法

        使用泛型算法必须包含algorithm头文件:

        #include<algorithm>;

        标准库还定义了一组泛化的算术算法,使用这些算法则必须包含numberic头文件

        #include<numeric>

1. 只读算法

  • find(vec.begin(),vec.end(),search_value)
    • 使用两个迭代器和一个值调用find函数,检查两个迭代器实参标记范围内的每一个元素,只要找到与给定值相等的元素,find就会返回指向该元素 的迭代器。
  • int sum = accumulate(vec.begin(),vec.end(),42);
    • accumulate函数将它的一个内部变量设置为指定的初值,然后在此初值上累加输入范围内所有元素的值。accumulate算法返回累加的结果,其返回类型就是其第三个实参的类型。用于指定累加初始值的第三个实参是必要的,因为accumulate对将要累加的元素类型一无所知,因此,除此之外,没有别的办法创建合适的起始值或者关联的类型。
  • find_first_of:
    • 功能描述:在第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素。如果找不到匹配,则返回第一个范围的end迭代器。示例如下:
size_t cnt;
list<string>::iterator iter = roster1.begin();

while( (iter = find_first_of(iter, roster1.end(),roster2.begin(),roster2.end())) !=roster1.end() ){
        ++cnt;
        ++iter;
}

cout << "Found " << cnt << " name on both rosters" << endl;

2. 写容器元素的算法

  • 写入输入序列的元素
    • fill(vec.begin(), vec.end(), 10);
      • fill带有一对迭代器形参,用于指定要写入的范围,而所写的值是它的第三个形参的副本。如果输入范围有效,则可安全写入。
  • 不检查写入操作的算法
    • fill_n(vec.begin(), 10, 0);
      • 该函数从迭代器指向的元素开始,将指定数量的元素设置为给定的值。
  • 引入back_inserter

        back_inserter生成一个绑定在该容器上的插入迭代器。在试图通过这个迭代器给元素赋值时,赋值运算将调用push_back在容器中添加一个具有指定值的元素。示例如下:

vector<int> vec;

fill_n(back_inserter(vec), 10, 0);

        实现效果相当于在vec末尾添加10个元素,每个元素的值都是0.

  • 写入到目标迭代器的算法

vector<int> ivec;

copy(ilst,begin(), ilst.end(), back_inserter(ivec));

        这个例子的效率比较差,更好的方法是直接用输入范围作为新构造容器的初始化:

vector<int> ivec(ilst.begin(), ilst.end());

  • 算法的_copy版本

vector<int> ivec;

replace_copy(ilst.begin(), ilst,end(), back_inserter(ivec), 0, 42);

        调用该函数后,ilst没有改变,ivec存储ilst的一份副本,而ilst内所有的0在ivec中都变成了42.

3 对容器元素重新排序的算法

bool isShorter(const string &s1, const string &2){
        return s1.size() < s2.szie();
}

bool GT6(const string &s){
        reutrn s.size() >= 6;
}

int main(){
        vector<string> words;
        string next_word;
        while(cin >> next_word){
                words.push_back(next_word);
        }

        sort(words.begin(), words.end());
        vector<string>::iterator end_unique = unique(words.begin(), words.end());

        words.erase(end_unique, words.end());
        stable_sort(words.begin(), words.end(), isShorter);
        vector<string>::size_type wc = count_if(words.begin(), words.end(), GT6);
        cout << wc << " " << make_plural(wc, "word", "s") << " b characters or longer" << endl;

        return 0;
}

        words中的单词排好序后,调用unique返回一个迭代器,指向超出无重复的元素范围末端的下一位置,即表示无重复的值范围的结束。函数isShorter和GT6分别是函数stable_sort和count_if的谓词。

4 再谈迭代器

        容器除了普通的迭代器以外,C++还提供了另外三种迭代器:

  • 插入迭代器(inster iterator)
    • 实现在容器中插入元素的功能。
  • iostream迭代器(iostream iterator)
    • 与输入输出流绑定在一起,用于迭代遍历所关联的IO流。
  • 反向迭代器(reverse iterator)
    • 由rbegin和rend成员函数返回

4.1 插入迭代器

        调用这三个函数都能生成一个迭代器:

  • back_inserter:生成使用push_back实现插入的迭代器
  • front_inserter:生成使用push_front实现插入的迭代器
  • inserter :生成使用insert函数实现插入的迭代器,除了所关联的容器外,inserter还带有第二个实参:指向插入起始位置的迭代器(该迭代器指向位置不变)

        用法示例如下:

list<int> ilst, ilst2, ilst3;

//after this loop,ilst contains 3 2 1 0
for(list<int>::size_type i=0;i!=4;++i)
         ilst.push_front(i);

//after copy,ilst2 contains 0 1 2 3
copy(ilst.begin(), ilst.end(), front_inserter(ilst2));

//after copy,ilst3 contains 3 2 1 0
copy(ilst.begin(), ilst.end(), inserter(ilst3, ilst3.begin()));

4.2 iostream迭代器

  • iostream迭代器的构造函数(头文件iterator)
    • istream_iterator<T> in(strm)
      • 创建从输入流strm读取T类型对象的istream_iterator对象
    • istream_iterator<T> in;
      • 未关联输入流,默认为istream_iterator对象的超出末端迭代器
    • ostream_iterator<T> out(strm)
      • 创建将T类型的对象写到输出流strm的ostream_iterator对象
    • ostream_iterator<T> out(strm, delim)
      • 创建将T类型的对象写到输出流strm的ostream_iterator对象,在写入过程中使用delim作为元素的分割符。delim是以空字符结束的字符数组。
  • 示例一
istream_iterator<int> cin_it(cin);
istream_iterator<int> end_of_stream;

//使用迭代器范围初始化ivec
//vector<int> ivec(cin_it, end_of_stream);

while(cin_it != end_of_stream){
        ivec.push_back(*cin_it++);
}

for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)
        cout << *iter << endl;
  • 示例二
ostream_iterator<string> out_iter(cout, "\n");
istream_iterator<string> cin_it(cin), eof;

while(cin_it != eof){
        *out_iter++ = *cin_it++;
}

        注解:当绑在流上的迭代器在遇到文件结束或者某个错误时,将等于超出末端迭代器的值。

4.3 反向迭代器

  • 由于不能反向遍历流,因此流迭代器不能创建反向迭代器。
  • 反向迭代器的几个示例:

        string:reverse_iterator rcomma = find(line.rbegin(), line.rend(), ',');

        cout << string(line.rbegin(), rcomma) << endl;

        假设字符串line的值为hello,world,则以上程序的输出为:dlrow.这是因为反向迭代器是逆序从后向前处理string对象。为了得到争取的输出,可以采用反向迭代器提供的成员函数base,用法如下:

        cout << string(rcomma.base(), line.end()) << endl;

        得到正确的输出:world。

4.4 const_iterator:只读迭代器

5. 五种迭代器

        算法要求的迭代器操作分为五个类别,分别对应如下五中迭代器:

  • 输入迭代器
    • 只能读不能写;只支持自增运算
  • 输出迭代器
    • 只能写不能读;只支持自增运算
  • 前向迭代器
    • 读和写;只支持自增运算
  • 双向迭代器
    • 读和写;支持自增和自减运算
  • 随机访问迭代器
    • 读和写;支持完整的迭代器算术运算
  • 6. list容器特有的操作
    • lst.merge(lst2)
    • lst.merge(lst2, comp)
    • lst.remove(va)
    • lst.remove_if(unaryPred)
    • lst.reverse()
    • lst.sort()
    • lst.splice(iter, iter2)
    • lst.splice(iter, lst2, iter2)
    • lst.splice(iter, begin, end)
    • lst.unique()
    • lst.unique(binaryPred)

        具体用法和含义略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值