笔记:C++学习之旅---泛型算法


       标准库并未给每个容器定义成员函数来实现这些操作,而是定义了一组泛型算法(generic algorithm):称他们为”算法“,是因为他们实现了一些经典算法的公共接口,如排序和搜索:称他们是“泛型的”,是因为它们可以用于不同类型的元素和多种容器类型(不仅包括标准库类型,如vector或list,还包括内置的数组类型),以及我们将看到的,还能用于其他类型的序列。

练习10.3,10.4
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;

int main()
{
             vector < int > vec;
             int i = 0;
            cout << "请输入整数" << endl;
             while (cin >> i)
            {
                         if (i == -1)
                                     break ;
                        vec.push_back(i);
            }
             int val;
            cout << "请输入你要查找的数字\n" ;
            cin >> val;
             auto result = find(vec.cbegin(), vec.cend(), val); //查找输入的数字是否在容器中,在则显示the value x is present,否则显示the value is not present;
            cout << "The value " << val << (result == vec.cend() ? " is not present\n " : " is present\n" ) << endl; //
            cout << "accumulate1:" << accumulate(vec.cbegin(), vec.cend(), 0)<<endl; //算出元素之和;
             vector < double > ivec = { 1.1, 2.2, 3.3, 4.4,5.5 };
            cout << "accumulate2:" << accumulate(ivec.cbegin(), ivec.cend(), 0.0)<<endl;   //16.5   前面是double,一定要注意用0.0
             return 0;
}


关键概念:算法永远不会执行容器的操作


慎用内联
内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?
如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的
执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收
获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,
消耗更多的内存空间。以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构
函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。
所以不要随便地将构造函数和析构函数的定义体放在类声明中。
一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明
了inline 不应该出现在函数的声明中)。

C++ 语言支持函数内联,其目的是为了提高函数的执行效率(速度)。

重排容器元素的算法(sort)、消除重复单词(unique)、使用容器操作删除元素(erase)
练习:10.9
实现你自己的elimDups。测试你的程序,分别在读取输入后,调用unique后以及调用erase后打印vector。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

void elimDups( vector < string > & vec )
{
            sort( vec .begin(), vec .end()); //排序

             auto end_unique = unique( vec .begin(), vec .end()); //重排输入范围,使得每个单词只出现一次,找到重复元素;
            cout << "unique after\n" ;

             for ( auto i = 0; i != vec .size(); ++i)
            {
                        cout<< vec [i] << " " ;
            }
            cout<< endl;
             vec .erase(end_unique, vec .end()); //删除重复元素
            cout << "erase after\n" ;
             for ( auto i = 0; i != vec .size(); ++i)
            {
                        cout << vec [i] << " " ;
            }
            cout << endl;
}
int main()
{
             string word;
             vector < string > vec;
            cout << "请输入一串单词(#结束)\n" ;
             while (cin >> word)
            {
                         if (word == "#" )
                                     break ;
                        vec.push_back(word);
            }
            elimDups(vec);

             return 0;
}


lambda 表达式

练习10.16
使用lambda编写你自己版本的biggies.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

void elimpDups(vector<string> &s)
{
            sort(s.begin(), s.end()); //排序;
             auto new_end = unique(s.begin(), s.end()); //找出重复元素;
            s.erase(new_end, s.end()); //删除重复元素;
}
void biggies(vector<string> &words, vector<string>::size_type sz,ostream &os = cout, char c = ' ' )
{
            elimpDups(words);
            stable_sort(words.begin(), words.end(), [](string const &lhs, string const &rhs){
                         return lhs.size() < rhs.size();}); //按长度排序,长度相同的单词维持字典序;
                         auto wc = find_if(words.begin(), words.end(), [sz](string const &a){
                                     return a.size() >= sz;}); //找到满足size >= sz的元素数目;
                                     /*for_each(wc, words.end(),[](const string &s){
                                                cout << s << " ";});// 打印长度大于等于给定值的单词,每个单词后面接一个空格;
                                                cout << endl;
                                                */
                                    for_each(wc, words.end(), [&os, c]( const string &s){
                                                os << s << c;}); //加入引用捕获;ostream &os = cout,char c = ' ';
                                                os << endl;
}
void   fun1()
{
            size_t v1 = 42;
             auto f2 = [&v1]{ return ++v1; };
            v1 = 0;
             auto j1 = f2();
            cout << j1 << endl; //j1 = 1;
}
void fun2()
{
            size_t v1 = 42;
             auto f2 = [v1]() mutable { return ++v1; };
            v1 = 0;
             auto j2 = f2();
            cout << j2 << endl; //j2 = 43
}
int main()
{
            vector<string> vec = { "1234" , "1234" , "1234" , "hi~" , "alan" , "alan" , "cp" , "a" , "abc" };
            biggies(vec,3);
            fun1(); //引用捕获
            fun2(); //变量捕获
             return 0;
}

默认情况下,对一个被拷贝的变量,lambda不会改变其值,如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上关键字mutable。因此,可变的lambda能省略参数列表。


引用捕获



隐示捕获


谓词: 是一个可调用的表达式,其返回结果是一个能用做条件的的值。标准库算法所使用的的谓词分为两类:一元谓词(意味着它只接受单一参数)、二元谓词(意味着它们有两个参数)。


练习10.24:
给定一个string,使用bind和chaeck_size在一个int的vector中查找第一个大于string长度的值。
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <functional>
using namespace std;
inline bool check_size( const string & s , vector < int >:: size_type sz )
{
             return s .size() < sz ;
}
inline vector < int >:: const_iterator find_first_bigger( const vector < int > & vec , const string & s )
{
             return find_if( vec .cbegin(), vec .cend(),
                        bind(check_size, s , placeholders::_1));
}
int main()
{
             vector < int > vec = { 1, 2, 3, 4, 5, 6 };
             string s = { "test" };
            cout << *find_first_bigger(vec, s)<<endl; //5,找到第一个比字符串“test“ 4 大的数.

             return 0;
}

再探迭代器
除了为每个容器定义的迭代器之外,标准库在头文件iterator中还定义了额外几种迭代器:
插入迭代器:这些迭代器被绑定到一个容器上,可以来向容器插入元素。
流迭代器:这些迭代器被绑定到输入输出流上,可用来遍历所关联的IO流。
反向迭代器:这些迭代器向后面不是向前移动,除了forword_list之外的标准库容器都有反向迭代器。
移动迭代器:这些专用的迭代器不是拷贝其中的元素,而是移动它们。

插入迭代器


流迭代器


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值