C++学习之第二十天-STL之算法algorithm

知识点

1.概述
    算法中包含很多对容器进行处理的算法,使用迭代器来标识要处理的数据或数据段、以及结果的存放位置,有的函数还作为对象参数传递给另一个函数,实现数据的处理。
    这些算法可以操作在多种容器类型上,所以称为“泛型”,泛型算法不是针对容器编写,而只是单独依赖迭代器和迭代器操作实现。
    
2.分类
    1、非修改式序列操作:不改变容器的内容,如find()、for_each()等。
    2、修改式序列操作:可以修改容器中的内容,如transform()、random_shuffle()、copy等。
    3、排序和相关操作:包括各种排序函数等,如sort()等。
    4、通用数字运算:计算两个容器的内部乘积等。

3.一元函数以及一元断言/一元谓词
    一元函数:函数的参数只有一个;
    一元断言/一元谓词:函数的参数只有一个,并且返回类型是bool类型。
    二元函数:函数的参数有两个;
    二元断言/二元谓词:函数的参数两个,并且返回类型是bool类型。

4.函数适配器——函数绑定器,bind1st,bind2nd,bind.
    模板形式中,两个函数绑定器的第一个参数就是一个函数,第二个参数就是一个数字,如果F是一个二元函数(普通二元函数或者二元谓词),我们可以绑定F的第一个参数(bind1st)或者第二个参数(bind2nd),达到我们想要的效果(使用二元谓词的效果)
    bind函数的使用相比于bind1st以及bind2nd更加的具有通用性,因为后者只能绑定一个参数,而bind可以绑定任意个参数。bind可以绑定到普通函数、成员函数。
    bind函数的返回类型到底是什么呢?其实就是一种函数类型,就是一种可以装函数类型的容器,即:function。有了function之后,bind函数还可以绑定到数据成员上面来

5.std::function与std::bind结合使用体现出多态性的例子,也就是注册回调函数与执行回调函数。
6.成员函数绑定器.
    em_fun() //容器参数为类指针
    mem_fun_ref() //容器参数为类对象
    mem_fn()// 两者都能用(C++11),其使用更具有广泛性,直接使用代码就ok

1.非修改式算法,for_each,find的用法

​ 1.使用for_each和匿名函数实现打印vector

​ 2.algorithm中count和find的使用方法,find返回的是一个迭代器

接口:

template< class InputIt, class UnaryFunction >
UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
//UnaryFunction一元函数

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
void myPrint(int &num)
{
    ++num;
    cout<<num<<" ";
}
void test01()
{
    vector<int> numberVec={1,3,5,7,9,2,3,4,5};
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;
    //for_each进行遍历打印
    for_each(numberVec.begin(),numberVec.end(),myPrint);
    cout<<endl;
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;

    //匿名函数lambda实现打印
    for_each(numberVec.begin(),numberVec.end(),[](int num){cout<<num<<" ";});
    cout<<endl;
}
void test02()
{
    //count的使用
    vector<int> numberVec={1,3,5,7,9,2,3,4,5,3,3,3};
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;

    int ret = count(numberVec.begin(),numberVec.end(),3);
    
    cout<<"count="<<ret<<endl;
    //find返回的是一个迭代器
   auto it= find(numberVec.begin(),numberVec.end(),13);
   cout<<"find(9)="<<*it<<endl;

}
int main()
{
    test01();
    cout<<endl<<endl;
    test02();
    return 0;
}
/*
1 3 5 7 9 2 3 4 5 
2 4 6 8 10 3 4 5 6 
2 4 6 8 10 3 4 5 6 
2 4 6 8 10 3 4 5 6 


1 3 5 7 9 2 3 4 5 3 3 3 
count=5
find(9)=0
*/

2.修改式算法(copy/remove_if)

template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p);
//UnaryPredicate:一元谓词,函数参数只有一个,并且返回的是bool类型
//1.remove_if返回要删除的数据的首个迭代器,把要保留的数据往前移了
//2.remove_if必须配合erase使用,才能把数据干掉,再配合shrink_to_fit()回收相应内存空间

删除vector中大于4的元素

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
void myPrint(int &num)
{
    ++num;
    cout<<num<<" ";
}
bool func(int number)
{
    return number>4;
}
void test01()
{
    vector<int> numberVec={1,3,5,7,9,2,3,4,4,6,9,8,7,7};
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;

    auto it = remove_if(numberVec.begin(),numberVec.end(),func);
    //把小于等于4的数据往前移,返回要删除的数据的首个迭代器
    cout<<numberVec.capacity()<<endl;
    //remove_if必须配合erase使用,才能把数据干掉
    numberVec.erase(it,numberVec.end());//返回要删除的第一个数据迭代器
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;
    numberVec.shrink_to_fit();
    cout<<numberVec.capacity()<<endl;
}
//remove_if写成匿名函数形式
void test02()
{
    vector<int> numberVec={1,3,5,7,9,2,3,4,4,6,9,8,7,7};
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;

    auto it = remove_if(numberVec.begin(),numberVec.end(),
                        [](int num)
                      -> bool {//返回类型的书写方式,可以省略不写
                            return num>4;
                        });
    //把小于等于4的数据往前移,返回要删除的数据的首个迭代器
    cout<<numberVec.capacity()<<endl;
    //remove_if必须配合erase使用,才能把数据干掉
    numberVec.erase(it,numberVec.end());//返回要删除的第一个数据迭代器
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;
    numberVec.shrink_to_fit();
    cout<<numberVec.capacity()<<endl;
}



int main()
{
    test01();
    test02();
    return 0;
}

3.bind1st和bind2nd

template< class F, class T >
std::binder1st<F> bind1st( const F& f, const T& x );
//把x绑定到二言谓词的第一个或者第二个参数
template< class F, class T >
std::binder2nd<F> bind2nd( const F& f, const T& x );

/* 删除vector中大于4的元素*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>

using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
using std::copy;
void test01()
{
    vector<int> numberVec = {1,3,5,7,9,8,67,32,2,3,4,7};
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;//1 3 5 7 9 8 67 32 2 3 4 7 
	//把4绑定到std::less<int>()函数对象的第一个参数
    auto it = remove_if(numberVec.begin(),numberVec.end(),std::bind1st(std::less<int>(),4));
    numberVec.erase(it,numberVec.end());
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;

}
void test02()
{
	
    vector<int> numberVec = {1,3,5,7,9,8,67,32,2,3,4,7};
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;//1 3 5 7 9 8 67 32 2 3 4 7 
	//把4绑定到std::greater<int>()函数对象的第2个参数
    auto it = remove_if(numberVec.begin(),numberVec.end(),std::bind2nd(std::greater<int>(),4));
    numberVec.erase(it,numberVec.end());
    copy(numberVec.begin(),numberVec.end(),ostream_iterator<int>(cout," "));
    cout<<endl;
    numberVec.shrink_to_fit();

}
int main()
{
    test01();
    test02();
    return 0;
}
/*
1 3 5 7 9 8 67 32 2 3 4 7 
1 3 2 3 4 
1 3 5 7 9 8 67 32 2 3 4 7 
1 3 2 3 4 
*/

5.bind的使用

test01():.bind绑定到普通函数

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <functional>
using std::cout;
using std::endl;
using std::for_each;
using std::vector;
using std::ostream_iterator;
using std::copy;
using std::bind;
int add(int x, int y)
{
    return x+y;
}
int multiply(int x,int y,int z)
{
    cout<<"int multiply(int,int,int)"<<endl;
    return x*y*z;
}
//1.绑定到普通函数
void test01()
{
    //1.bind绑定两个参数
    auto f = bind(add, 1,2);//把参数1,2绑定到add,不用给f传参
    //f的类型:int(),直接调用
    cout<<f()<<endl;//3
    
    //2.bind 绑定三个参数,f1类型:int()
    auto f1 = bind(multiply, 1,2,3);
    cout<<f1()<<endl;//6
}

2.bind绑定到类的成员函数

class Example
{
public:
    int add(int x,int y)
    {
        cout<<"int Example::add(int,int)"<<endl;
        return x+y;
    }
    int data = 100;//c++11提出了的初始化的方式
};
//2.bind绑定到类的成员函数
void test02()
{
    Example ex;
    auto f1 = bind(&Example::add, &ex,1,2);
    //加&ex的原因:成员函数内蕴含了一个指针this
    cout<<f1()<<endl;//3
}

3.placeholder占位符的使用

//3.placeholder占位符的使用
void test03()
{
    int number = 100;
    auto f=bind(add,std::placeholders::_1,
                std::placeholders::_3);
    //绑定了两个参数,未知参数
    cout<<f(20,10,30)<<endl;
}
/*
50
*/
//4.placeholders的作用
void func4(int x1,int x2,int x3,const int &x4, int x5)
{
    cout<<"("<<x1
        <<","<<x2
        <<","<<x3
        <<","<<x4
        <<","<<x5<<")"<<endl;
} 
void test04()
{
    int number = 100;
    auto f = std::bind(func4,std::placeholders::_11,std::placeholders::_5
         ,number,std::cref(number),number);//placeholders占位符:表示形参的位置
    //f(111,22,2);placeholders后面的数字代表传的是实参处于实参列表的位置
    number = 500;//参数传递使用的是值传递,用cref来改变,const ref
    //cref:引用的包装器
    f(1,3,5,7,9,12,3,212,2123,444,122);//第11个数:122,第5个数:9
    //除了第5个和第11个数,其余的数没多大用处,只用来占位
}
/*
(122,9,100,500,100)
*/

4.用函数类型(function)容器来接受bind函数返回的类型

int add(int x, int y)
{
    return x+y;
}
int multiply(int x,int y,int z)
{
    cout<<"int multiply(int,int,int)"<<endl;
    return x*y*z;
}
class Example
{
public:
    int add(int x,int y)
    {
        cout<<"int Example::add(int,int)"<<endl;
        return x+y;
    }
    int data = 100;//c++11提出了的初始化的方式
};
void test05()
{
//int (int,int)====> int(),返回的是一个int类型的参数?
    std::function<int()> f = bind(add, 1,2);
    cout<<"f()="<<f()<<endl;//3

    auto f2 = bind(multiply,3,4,5);
    cout<<"f2()="<<f2()<<endl;//60


    cout<<endl;
    Example ex;
    std::function<int()> f3 = bind(&Example::add,&ex,4,5);//成员函数中隐藏了一个this指针
    cout<<f3()<<endl;//9
    
    //绑定到成员,对象里来
    f3 = bind(&Example::data,&ex);
    cout<<"data:f3()="<<f3()<<endl;//100
    //int (int ,int)====> int add(1,xxxx);绑定一个参数,另外一个在调用时输入
    std::function<int(int)> f4 = bind(add, 1, std::placeholders::_1);
    cout<<f4(3)<<endl;//4


    std::function<int(int,int,int)> f5 = bind(add, std::placeholders::_3, std::placeholders::_1);
    cout<<f5(3,12,300)<<endl;//303
}

6.bind+function的特点的使用来实现类的多态--也就是注册回调函数与执行回调函数。

1.回调函数:把函数的注册和函数的执行分开。
2.bind:返回的是一种函数类型,是一种可以装函数类型的容器。
    template< class R, class F, class... Args >
    bind( F&& f, Args&&... args )
3.有了function之后,bind函数还可以绑定到数据成员上面来,其实就是int()这中类型上来。

#include <math.h>
#include <iostream>
#include <functional>
#include <string>
using std::string;
using std::cout;
using std::endl;
using std::bind;
using std::function;

class Figure
{
public:
    //1.定义函数的类型
    using DisplayCallback = std::function<void()>; //用DisplayCallback代替std::function<void()>,
    //用DisplayCallback声明的对象,是一个可以接受void()---void无参类型的函数的容器
    using AreaCallback = std::function<double()>; //用AreaCallback声明的对象,是一个接受doulbe()类型的容器
    
    using AreaCallback_double = std::function<double(double)>;//声明一个接收double(double)类型的容器,传入参数pi

    DisplayCallback _display;
    AreaCallback _showarea;
    AreaCallback_double _area_double;
    //2.注册回调函数
    void SetDisplayCallback(DisplayCallback &&dc)//dc用来接受bind返回的对象,是一个右值
    {
        _display =std::move(dc);//用移动语义转移资源
    }
    void SetAreaCallback(AreaCallback &&ac)//dc用来接受bind返回的对象,是一个右值
    {
        _showarea =std::move(ac);//用移动语义转移资源
    }
    void SetAreaCallback_double(AreaCallback_double &&acd)
    {
        _area_double = std::move(acd);
    }
    //3.执行回调函数
    void Execute_Display()const
    {
        if(_display)
        {
            _display();
        }
    }

    double Execute_Area()const
    {
        if(_showarea)
        {
            return _showarea();
        }
        else
        {
            return 0;
        }
    }

    double Execute_Area_double(const double &pi)const
    {
        if(_area_double)
        {
            return _area_double(pi);
        }
        else
        {
            return 0;
        }
    }
};
class Rectangle
{
public:
    Rectangle(double len = 0, double width = 0)
    : _length(len)
    , _width(width)
    {}

    void display() const
    {
        cout << "Rectangle(length)= "<<_length
            <<endl<<"Rectangle(width)="<<_width<<endl;
    }

    double area() const
    {
        return _length * _width;
    }
private:
    double _length;
    double _width;
};

class Circle
{
public:
    Circle(double len = 0)
    : _didus(len)
    {}

    void print() const
    {
        cout << "Circle(Radius)= "<<_didus<<endl ;
    }

    double printArea(const double &pi) const//传个pi进来
    {
        return  pi * _didus * _didus;
    }
private:
    double _didus;
};
class Traingle
{
public:
    Traingle(double a = 0, double b = 0, double c = 0)
    : _a(a)
    , _b(b)
    , _c(c)
    {
    }

    void show() const 
    {
        cout << "Traingle(a)="<<_a<<endl ;
        cout << "Traingle(a)="<<_b<<endl ;
        cout << "Traingle(a)="<<_c<<endl ;
    }

    double showArea() const 
    {
        double p = (_a + _b + _c)/2;
        return sqrt(p * (p - _a) * (p - _b) * (p - _c));
    }

private:
    double _a;
    double _b;
    double _c;
};
void test01()
{   
    Rectangle rectagle(10, 20);
    Circle circle(100);
    Traingle traingle(3, 4, 5);

    Figure figure;
    //1.注册回调函数,Rectangle回调函数
    //2.执行回调函数Rectangle回调函数
    figure.SetDisplayCallback(bind(&Rectangle::display, &rectagle));
    figure.Execute_Display();

    figure.SetAreaCallback(bind(&Rectangle::area,&rectagle));
    cout<<"S(Rectangle)="<<figure.Execute_Area()<<endl;//Area返回是一个double类型的值

    
    //1.注册回调函数,Circle回调函数
    //2.执行回调函数Circle回调函数
    figure.SetDisplayCallback(bind(&Circle::print, &circle)); 
    figure.Execute_Display();//打印半径
    //传入实参,能顺利执行
    figure.SetAreaCallback_double(bind(&Circle::printArea, &circle, std::placeholders::_1));
    cout<<"S(Circle)="<<figure.Execute_Area_double(3.14)<<endl;//31400
    
    //1.注册回调函数,Traingle回调函数
    //2.执行回调函数Triangle回调函数
    figure.SetDisplayCallback(bind(&Traingle::show, &traingle));
    figure.Execute_Display();
    figure.SetAreaCallback(bind(&Traingle::showArea,&traingle));
    cout<<"S(Triangle)="<<figure.Execute_Area()<<endl;
}
int main()
{
    test01();
    return 0;
}
/*
Rectangle(length)= 10
Rectangle(width)=20
S(Rectangle)=200
Circle(Radius)= 100
S(Circle)=31400
Traingle(a)=3
Traingle(a)=4
Traingle(a)=5
S(Triangle)=6
*/

7.成员函数绑定器.

em_fun() //容器参数为类指针
mem_fun_ref() //容器参数为类对象
mem_fn() //两者都能用(C++11),其使用更具有广泛性,直接使用代码就ok

/* 用mem_fn绑定类中的成员函数来实现remove_if筛选和进行for_each打印*/
#include <iostream>
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

using std::cout;
using std::endl;
using std::vector;
using std::mem_fn;
class Number
{
public:
    Number(size_t data=0)
    :_data(data)
    {

    }
    void print()const
    {
        cout<<_data<<" ";
    }

    bool isEven()const//偶数
    {
        return 0==_data%2;
    }

    bool isPrime()const//判断一个数是否为质数
    {
        if(1==_data)
        {
            return false;
        }
        for(size_t idx = 2; idx<=_data/2;++idx)
        {
            if(0==_data%idx)
            {
                return true;
            }

        }

        return false;
            
    }

private:
    size_t _data;
};
void test01()
{
    vector<Number> numbers;
    for(size_t idx=1;idx!=30;++idx)
    {
        numbers.push_back(Number(idx));
    }
    //用mem_fn绑定成员打印函数·
    std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
    cout<<endl;
    cout<<"调用类中成员函数来删除偶数:"<<endl;
    numbers.erase(remove_if(numbers.begin(),numbers.end(), mem_fn(&Number::isEven))
                  ,numbers.end());//remove_if的用法
    numbers.shrink_to_fit();
    std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
    cout<<endl;
}
//保留质数
void test02()
{
    
    vector<Number> numbers;
    for(size_t idx=1;idx!=100;++idx)
    {
        numbers.push_back(Number(idx));
    }
    std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
    cout<<endl;
    numbers.erase(remove_if(numbers.begin(),numbers.end(),
                            mem_fn(&Number::isPrime)),
                  numbers.end());
    numbers.shrink_to_fit();
    cout<<"调用类中的成员函数来删除非质数:"<<endl;
    std::for_each(numbers.begin(),numbers.end(),mem_fn(&Number::print));
    cout<<endl;

}
    
int main()
{
    test01();
    cout<<endl<<endl;
    test02();
    return 0;
}


/*
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
调用类中成员函数来删除偶数:
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
调用类中的成员函数来删除非质数:
1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

给你。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值