C++ 提高编程

0.前言

最近在做算法移植的时候,发现自己对c++的知识忘得很多,于是就计划重新捡起来。
纸上得来终觉浅,绝知此事要躬行
一直都是我学习和工作的原则,我比较喜欢动手。
于是我把c++的基础知识一行行代码敲了一遍。

1.模板


1.1 模板的概念

模板就是建立通用的摸具,提高复用性。

模板的特点:

  • 模板不可以直接使用,它只是一个框架
  • 模板的通用不是万能的

1.2 函数模板

  • c++的另一种编程思想称为泛型编程,主要利用的技术就是模板
  • c++提供2种模板机制:函数模板类模板

1.2.1 函数模板的语法

函数模板的作用:
建立一个统一的函数,其函数返回值类型和形参类型可以不具体,用一个虚拟的类型来代表。

语法:

template<typename T>
函数声明或者定义
**解释:**
* template ---声明创建模板
* typename --- 表面一种数据类型,可以用class代替
* T --- 通用的数据类型,名字可以随便取,通常为大写字母
template <typename T> //或者template <class T>
void mySwap(T &a,T &b)
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}
int main(int argc, char** argv) {
    int a = 10;
    int b = 20;
    //2种方式使用函数模板 
    //1.自动推导类型 
    mySwap(a,b);
    //2.显示指定类型
    mySwap<int>(a,b);
    cout<<"a="<<a<<" b="<<b<<endl; 
    return 0;
}

2种方式使用函数模板

  • 1.自动推导类型
    mySwap(a,b);
  • 2.显示指定类型
    mySwap<int>(a,b);

1.2.2 函数模板的注意事项

注意事项:

  • 自动类型推导,必须推导出一致的数据类型,才可以使用
template <typename T>//或者template <class T>
void mySwap(T &a,T &b)
{
    //省略    
} 
void test1()
{
    int a = 10;
    char b = 'c';
    //mySwap(a,b);报错,a和b类型不一致
}
  • 模板必须要确定出T的数据类型,才可以使用
template <class Z>
void func()//函数模板 
{
    
}

void test2()
{
    //func();//报错,没指定类型 
    func<int>();//正确 
} 

1.2.3 普通函数和函数模板的区别

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型方式,可以发生显示转换
//普通函数
int add(int a,int b)
{
    cout<<a+b<<endl;
    return a+b;
} 
//函数模板 
template <class T>
T myAdd(T a,T b)
{
    cout<<a+b<<endl;
    return a+b;
}

int main(int argc, char** argv) {
    int a=10;
    char b ='a';
    add(a,b);
    //myAdd(a,b);//报错 
    myAdd<int>(a,b);
    return 0;
}

1.2.4 普通函数和函数模板的调用规则

  • 1.如果函数模板和普通函数都可以实现,优先调用普通函数
  • 2.可以通过空模板参数列表来强制调用函数模板
  • 3.函数模板也可以发生重载
  • 4.如果函数模板可以产生更好的匹配,优先调用函数模板。
//普通函数
void myPrint(int a,int b)
{
    cout<<"普通函数 调用"<<endl;
} 

//函数模板
template <class T>
void myPrint(T a,T b)
{
    cout<<"函数模板 调用"<<endl;
} 
//函数模板重载 
template <class T>
void myPrint(T a,T b,T c)
{
    cout<<"函数模板 重载调用"<<endl;
} 
int main(int argc, char** argv) {
    myPrint(10,20);//调用普通函数
    myPrint<>(10,20);//强制调用模板函数 
    myPrint(10,20,30);//调用重载的函数模板 
    myPrint('a','b');//函数模板更匹配 
    return 0;
}

1.2.5 模板的局限性

局限性:
模板通用性不是万能的

class Person
{
public:
    Person(string n,int a):name(n),age(a){}
    string name;
    int age;    
} ;

template<class T>
bool myCompare(T &a,T &b)
{
    if(a == b)//无法比较Person类 
        return true;
    return false;
}
//利用具体化Person的版本实现代码,具体化优先调用 
template<> bool myCompare(Person &a,Person &b)
{
    if(a.age == b.age && a.name == b.name)
        return true;
     
     return false;
}

void test1()
{
    Person p1("Tom",10);
    Person p2("Tom",10);
    myCompare(p1,p2);
}
  • 利用具体化的模板,可以解决自定义类型的通用化
  • 学习模板并不是为了写模板,而是在STL能够运用系统提供的模板

1.3 类模板

1.3.1 类模板语法

类模板的作用:

  • 建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟的类型来代表

语法:

template <typename T>
类
template <typename T,typename P>
class Person
{
public:
    Person(T n,P a):name(n),age(a){}
    T name;
    P age;  
};
int main() {
    Person<string,int> p1("Tom",10);
    cout<<p1.name<<" "<<p1.age<<endl;
    return 0;
}

1.3.2 类模板与函数模板的区别

  • 1.类模板没有自动类型推导的使用方式,必须显示指定类型
  • 2.类模板在模板参数列表中可以有默认参数
template <typename T,typename P = int>//默认整型 
class Person
{
public:
    Person(T n,P a):name(n),age(a){}
    T name;
    P age; 
};
int main(int argc, char** argv) {
    Person<string,int> p1("tom",10);
    Person<string> p2("tom",10);//<>里面的int可以省略 
    return 0;
}

1.3.3 类模板中 成员函数的创建时机

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才创建

1.3.4 类模板对象做函数参数

  • 1.指定传入的类型 --- 直接显示对象的数据类型
  • 2.参数模板化 --- 将对象中的参数变为模板进行传递
  • 3.整个类模板化 --将这个对象类型 模板化进行传递
template <class T,class P> 
class Person
{
public:
    Person(T n,P a):m_age(a),m_name(n){}
    void showPerson()
    {
        cout<<this->m_name<<" "<<this->m_age<<endl;
    }
    
    T m_name;   
    P m_age;
};
//1.指定传入的类型
void printPerson1(Person<string,int> &p)
{
    p.showPerson();
}
void test1() 
{
    Person<string,int> p1("tom",10);
    printPerson1(p1);
}

//2.参数模板化 
template<class T ,class P>
void printPerson2(Person<T,P> &p)
{
    p.showPerson();
}
void test2() 
{
    Person<string,int> p1("tom2",10);
    printPerson2(p1);
}

//3.整个类模板化 
template<class T>
void printPerson3(T &p)
{
    p.showPerson();
}
void test3() 
{
    Person<string,int> p1("tom3",10);
    printPerson3(p1);
}

1.3.5 类模板与继承

  • 当子继承的父类时一个类模板时,子类在声明的时候,要指定父类中T的类型
  • 如果不指定,编译器无法为子类分配内存
  • 如果想灵活指定父类中T的类型,子类也需要变成类模板
template <class T>
class Base
{
public:
    T a;    
};

class Son : public Base<int>//指定类型 
{
    
};

template<class T1,class T2>
 class Son2 : public Base<T2>//灵活指定类型 
 {
    T1 obj;
 };

1.3.6 类模板成员函数类外实现

类模板中的成员函数类外实现时,需要加上模板参数列表

template <class T1,class T2>
class Person
{
public:
    Person(T1 n,T2 a);
    void show();
    T1 m_name;
    T2 m_age;
};

template <class T1,class T2>
Person<T1,T2>::Person(T1,T2)
{
    
}

template <class T1,class T2>
void Person<T1,T2>::show()
{
    
}

1.3.7 类模板分文件编写

问题:

  • 类模板成员函数创建时机是在调用阶段,导致分文件编写时链接不到
    解决:
  • 解决方式1:直接包含cpp文件
  • 解决方式2:将声明和实现写到同一个文件红,然后改后缀名为hpp,hpp是约定的名称,非强制!
    Person.h
#include <iostream>
#include <string>
using namespace std;

template <class T1,class T2>
class Person
{
public:
    Person();
    Person(T1 name,T2 age);
    ~Person();
    void showPerson();
    
    T1 name;
    T2 age;
};

Person.cpp

#include "Person.h"


template <class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
    this->name = name;
    this->age = age;
}

template <class T1,class T2>
Person<T1,T2>::~Person()
{
}

template <class T1,class T2>
void Person<T1,T2>::showPerson()
{
    cout<<name<<" "<<age<<endl;
}

main.cpp

  • 解决方式1:直接包含cpp文件 很少这么做
//#include "Person.h" //类模板的成员函数编译时不会创建,因此会找不到引用
#include "Person.cpp" //* 解决方式1:直接包含cpp文件
void test()
{
    Person<string,int> p("tom1",18);
    p.showPerson();
} 
int main() {
    test(); 
    return 0;
}
  • 解决方式2:将.h和.cpp中的内容写到一起,将后缀名改为hpp,非强制!
    Person.hpp
#include <iostream>
#include <string>
using namespace std;

template <class T1,class T2>
class Person
{
public:
    Person();
    Person(T1 name,T2 age);
    ~Person();
    void showPerson();
    
    T1 name;
    T2 age;
};

template <class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age)
{
    this->name = name;
    this->age = age;
}

template <class T1,class T2>
Person<T1,T2>::~Person()
{
}

template <class T1,class T2>
void Person<T1,T2>::showPerson()
{
    cout<<name<<" "<<age<<endl;
}

main.cpp

#include "Person.hpp" //* 解决方式2:直接包含hpp文件
void test()
{
    Person<string,int> p("tom1",18);
    p.showPerson();
} 
int main() {
    test(); 
    return 0;
}

1.3.8 类模板和友元

  • 全局函数在类内实现:直接在类内声明友元,实现函数即可
  • 全局函数在类外实现:需要提前让编译器知道全局函数的存在(比较麻烦的写法)
template <class T1,class T2>
class Person;
          
//提前让编译器知道全局函数
template<class T1,class T2>
void printPerson2(Person<T1,T2> p)
{
    cout<<p.name<<" "<<p.age<<endl;
}

template <class T1,class T2>
class Person
{
    //1. 全局函数 类内实现 
    friend void printPerson(Person<T1,T2> p)
    {
        cout<<p.name<<" "<<p.age<<endl;
    }
    //2.全局函数 类外实现
    //加空模板参数列表<> 
    friend void printPerson2<>(Person<T1,T2>p);//不加<>就是普通函数,加了<> 就是函数模板 
public:
    Person(T1 n,T2 a):name(n),age(a)
    {
        
    }
private:
    T1 name;
    T2 age;
};
void test1()
{
    Person<string,int> p("Tom",18);
    printPerson(p);
}

void test2()
{
    Person<string,int> p("Tom2",18);
    printPerson2(p);
}

1.3.9 类模板案例

MyArray .hpp

#pragma once
#include <iostream>
using namespace std;

template <class T>
class MyArray {
    public:
        //有参构造 参数 容量
        MyArray(int capacity) {
            cout<<"MyArray(int capacity) is call" <<endl;
            this->pAddress = new T[capacity];
            this->m_Capacity = capacity;
            this->m_Size = 0;
        }
        //拷贝构造-防止浅拷贝
        MyArray(MyArray &arr) {
            cout<<"MyArray(MyArray &arr) is call" <<endl;
            this->m_Capacity = arr.m_Capacity;
            this->m_Size = arr.m_Size;
            //this->pAddress = arr.pAddress;//编译器默认实现
            this->pAddress = new T[arr.m_Capacity]; //深拷贝
            //将arr的数据拷贝过来
            for (int i = 0; i < arr.m_Size; i++) {
                this->pAddress[i] = arr.pAddress[i];
            }
        }

        //重载= 防止浅拷贝问题
        MyArray& operator=(const MyArray &arr) {
            cout<<"MyArray& operator=(const MyArray &arr) is call" <<endl;
            //先判断原来堆区是否有数据,如果有先释放
            if (this->pAddress != NULL) {
                delete[] this->pAddress;
                this->pAddress = NULL;
                this->m_Size = 0;
                this->m_Capacity = 0;
            }
            //深拷贝
            this->m_Capacity = arr.m_Capacity;
            this->m_Size = arr.m_Size;
            this->pAddress = new T[arr.m_Capacity];
            //将arr的数据拷贝过来
            for (int i = 0; i < arr.m_Size; i++) {
                this->pAddress[i] = arr.pAddress[i];
            }
        }
        //析构函数
        ~MyArray() {
            cout<<"~MyArray() is call" <<endl;
            if (this->pAddress != NULL) {
                delete[] this->pAddress;
                this->pAddress = NULL;
            }
        }
    private:
        T * pAddress;//指针指向堆区开辟的真实数组
        int m_Capacity;//数组容量
        int m_Size;//数组大小
};
void test1()
{
    MyArray<int> arr1(5);
    MyArray<int> arr2(arr1);
    MyArray<int> arr3(100);
    arr3 = arr1;
}

2.STL

2.1 STL的诞生

  • 长久以来,软件界一直希望建立一种可重复利用的东西
  • C++的面向对象泛型编程思想,目的就是为了提升复用性
  • 大多数情况下,数据结构和算法都没有一套标准的代码,因此STL就诞生了

2.2 SLT的基本概念

  • STL(Standard Template Library.标准模板库)
  • STL从广义上分为:容器算法迭代器
  • 容器算法之间通过迭代器进行无缝连接
  • STL几乎所有的代码都采用了模板类和模板函数

2.3 SLT六大组件

分别是:容器、算法、迭代器、仿函数、适配器、空间配置器

1.容器:各种数据结构,如vector、list、deque、set、map等
2.算法:各种常用的算法:如sort、find、copy、for_each等
3.迭代器:容器和算法沟通的桥梁
4.仿函数:行为类似函数。可作为算法的某种策略
5.适配器:用来修饰容器或者仿函数或者迭代器接口的东西
6.空间配置器:负责空间的配置与管理

2.4 STL中容器、算法、迭代器
1.容器:各种数据结构,如vector、list、deque、set、map等
2.算法:各种常用的算法:如sort、find、copy、for_each等
3.迭代器:容器和算法沟通的桥梁

迭代器的种类:

种类 功能 支持运算
输入迭代器 只读 只读,支持++、==、!=
输出迭代器 只写 只写,支持++
前向迭代器 读写 ,并能向前推进 读写,支持++、==、!=
双向迭代器 读写,并能向前和向后操作 读写写,支持++、--
随机访问迭代器 读写,能任意访问 读写,支持++ 、--、[n]、-n、<、<=、>、>=

2.5 容器算法迭代器

2.5.1 vector存放内置数据类型

容器:vector
算法:for_each
迭代器:vector<int>::iterator

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std; 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void myPrint(int val)
{
    cout<<val<<endl;
} 
void test()
{
    //1.创建一个容器 
    vector<int> v;
    //2.插入数据
    v.push_back(10);
    v.push_back(20);
    v.push_back(30); 
    //通过迭代器访问
    vector<int>::iterator itBegin = v.begin();//起始迭代器,指向容器第一个元素
    vector<int>::iterator itEnd = v.end();//结束迭代器,指向容器最后一个元素的下一个位置 
    //第一种遍历方式
    while(itBegin != itEnd)
    {
        cout<<*itBegin++<<endl;
    } 
    //第二种遍历方式
    for(vector<int>::iterator it = v.begin();it!=v.end();it++)
    {
        cout<<*it<<endl; 
    }
    //第三种遍历方式,STL提供的标准遍历
    for_each(v.begin(),v.end(),myPrint);
    
}

int main(int argc, char** argv) {
    test();
    return 0;
}

2.5.2 vector存放自定义数据类型

class Person
{
public:
    Person(string n,int a):name(n),age(a){}
    string name;
    int age;    
};

void myPrint(Person p)
{
    cout<<p.name<<" "<<p.age<<endl;
}

void myPrint2(Person *p)
{
    cout<<p->name<<" "<<p->age<<endl;
}
//存放自定义数据类型 
void test1()
{
    vector<Person> v;
    Person p1("a",10);
    Person p2("b",20);
    Person p3("c",30);
    Person p4("d",40);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    //方式1 遍历 
    for(vector<Person>::iterator it = v.begin();it!=v.end();it++)
    {
        cout<<(*it).name<<" "<<(*it).age<<endl;
        cout<<it->name<<" "<<it->age<<endl;     
    } 
    //方式2 遍历
    for_each(v.begin(),v.end(),myPrint); 
}
//存放 自定义数据类型 指针
void test2()
{
    vector<Person*> v;
    Person p1("a",10);
    Person p2("b",20);
    Person p3("c",30);
    Person p4("d",40);
    v.push_back(&p1);
    v.push_back(&p2);
    v.push_back(&p3);
    v.push_back(&p4);
    //方式1 遍历 
    for(vector<Person*>::iterator it = v.begin();it!=v.end();it++)
    {
        cout<<(*it)->name<<" "<<(*it)->age<<endl;
    } 
    //方式2 遍历
    for_each(v.begin(),v.end(),myPrint2); 
} 

2.5.3 vector嵌套容器

//容器嵌套容器
 void test()
 {
    //1.创建大容器
     vector<vector<int>> v;
    //2.创建小容器
    vector<int> v1; 
    vector<int> v2; 

    //小容器赋值
    for(int i=0;i<2;i++)
    {
        v1.push_back(i+1);
        v1.push_back(i+1);
        v1.push_back(i+1);
        
        v2.push_back(i+2);
        v2.push_back(i+2);
        v2.push_back(i+2);
    } 
    //大容器赋值
    v.push_back(v1);
    v.push_back(v2);
    //遍历数据
    for(vector<vector<int>>::iterator it = v.begin();it != v.end();it++)
    {
        for(vector<int>::iterator vit = it->begin();vit!=it->end();vit++)
        {
            cout<<*vit<<" ";
        }
        cout<<endl;
    } 
      
 }
int main(int argc, char** argv) {
    test();
    return 0;
}

3.1 string容器

3.1.1 string基本概念

本质:

  • string是c++的字符串,本质上是一个类

string和char*的区别

  • char *是一个指针
  • string是一个类,内部封装了char指针,管理字符串,是一个char类型的容器

特点:
string类内封装了很多成员方法,如find,copy,delete等。
string管理char*所分配的内存,不用担心复制越界和取值越界问题,都类内部进行负责

3.1.2 string构造函数

  • string():创建一个空的字符串,例如string s;
  • string(const char *s):使用字符串s初始化
  • sting(const string& str):使用string对象初始化
  • string(int n,char c):使用n个字符c初始化

省略string的一些内容···

3.2 vector容器

3.2.1 vector基本概念

  • vector数据结构和数组非常相似,也称为单端数组
  • vector可以动态扩展空间,数组是空间是不可变的
  • vector容器的迭代器支持随机访问

动态扩展:

  • 并不是原空间之后申请新的空间,而是找到更大的内存空间,然后将原有数据拷贝到新空间,释放原空间。

3.2.2 vector构造函数

函数原型:

  • vector<T> v:默认构造
  • vector(v.begin(),v.end()):将v.begin()到v.end()中的元素拷贝给自己
  • vector(n,elem):把n个elem拷贝给自己
  • vector(const vector &vec):拷贝构造函数

3.3 deque容器

3.4 stack容器-栈

3.5 queue-队列

3.6 list容器-双向循环链表

3.7 set/multiset容器-二叉树

3.8 map/multimap容器


4.STL-函数对象

4.1 函数对象

4.1.1函数对象的概念

概念

  • 重载函数调用操作符的类,其对象常常称为函数对象
  • 函数对象使用重载的()时,行为类似函数调用,也成为仿函数

本质:
函数对象(仿函数)是一个类,不是函数

4.1.2 函数对象的使用

特点:

  • 函数对象在使用时,可以像普通函数那样调用,可以有参数和返回值
  • 函数对象可以有自己的状态
  • 函数对象可以作为参数传递
class MyAdd
{
public:
    int operator()(int a,int b)
    {
        return a+b;
    }   
} ;
//1. 函数对象在使用时,可以像普通函数那样调用,可以有参数和返回值
void test1()
{
    MyAdd add;
    cout<<add(1,2)<<endl;
}

//2. 函数对象可以有自己的状态
class MyPrint
{
public:
    MyPrint():count(0){}
    void operator()(string s)
    {
        count++;
        cout<<"第"<<count<<"次打印:"<<s<<endl;
    }
    
    int count;//内部自己的状态,记录调用次数 
};

void test2()
{
    MyPrint mp;
    mp("hello");
    mp("hello");
    mp("hello");
    mp("hello");
}

//3. 函数对象可以作为参数传递
void doPrint(MyPrint &mp,string s)
{
    mp(s);
}
void test3()
{
    MyPrint mp;
    doPrint(mp,"22222");
}

4.2 谓词

4.2.1 谓词的概念

概念:

  • 返回bool的类型的仿函数称为 谓词
  • 如果operator()接受1个参数,称为 一元谓词
  • 如果operator()接受2个参数,称为 二元谓词

4.2.2 一元谓词

//1.一元谓词
class GreterFive {
    public:
        bool operator()(int v) {
            return v > 5;
        }
};
void test1() {
    vector<int> v;
    for (int i = 0; i < 10; i++)
        v.push_back(i);
    //查找大于5的值,这里 new GreterFive()是一个匿名对象
    vector<int>::iterator it = find_if(v.begin(), v.end(), GreterFive());
    if (it == v.end()) {
        cout << "没有找到大于5的值" << endl;
    } else {
        cout<<"找到大于5的值:"<<*it<<endl;
    }
}

4.2.3 二元谓词

//二元谓词
class Mycompare
{
public:
    bool operator()(int v1,int v2)
    {
        return v1>v2;
    }   
};
void test()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(20);
    v.push_back(50);
    Mycompare m;
    sort(v.begin(),v.end(),m);
    //sort(v.begin(),v.end(),Mycompare());// Mycompare()是匿名对象 
    for(vector<int>::iterator it = v.begin();it!=v.end();it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;
}

4.3 内建函数对象

4.3.1 概念

概念:

  • STL内建了一些函数对象
    分类:
  • 算术仿函数
  • 关系仿函数
  • 逻辑仿函数
    用法:
  • 这些仿函数所产生的对象,用法和一般函数完全相同
  • 使用内建函数对象,需要引入头文件<functional>

4.3.2 算术仿函数

功能描述:

  • 实现四则运算
  • 其中negate是一元运算,其他都是二元运算

仿函数原型

  • template<class T> plus<T> //加法仿函数
  • template<class T> minus<T>//减法仿函数
  • template<class T> multiplies<T>//乘法仿函数
  • template<class T> divides<T>//除法仿函数
  • template<class T> modulus<T> //取模仿函数
  • template<class T> negate<T>//取反仿函数
//1.取反仿函数 
void test1()
{
    negate<int> n;
    std::cout<<n(50)<<endl; 
}
//2.加法仿函数 
void test2()
{
    plus<int> p;
    std::cout<<p(50,50)<<endl; 
} 
int main(int argc, char** argv) {
    test1();
    test2();
    return 0;
}

4.3.3 关系仿函数

仿函数原型:

  • template<class T >bool equal_to<T> //等于
  • template<class T >bool not_equal_to<T> //不等于
  • template<class T >bool greater<T> //大于
  • template<class T >bool greater_equal<T> //大于等于
  • template<class T >bool less <T> // 小于
  • template<class T >bool less_equal<T> //小于等于
#include <iostream>
#include <vector>
#include<algorithm>
#include <functional>
using namespace std; 
void test()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(40);
    v.push_back(20);

    sort(v.begin(),v.end(),greater<int>());
    for(vector<int>::iterator it= v.begin() ;it!=v.end();it++)
    {
        cout<<*it<<" ";
    } 
    cout<<endl; 
    
}

4.3.4 逻辑仿函数

函数原型:

  • template <class T> bool logical_and<T> //逻辑与
  • template <class T> bool logical_or<T> //逻辑或
  • template <class T> bool logical_not<T> //逻辑非

5.STL-常用算法


概述:

  • 算法主要由头文件 <algorithm>、<functional>、<numeric>组成

5.1 常用遍历算法

  • for_each //遍历容器
  • transform //搬运容器到另一个容器中

5.1.1 for_each

函数原型:

  • for_each(iterator beg,iterator end,_func);
//普通函数
void myPrint(int v)
{
    cout<<v<<" ";
}
//仿函数
class MyPrint2
{
public:
    void operator()(int v)
    {
        cout<<v<<" ";
    }   
} ;
void test()
{
    vector<int> v;
    for(int i=0;i<5;i++)
        v.push_back(i);
    for_each(v.begin(),v.end(),myPrint);
    cout<<endl;
    for_each(v.begin(),v.end(),MyPrint2());
}

5.1.2 transform

功能:

  • 将一个容器的内容搬运到另一个容器
    函数原型:
  • transform(iterator beg1,iterator end1,iterator beg2,_func)
    • beg1 源容器开始迭代器
    • end1 源容器结束迭代器
    • beg2 目标容器开始迭代器
    • _func 函数或者函数对象(仿函数)
class MyTransform
{
public:
    int operator()(int v)
    {
        return v;
    }
};

void test()
{
    vector<int> v;
    for(int i=0;i<5;i++)
    {
        v.push_back(i);
    }
    
    vector<int> vTarget;
    vTarget.resize(v.size());//一定要开辟空间,不能用reserve 
    
    transform(v.begin(),v.end(),vTarget.begin(),MyTransform());
    for(vector<int>::iterator it = v.begin();it!=v.end();it++)
    {
        cout<<*it<<" ";
    } 
    cout<<endl;
    for(vector<int>::iterator it = vTarget.begin();it!=vTarget.end();it++)
    {
        cout<<*it<<" ";
    }           
}

5.2 常用的查找算法

  • find
  • find_if
  • adjacent_find
  • binary_search
  • count
  • count_if

5.3常用的排序算法

  • sort
  • random_shuffle 随机打乱元素
  • merge
  • reverse

5.4 常用的拷贝和替换算法

  • copy
  • replace
  • replace_if
  • swap

5.5 常用的算术生成算法

头文件:#include <numeric>

  • accumulate 计算容器内所有元素的总和
  • fill 向容器内填充元素

5.6 常用的集合算法

  • set_intersection 求两个容器的交集
  • set_union 求两个容器的并集
  • set_difference 求两个容器的差集

继续当一名咸鱼( ̄︶ ̄)!

Stay hungry,Stay foolish!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容