C/C++教程

C++基础知识

本文主要是介绍C++基础知识,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

浅拷贝和深拷贝

浅拷贝:简单的赋值拷贝操作;会出现堆区内存重复释放的问题;

深拷贝:在堆区中重新申请内存空间,进行操作;

深拷贝语句:

 Person(const Person &p)
    {
        cout << "拷贝构造函数" << endl;
        age = p.age;
        // 深拷贝
        height = new int(*p.height); // 核心部分
    }

    ~Person()
    {
        // 析构函数将堆区开辟的数据做释放操作
        if (height != NULL)
        {
            delete height;
            height = NULL; // 防止野指针
        }
        cout << "析构函数" << endl;
    }

加号运算符重载

class Person
{
public:
    // 成员函数
    Person operator+(Person &p)
    {
        Person temp;
        temp.a = this->a + p.a;
        temp.b = this->b + p.b;
        return temp;
    }
    int a;
    int b;
};

void test01()
{
    Person p1;
    p1.a = 10;
    p1.b = 10;

    Person p2;
    p2.a = 10;
    p2.b = 10;

    Person p3 = p1 + p2;
    cout << p3.a << p3.b << endl;
}

左移运算符重载

左移运算符重载只能时全局函数,千万不要写成成员函数,如果想访问私有的数据成员,可以将重载函数声明为该类的友元函数

不会利用成员函数重载<<运算符,因为无法实现cout在左侧

// 全局函数
// 返回值时引用类型的
ostream &operator<<(ostream &cout, Person &p) // 做成友元函数即可
{
    cout << "a=" << p.a << " b=" << p.b;
    return cout; // 使用了链式编程思想
}

递增运算符重载(++)

前置++

// 成员函数 
// 重载前置++运算符
    MyInteger operator++()
    {
        // 先++
        m++;
        // 再返回
        return *this;
    }

后置++

// 重载后置++运算符
    //这个int代表一个占位参数,用于区分前置和后置递增
    MyInteger operator++(int)
    {
        // 先记录当时的结果
        MyInteger temp = *this;
        // 再++
        m++;
        // 最后将记录结果返回
        return temp;
    }

赋值运算符的重载

c++编译器至少给一个类提供4个函数

1.默认的构造函数(无参,函数体为空)

2.默认的析构函数(无参,函数体为空)

3.默认的拷贝构造函数,对属性进行值拷贝

4.赋值运算符operator=,对属性进行值拷贝

// 成员函数

Person &operator=(Person &p)
    {
        // 判断是否有属性在堆区,然后再释放,然后再拷贝
        if (age != NULL)
        {
            delete age;
            age = NULL;
        }
        age = new int(*p.age);
        return *this;
    // *解引用
    }

int *age;

关系运算符的重载

// 成员函数
bool operator==(Person &p)
    {
        if (this->name == p.name && this->age == p.age)
        {
            return true;
        }
        return false;
    }
    bool operator!=(Person &p)
    {
        if (this->name != p.name && this->age != p.age)
        {
            return true;
        }
        return false;
    }




函数调用运算符重载

  • 函数调用运算符()也可以重载
  • 由于重载后使用的方式非常像函数的调用,因此称为仿函数
  • 仿函数没有固定的方法,非常灵活
class MyPrint
{
public:
    void operator()(string test) // 类似于函数的使用,称为仿函数
    {
        cout << test << endl;
    }
};

void MyPrint02(string test)
{
    cout << test << endl;
}

// Example2
class myAdd
{
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};
void test02()
{
    myAdd add;
    add(10, 20);
    cout << myAdd()(10, 10); // 匿名(函数)对象 
}
void MyPrint02(string test)
{
    cout << test << endl;
}

查看对象模型

  1. 打开Developer Command Prompt for vs 2019
  2. 盘符名称加:跳转至文件位置
  3. cd[sapce] 文件名进入文件
  4. dir显示文件夹中的所有文件
  5. 使用命令cl /d1 reportSingleClassLayout[类名][space][文件名]

继承的同名成员处理

子类对象加作用域可以访问到父类同名成员;

如果子类中出现了和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数;

如果想访问到父类被隐藏的同名成员函数,需要加作用域;

#include <iostream>
using namespace std;
class Base
{
public:
    Base()
    {
        a = 100;
        cout << "b构造函数" << endl;
    }
    void func()
    {
        cout << "base " << endl;
    }
    void func(int a)
    {
        cout << "1000000" << endl;
    }
    int a;
};

class Son : public Base
{
public:
    Son()
    {
        a = 200;
        cout << "s构造函数" << endl;
    }
    void func()
    {
        cout << "son " << endl;
    }

    int a;
};
void test01()
{
    // Base b;
    Son s;
    cout << s.Base::a;
}
void test02()
{
    Son s;
    s.Base::func(100);
}
int main()
{
    test02();
}

继承同名静态成员处理方式

  1. 处理方式和继承同名成员处理方式相同;

  2. 可以直接通过类名的方式直接访问,不需要创建对象;

  3. cout << Son::Base::a;
    //第一个::代表通过类名的方式访问 第二个::代表访问父类的作用域下
    

静态多态和动态多态的区别:

静态多态的函数地址早绑定 - 编译阶段确定函数地址;

动态多态的函数地址晚绑定 - 运行阶段确定函数地址;

动态多态的满足条件

  1. 有继承的关系;
  2. 重写父类中的基函数;

动态多态的使用

父类的指针或引用 ,执行子类对象;


纯虚函数和抽象类

只要有一个纯虚函数,这个类称为抽象类

抽象类特点:

  1. 无法实现实例化对象;

  2. 抽象类的子类,必须重写父类中的纯虚函数,否则也属于抽象类也无法实例化对象;


虚析构和纯虚析构

问题:

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码;

解决方式:

将父类中的析构函数改为虚析构或者是纯虚析构;

共性:

可以解决父类指针释放子类对象;

都需要有具体的函数实现;

区别:

如果是纯虚析构,该类属于抽象类,无法实例化对象;

// 虚析构
virtual ~类名(){}

// 纯虚析构
virtual ~类名()=0;

例子:

#include <iostream>
#include <string>
using namespace std;

class Animal
{
public:
    virtual void speak() = 0;
    Animal()
    {
        cout << "Animal构造函数" << endl;
    }
    // 虚析构可以解决,父类指针释放子类对象是不干净的问题

    virtual ~Animal() = 0;
};
// 需要声明,也需要实现;
// 有了纯虚析构函数,也个类也是抽象类,无法实现对象实例化
Animal::~Animal()
{
    cout << "Animal纯需构造函数" << endl;
}

class Cat : public Animal
{
public:
    Cat(string name)
    {
        cout << "Cat构造函数" << endl;

        this->name = new string(name);
    }
    void speak()
    {
        cout << *name << ": 喵喵喵~~~~~" << endl;
    }
    string *name;
    ~Cat()
    {
        cout << "Cat析构函数" << endl;

        if (name != NULL)
        {
            delete name;
            name = NULL;
        }
    }
};

void test01()
{
    Animal *a = new Cat("Tom");
    a->speak();
    // 父类的指针在析构时候,不会调用子类中的析构函数,导致子类如果没有堆区属性,出现内存泄漏

    delete a;
}

int main()
{
    test01();
}

总结:

  1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象;
  2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构;
  3. 拥有纯虚析构的类也属于抽象类;

文件操作

C++中对文件操作需要包含头文件<fstream>

<ofstream>:写操作

<ifstream>:读操作

<fstream>:读写操作

写文件步骤:

  1. 包含头文件

    #iclude <fstream>

  2. 创建流对象

    ofstream ofs;

  3. 打开文件

    ofs.open(“文件路径”,打开方式);

  4. 写数据

    ofs<<“写入数据”:

  5. 关闭文件

    ofs.close();

文件的打开方式:

打开方式解释
ios::in为读文件而打开文件
ios::out为写文件而打开文件
ios::ate初始位置:文件末尾
ios::app追加方式写文件
ios::trunc如果文件存在先删除,在创建
ios::binary二进制方式

注意:文件的打开方式可以配合使用,利用|操作符;


文件读入的四种方式

利用is_open函数可以判断文件是否打开;

第一种:

 char buf[1024] = {0};

     while (fin >> buf)
     {
        cout << buf << endl;
     }

第二种:

   char buf[1024] = {0};
     while (fin.getline(buf, sizeof(buf)))
     {
         cout << buf << endl;
     }

第三种:

  string buf;
     while (getline(fin, buf))
     {
         cout << buf << endl;
     }

第四种:

 char c;
    while ((c = fin.get()) != EOF) 
    {
        cout << c;
    }
fin.close(); // 读完文件要关闭文件

EOF: End Of File;


普通函数与函数模板调用规则

  1. 如果函数模板和普通函数都可以调用,要先调用普通函数
  2. 可以通过空模板参数列表强制调用函数模板
  3. 函数模板可以发生函数重载
  4. 如果函数模板可以更好的匹配,优先调用函数模板

模板具体化

#include <iostream>
using namespace std;

class Person
{
public:
    Person(string name, int age)
    {
        m_name = name;
        m_age = age;
    }
    string m_name;
    int m_age;
};
template <typename T>
bool myCompare(T &a, T &b)
{
    if (a == b)
    {
        return true;
    }
    else
    {
        return false;
    }
}
// 利用具体化的Person的版本来实现代码具体化会优先调用
template <>
bool myCompare(Person &a, Person &b)
{
    if (a.m_name == b.m_name && a.m_age == b.m_age)
    {
        return true;
    }
    return false;
}

void test01()
{
    int a = 10;
    int b = 20;
    bool result = myCompare(a, b);
    if (result)
    {
        cout << "a==b" << endl;
    }
    else
    {
        cout << "a!=b" << endl;
    }
}
void test02()
{
    Person p1("Tom", 10);
    Person p2("Tom", 10);
    bool result = myCompare<Person>(p1, p2);
    if (result)
    {
        cout << "p1==p2" << endl;
    }
    else
    {
        cout << "p1!=p2" << endl;
    }
}
int main()
{
    test02();
}

类模板和函数模板的区别

  1. 类模板没有自动类型推导的使用方式;
  2. 类模板在模板参数列表中可以有默认参数;

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

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

类模板对象做函数参数

  1. 指定传入的类型 – 直接显示对象的数据类型
  2. 参数模板化 – 将对象中的参数变为模板进行传递
  3. 整个类模板化 – 将这个对象类型模板化进行传递

类模板与继承

  • 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定出父类中T的类型,子类也要变为类模板

类模板成员函数类外实现

#include <iostream>
using namespace std;

template <class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age)
    {
        // this->m_name = name;
        // this->m_age = age;
    }
    T1 m_name;
    T2 m_age;
    void showPerson()
    {
        cout << this->m_name << this->m_age << endl;
    }
};
template <class T1, class T2>
void Person<T1, T2>::showPerson()
{
}

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

Vector

数据类型vector<数据类型> 变量名

使用的头文件:

#include <vector>

#include <algorithm> // 标准算法的头文件

方法:

变量名.push_back(数据) // 尾插法
变量名.begin() // 迭代器的第一个元素
变量名.end() // 迭代器的最后一个元素的下一个位置

三种遍历方法:

#include <iostream>
#include <vector>
#include <algorithm> // 标准算法的头文件
using namespace std;

void test01()
{
    vector<int> v;

    // 向容器中插入数据
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);

    // 通过迭代器访问容器中的数据
    // 起始迭代器,指向容器中的第一个元素
    
    vector<int>::iterator itBegin = v.begin();
    // 指向最后一个元素的下一个位置
    vector<int>::iterator itEnd = v.end();
    while (itBegin != itEnd)
    {
        cout << *itBegin << endl;
        itBegin++;
    }
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << endl;
    }
    // 起始 终止 函数
    for_each(v.begin(), v.end(), myPrint); // for_each使用头文件#include <algorithm>
}

void myPrint(int val)
{
    cout << val << endl;
}
int main()
{
    test01();
    return 0;
}

vector存储自定义数据类型:

void test02()
{
    vector<Person *> v; // 存储指针 一般数据类型是去掉指针

    Person p1("aa", 18);
    Person p2("bb", 18);
    Person p3("cc", 18);
    Person p4("dd", 18);
    Person p5("ee", 18);

    v.push_back(&p1);
    v.push_back(&p2);
    v.push_back(&p3);
    v.push_back(&p4);
    v.push_back(&p5);

    for (vector<Person *>::iterator it = v.begin(); it != v.end(); it++)
    {
        // it的数据类型取决于<>中的数据类型
        cout << "name = " << (*it)->m_name << "; age = " << (*it)->m_age << endl;
        // cout << "name = " << it->m_name << "; age = " << it->m_age << endl;
    }
}


Control typeIDCaptionfunction
CDialongDemo
CStaticIDC_TXTI am Waiting….
CButtonBTN_GENClickgen

DLL:Dynamic Linked library


容器嵌套容器

void test01()
{
    vector<vector<int> > v;

    vector<int> v1;
    vector<int> v2;
    vector<int> v3;
    vector<int> v4;

    for (int i = 0; i < 4; i++)
    {
        v1.push_back(i + 1);
        v2.push_back(i + 2);
        v3.push_back(i + 3);
        v4.push_back(i + 4);
    }

    v.push_back(v1);
    v.push_back(v2);
    v.push_back(v3);
    v.push_back(v4);
    for (vector<vector<int> > ::iterator it = v.begin(); it != v.end(); it++)
    {
        for (vector<int>::iterator it2 = (*it).begin(); it2 != (*it).end(); it2++)
        {
            cout << *it2;
        }
        cout << endl;
    }
}

String容器

string构造函数

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

string 赋值操作

string& operator=(const char* s); //char*类型字符串赋值当前的字符串
string& operator=(const string &s); // 把字符串s赋值给当前的字符串
string& operator=(char c); // 字符赋值给当前的字符串

string& assign(const char* s); // 把字符串s赋值给当前的字符串
string& assign(const char* s, int n); // 把字符串s的前n个字符赋值给当前的字符串
string& assign(const string &s); // 把字符串s赋值给当前字符串
string& assign(int n,char c); // 把n个字符c赋给当前字符串

string字符串拼接

string& operator+=(const char* s); // 重载+=操作符
string& operator+=(const string &s); // 重载+=操作符
string& operator+=(const char c); // 重载+=操作符

string& append(const char* s); // 把字符串s连接到当前字符串结尾
string& append(const char* s, int n); // 把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s); // 同operator+=(const string &str)
string& append(const string &s,int pos,int n); // 字符串s中从pos开始的n个字符连接到字符串结尾

string查找和替换

int find(const string& str,int pos = 0) const; // 查找str第一次出现位置,从pos开始查找
int find(const char* s,int pos = 0) const; // 查找s第一次出现位置,从pos开始查找
int find(const char* s,int pos, int n) const; // 从pos位置查找s的前n个字符第一次位置
int find(const char s,int pos = 0) const; // 查找字符c第一次出现位置

int rfind(const string& str,int pos = npos) const; // 查找str最后一次位置,从pos开始查找
int rfind(const char* s,int pos = npos) const; // 查找s最后一次出现位置,从pos开始查找
int rfind(const  char* s,int pos, int n) const; // 从pos查找s的前n个字符最后一次位置
int rfind(const char c,int pos = 0) const; // 查找字符c最后一次出现位置

string& replace(int pos, int n, const string& str) const; // 替换从pos开始n个字符为字符串str
string& replace(int pos, int n, const char* c) const; // 替换从pos开始的n个字符为字符串s

string比较

比较方式:

字符串比较是按字符的ASCLL码进行对比

相等:返回0;

大于:返回1;

小于:返回-1;

int compare(const string &s) const;
int compare(const char* s) const;

string字符存取

char& operator[](int n); // 通过[]方式取字符
char& at(int n); // 通过at方法获取字符

string插入和删除

string& insert(int pos, const char* s); // 从pos插入字符串
string& insert(int pos, const string* str); // 从pos插入字符串
string& insert(int pos, int n, char c); // 在指定位置插入n个字符c
string& erase(int pos, int n = npos); // 删除从Pos开始的n个字符

string子串

string substr(int pos = 0, int n = npos) const; // 返回由pos开始的n个字符组成的字符串

vector容器

使用时包含头文件:#include <vector>

vector与普通数组区别:

数组是静态的,而vector可以动态扩展;

动态扩展:

并不是在原有空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间;

vector容器的迭代器是支持随机访问的迭代器;

vector构造函数

vector<T> v; // 采用模板实现类实现,默认构造函数
vector(v.begin(), v.end()); // 将v[begin(), end()]区间中的元素拷贝给本身
vector(n, elem);  // 构造函数将n个elem拷贝给本身
vector(const vector &vec); // 拷贝构造函数

vector赋值操作

vector& operator=(const vector &vec); // 重载赋值运算符
assign(beg, end);  // 将[beg, end] 区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身

vector容量和大小

empty(); // 判断容器是否为空
capacity(); // 容器的容量
size(); // 返回容器中的元素个数
resize(int num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(int num,elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

vector插入和删除

push_back(ele); // 尾部插入元素ele
pop_back(); // 删除最后一个元素
insert(const_iterator pos, ele); // 迭代器指向位置pos插入元素ele
insert(const_iterator pos, int count, ele); // 迭代器指向位置pos插入count个元素ele
erase(const_iterator pos); // 删除迭代器指向的元素
erase(const_iterator start, const_iterator end); // 删除迭代器从start到end之间的元素
clear(); // 删除容器中所有元素

vector数据存取

at(int idx); // 返回索引idx所指的数据
operator[]; // 返回索引idx所指的数据
front();  // 返回容器中第一个数据元素
back();  // 返回容器中最后一个数据元素

vector互换容器

swap(vec); // 将vec与本身的元素互换

内存收缩:

vector<int>(v).swap(v); // 匿名对象分配的内存空间,系统会在该语句执行完自动给释放

vector预留空间

可以减少在动态扩展容量时的扩展次数

reserve(int len); // 容器预留len个元素长度,预留位置不初始化,元素不可访问

统计开辟内存次数:

void test01()
{
    vector<int> v;
    int num;
    int *p = NULL;
    for (int i = 0; i < 100000; i++)
    {
        v.push_back(i);
        if (p != &v[0])
        {
            p = &v[0];
            num++;
        }
    }
    cout << num;
}

deque容器

使用时包含头文件:#include <deque>

双端数组,可以对头端进行插入删除操作;

dequevector区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低;

  • deque相对而言,对头部的插入删除速度会比vector快;

  • vector访问元素时的速度会比deque快,这和两者内部实现有关;

deque构造函数

deque<T> deqT; // 默认构造形式
deque(beg, end); // 构造函数将[beg, end]区间中的元素拷贝给本身
deque(n, elem); // 构造函数将n个elem拷贝给本身
deque(const deque &dep); // 拷贝构造函数

deque赋值操作

deque& operator=(const deque &deq); // 重载赋值运算符
assign(beg, end); // 将[beg, end]区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身

deque大小操作

deque.empty(); // 判断容器是否为空
deque.size(); // 返回容器中元素的个数
deque.resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

deque插入和删除

push_bakc(elem); // 在容器尾部添加一个数据
push_front(elem); // 在容器头部插入一个数据
pop_back(); // 删除容器中最后一个数据
pop_front(); // 删除容器中第一个数据

insert(pos, elem); // 在pos位置插入一个elem元素的拷贝,返回新数据的位置
insert(pos, n, elem); // 在pos位置插入n个elem数据,无返回值
insert(pos, beg, end); // 在pos位置插入[beg, end)区间的数据,无返回值
clear(); // 清空容器的所有数据
arase(beg, end); // 删除[beg, end)区间的数据,返回下一个数据位置
erase(pos); // 删除pos位置的数据,返回下一个数据的位置

deque数据存取

at(int idx); // 返回索引idx所指的数据
operator[]; // 返回索引idx所指的数据
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素

deque排序

使用时包含头文件#include <algorithm>

sort(iterator beg, iterator end); // 对beg和end区间内元素进行排序 默认从小到大

随机数种子

#include <ctime>
srand((unsigned int)time (NULL);

stack容器

概念:stack是一种先进后出的数据结构;

栈中只有栈顶的元素才可以被外界使用,因此栈不允许有遍历行为;

stack构造函数

stack<T> stk; // stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk); // 拷贝构造函数

stack赋值操作

stack& operator=(const stack &stk); // 重载等号操作符

stack 数据存取

push(elem); // 向栈顶添加元素
pop(); // 从栈顶移除第一个元素
top(); // 返回栈顶元素

stack大小操作

empty(); // 判断堆栈是否为空
size(); // 返回栈的大小

queue容器

概念:queue是一种先进先出的数据结构,他有两个出口;

队列容器允许从一端新增元素,从另一端移除元素;

队列中只有对头和队尾可以被外界使用,因此队列不允许有遍历行为;

queue构造函数

queue<T> que; // que采用模板类实现,que对象的默认构造形式
queue(const queue &que); // 拷贝构造函数

queue赋值操作

queue& operator=(const queue &que); // 重载等号操作符

queue数据存取

push(elem); // 向队尾添加元素
pop(); // 从队头移除第一个元素
back(); // 返回最后一个元素
front(); // 返回第一个元素

queue大小操作

empty(); // 判断堆栈是否为空
size(); // 返回栈的大小

list容器

使用头文件#include <list>

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器;

list的优点:

采用动态存储分配,不会造成内存浪费和溢出;

链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素;

list的缺点:

链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大;

List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的;

总结:STLListvector是两个最常被使用的容器,各有优缺点;

list构造函数

list<T> lst; // list采用模板类实现,对象的默认构造形式
list(beg, end); // 构造函数将[beg, end)区间中的元素拷贝给本身
list(n, elem); // 构造函数将n个elem拷贝给本身
list(const list &lst); // 拷贝构造函数

list赋值和交换

assign(beg, end); // 将[beg, end)区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身
list& operator=(const list &lst); // 重载等号操作符
swap(lst); // 将lst与本身的元素互换

list大小操作

empty(); // 判断容器是否为空
size(); // 返回容器中元素的个数
resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

list插入和删除

push_back(elem); // 在容器尾部加入一个元素
pop_back(); // 删除容器中最后一个元素
push_front(elem); // 在容器开头插入一个元素
pop_front(); // 从容器开头移除第一个元素
insert(pos,elem); // 在pos位置插elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem); // 在pos位置插入n个elem数据,无返回值。
insert(pos, beg, end); // 在pos位置插入[beg,end)区间的数据,无返回值。
clear(); // 移除容器的所有数据
erase(beg, end); // 删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos); // 删除pos位置的数据,返回下一个数据的位置。
remove(elem); // 删除容器中所有与elem值匹配的元素。

list数据存取

front(); // 返回第一个元素
back(); // 返回最后一个元素

list容器不可以通过[]或at方式访问数据;

list反转和排序

reverse(); // 反转链表
sort(); // 链表排序 (从小到大)成员函数

// 改变sort的排序规则
bool myCompare(int v1, int v2)
{
 	   return v1 > v2;
}
sort(myCompare)

所有不支持随机访问迭代器的容器,不可以使用标准算法;

不支持随机访问迭代器的容器,内部会提供对应的一些算法;

list自定义数据高级排序

自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序

#include <iostream>
using namespace std;
#include <list>
#include <string>

class Person
{
public:
    Person(string name, int age, int height)
    {
        this->m_name = name;
        this->m_age = age;
        this->m_height = height;
    }
    string m_name;
    int m_age;
    int m_height;
};
bool comparePerson(Person &p1, Person &p2)
{
    if (p1.m_age == p2.m_age)
    {
        return p1.m_height > p2.m_height;
    }
    return p1.m_age > p2.m_age;
}
void test01()
{
    list<Person> l;
    Person p1("A", 34, 189);
    Person p2("b", 34, 19);
    Person p3("c", 35, 159);
    Person p4("d", 30, 149);
    Person p5("e", 24, 199);
    Person p6("f", 64, 119);

    l.push_back(p1);
    l.push_back(p2);
    l.push_back(p3);
    l.push_back(p4);
    l.push_back(p5);
    l.push_back(p6);
    for (list<Person>::iterator it = l.begin(); it != l.end(); it++)
    {
        cout << it->m_age << it->m_name << it->m_height << endl;
    }
    cout << "排序后" << endl;
    l.sort(comparePerson);
    for (list<Person>::iterator it = l.begin(); it != l.end(); it++)
    {
        cout << it->m_age << it->m_name << it->m_height << endl;
    }
}

int main()
{
    test01();
}

验证迭代器是否支持随机访问:

list<int>::iterator it = l1.begin();
it++; // 支持双向
it--;
it = it + 1; // 不支持随机访问

set/multiset容器

使用时包含头文件#include <set>

所有元素都会再插入时自动排序

set/multiset属于关联式容器,底层结构使用二叉数实现;

setmultiset区别:

set不允许容器中有重复的元素

multiset允许容器中由重复元素

set插入数据的同时会返回插入结果,表示插入是否成功;

multiset不会检测数据,因此可以插入重复数据;

set构造和赋值

set<T> st; // 默认构造函数
set(const set &st); // 拷贝构造函数

set& operator=(const set &st); // 重载等号操作符

set大小和交换

size(); // 返回容器中元素的数目
empty(); // 判断容器是否为空
swap(st); // 交换两个集合容器

set插入和删除

insert(elem); // 在容器中插入元素
clear(); // 清楚所有元素
erase(); // 删除pos迭代器所指的元素,返回下一个元素的迭代器
arase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器
arase(elem); // 删除容器中值为eleme的元素

set查找和统计

find(key); // 查找key是否存在,若存在,返回该键的迭代器;若不存在,返回set.end()
count(key); // 统计key的元素个数

pair队组创建

成对出现的数据,利用队组可以返回两个数据;

pair<type, type> p (value1, value2);
pair<type, type> p = make_pair(value1, value2);

// value1调用方式:p.first
// value2调用方式:p.second

set容器排序

自定义数据类型排序必须指定排序规则

利用仿函数,可以改变排序规则

#include <iostream>
using namespace std;
#include <set>
class MyCompare
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void test01()
{
 
    set<int, MyCompare> s2;

    s2.insert(1);
    s2.insert(2);
    s2.insert(3);
    s2.insert(4);
    s2.insert(6);
    s2.insert(5);
    for (set<int>::iterator it = s2.begin(); it != s2.end(); it++)
    {
        cout << *it << endl;
    }
}

int main()
{
    test01();
}

自定义数据类型排序:

#include <iostream>
#include <set>
using namespace std;
#include <string>

class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    string m_name;
    int m_age;
};
class MyCompare
{
public:
    bool operator()(const Person &p, const Person &p2)
    {
        return p.m_age > p2.m_age;
    }
};

void test01()
{
    set<Person, MyCompare> s;
    Person p1("a", 13);
    Person p2("b", 1123);
    Person p3("c", 103);
    Person p4("d", 100);
    Person p5("e", 90);

    s.insert(p1);
    s.insert(p2);
    s.insert(p3);
    s.insert(p4);
    s.insert(p5);
    for (set<Person>::iterator it = s.begin(); it != s.end(); it++)
    {
        cout << it->m_age << it->m_name << endl;
    }
}
int main()
{
    test01();
}


map/multimap容器

简介:
map中所有元素都是pair;
pair中第一个元素为key (键值),起到索引作用,第二个元素为value(实值);
所有元素都会根据元素的键值自动排序;

本质:
map/multimap属于关联式容器,底层结构是用二叉树实现;

优点:
可以根据key值快速找到value值;

map和multimap区别:
map不允许容器中有重复key值元素;
multimap允许容器中有重复key值元素;

使用时包含头文件#include <map>


map构造和赋值

map<T1, T2> mp; // map默认构造函数
map(const map &mp); // 拷贝构造函数

map& operator=(const map &mp); // 重载等号运算符

map大小和交换

size(); // 返回容器中元素的数目
empty(); // 判断容器是否为空
swap(); // 交换两个结合容器

map插入和删除

insert(elem); // 在容器中插入元素
clear(); // 清楚所有元素
erase(pos); // 删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器
erase(key); // 删除容器中值为key的元素

插入例子:

m.insert(pair<type1, type2>(value1, value2));
m.insert(make_pair(value1, value2));
m.insert(map<type1, type2>::value_type(value1, value2));
m[key]=value; // 不建议用来插入数据,最好用来访问数据

map查找和统计

find(key); // 查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()
count(key); // 统计key的元素的个数 

map容器排序

利用仿函数,可以改变排序规则

#include <iostream>
#include <map>
using namespace std;
class MyCompare
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void test()
{
    map<int, int, MyCompare> m;
    m.insert(make_pair(1, 10));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(3, 30));
    m.insert(make_pair(4, 40));
    m.insert(make_pair(5, 50));
    for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
    {
        cout << it->first << " " << it->second << endl;
    }
}
int main()
{
    test();
}

对于自定义类型数据,map必须指定排序规则;


STL-函数对象

概念:

重载函数调用操作符的类,其对象常称为函数对象;

函数对象使用重载的()时,行为类似函数调用,也叫仿函数;

本质:

函数对象(仿函数)是一个类,不是一个函数;

特点:

函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值;

函数对象超出普通函数的概念,函数对象可以有自己的状态;

函数对象可以作为参数传递;

#include <iostream>
using namespace std;
#include <string>
class MyAdd
{
public:
    int operator()(int v1, int v2)
    {
        return v1 + v2;
    }
};
void test()
{
    MyAdd myAdd;
    cout << myAdd(10, 10);
}

class MyPrint
{
public:
    void operator()(string test)
    {
        cout << test << endl;
        this->count++;
    }
    int count;
    MyPrint()
    {
        this->count = 0;
    }
};
void doPrint(MyPrint &mp, string test)
{
    mp(test);
}
void test02()
{
    MyPrint myPrint;
    doPrint(myPrint, "ehllo ");
}
void test01()
{
    MyPrint myPrint;
    myPrint("hwllowe");
    myPrint("hwllowe");
    myPrint("hwllowe");
    myPrint("hwllowe");
    cout << myPrint.count;
}
int main()
{
    test02();
}

谓词

返回bool类型的仿函数称为谓词

如果operator()接受一个参数,那么叫一元谓词;

如果operator()接受两个参数,那么叫二元谓词;

一元谓词

#include <iostream>
#include <vector>
using namespace std;
#include <algorithm>
class GreaterFive
{
public:
    bool operator()(int val)
    {
        return val > 5;
    }
};
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }

    vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive()); // 使用了匿名的函数对象
    if (it == v.end())
    {
        cout << "未找到" << endl;
    }
    else
    {
        cout << "找到" << endl;
    }
}
int main()
{
    test01();
}

二元谓词

#include <iostream>
#include <vector>
using namespace std;
#include <algorithm>
class GreaterFive
{
public:
    bool operator()(int val, int val1)
    {
        return val > val1;
    }
};
void test01()
{
    vector<int> v;
    v.push_back(15550);
    v.push_back(30);
    v.push_back(1310);
    v.push_back(1310);
    v.push_back(1311230);
    sort(v.begin(), v.end(), GreaterFive());

    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << endl;
    }
}
int main()
{
    test01();
}

内建函数对象

这些仿函数所产生的对象,用法和一般函数完全相同;

使用内建函数对象,需要引入头文件#include <functional>

算数仿函数

实现四则运算

其中negate是一元运算,其他都是二元运算;

template<class T> T plus<T>    // 加法仿函数
template<class T> T minus<T>     // 减法仿函数
template<class T> T multiplies<T>     // 乘法仿函数
template<class T> T divides<T>     // 除法仿函数
template<class T> T modulus<T>     // 取模仿函数
template<class T> T negate<T>     // 取反仿函数
#include <iostream>
#include <functional>
using namespace std;

void test()
{
    negate<int> n;
    cout << n(50);
}
void test01()
{
    plus<int> n;
    cout << n(1, 2) << endl;
}

// 其它的用法有一样
int main()
{
    test01();
    system("pause");
}

关系仿函数

实现关系对比

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 <functional>
#include <vector>
#include <algorithm>

using namespace std;
class My
{
public:
    bool operator()(int val1, int val2)
    {
        return val1 > val2;
    }
};
void test()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(4);
    v.push_back(6);
    v.push_back(2);
    v.push_back(9);
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    sort(v.begin(), v.end(), greater<int>());  //  内建函数对象
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
}
int main()
{
    test();
}

逻辑仿函数

template<class T> bool logical_and<T> // 逻辑与
template<class T> bool logical_or<T> // 逻辑或
template<class T> bool logical_not<T> // 逻辑非
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;

void test()
{
    vector<bool> v;
    v.push_back(false);
    v.push_back(true);
    v.push_back(false);
    v.push_back(true);
    v.push_back(false);
    for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }

    vector<bool> v2;
    v2.resize(v.size());
    transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
    for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
}
int main()
{
    test();
}

STL-常用算法

算法主要是由头文件<algorithm>,<functional>,<numeric>组成;

<algorithm>是所有STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、赋值、修改等等;

<functional>体积很小,只包括了在序列上面进行简单数学运算的模块函数;

<numeric>定义了一些模板类,用以声明函数对象;

常用遍历算法

for_each()

for_each(iterator beg, iterator end, _func) //遍历容器
    /*
    beg 开始迭代器;
   	end 结束迭代器
   	_func 函数或者函数对象
   	*/

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print01(int val)
{
    cout << val << " ";
}
class print02 
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    // for_each(v.begin(), v.end(), print01);
    for_each(v.begin(), v.end(), print02());
}
int main()
{
    test();
}

transform()

transform(iterator beg1, iterator end1, iterator beg2, _func) // 搬运容器到另一个容器中
    /*
    beg1 原容器开始迭代器;
   	end1 原容器结束迭代器
   	beg2 目标容器开始迭代器  使用时目标容器要提前开辟空间(resize())
   	_func 函数或者函数对象
   	*/
    

常用查找算法

find

查找元素,找到返回指定元素的迭代器,找不到返回结束迭代器end();

find(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    bool operator==(const Person &a)
    {
        if (this->m_name == a.m_name && this->m_age == a.m_age)
        {
            return true;
        }
        return false;
    }
    string m_name;
    int m_age;
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 410);
    Person p2("bb", 10);
    Person p3("cc", 120);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person pp("bb", 10);
    vector<Person>::iterator i = find(v.begin(), v.end(), pp);
    if (i == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
        cout << i->m_name << i->m_age << endl;
    }
}
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    vector<int>::iterator it = find(v.begin(), v.end(), 41);
    if (it == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test01();
}

find_if

按条件查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置;

find_if(iterator beg, iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 函数或者谓词(返回bool类型的仿函数)
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    bool operator==(const Person &a)
    {
        if (this->m_name == a.m_name && this->m_age == a.m_age)
        {
            return true;
        }
        return false;
    }
    string m_name;
    int m_age;
};
class GreaterFive
{
public:
    bool operator()(int val)
    {
        return val > 5;
    }
};
class GreaterFive01
{
public:
    bool operator()(const Person &val)
    {
        return val.m_age > 5;
    }
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 410);
    Person p2("bb", 10);
    Person p3("cc", 120);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person pp("bb", 10);
    vector<Person>::iterator i = find_if(v.begin(), v.end(), GreaterFive01());
    if (i == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
        cout << i->m_name << i->m_age << endl;
    }
}
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    vector<int>::iterator i = find_if(v.begin(), v.end(), GreaterFive());

    if (i == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test01();
}

adjacent_find

查找相邻重复元素,返回相邻元素的第一个位置的迭代器;

adjacent_find(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void test()
{
    vector<int> v;
    v.push_back(0);
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    v.push_back(9);

    vector<int>::iterator it = adjacent_find(v.begin(), v.end());
    if (it == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test();
}

binary_search

二分法查找,查找指定的元素,找到返回ture,否则返回false;

注意:无序序列不可用;

bool binary_search(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    bool it = binary_search(v.begin(), v.end(), 4);
    if (!it)
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test();
}

count

统计元素个数

统计自定义数据类型时,需要配合重载operator==

count(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 统计的元素
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    bool operator==(const Person &a)
    {
        if (this->m_name == a.m_name && this->m_age == a.m_age)
        {
            return true;
        }
        return false;
    }
    string m_name;
    int m_age;
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 10);
    Person p2("bb", 10);
    Person p3("aa", 10);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person p("aa", 10);
    int i = count(v.begin(), v.end(), p);
    cout << i;
}
void test()
{
    vector<int> v;

    v.push_back(40);
    v.push_back(20);
    v.push_back(40);
    v.push_back(50);
    v.push_back(40);

    int it = count(v.begin(), v.end(), 40);
    cout << it << endl;
}
int main()
{
    test01();
}

count_if

按条件统计元素个数

count_if(iterator beg,iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }

    string m_name;
    int m_age;
};
class GreaterFive
{
public:
    bool operator()(int val)
    {
        return val > 50;
    }
};
class GreaterFive01
{
public:
    bool operator()(const Person &val)
    {
        return val.m_age > 51000;
    }
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 410);
    Person p2("bb", 10);
    Person p3("cc", 120);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person pp("bb", 10);
    int i = count_if(v.begin(), v.end(), GreaterFive01());
    cout << i << endl;
}
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    int i = count_if(v.begin(), v.end(), GreaterFive());
    cout << i << endl;
}
int main()
{
    test01();
}

常用排序算法

sort

按值查找元素,找到返回指定位置迭代器,找不到返回结束位置迭代器位置

sort(iterator beg, iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(4);
    v.push_back(5);
    v.push_back(2);
    v.push_back(9);
    v.push_back(10);
    sort(v.begin(), v.end());
    for_each(v.begin(), v.end(), myPrint);
    sort(v.begin(), v.end(), greater<int>());
    for_each(v.begin(), v.end(), myPrint);
}
int main()
{
    test01();
}

random_shuffle

指定范围内的元素随机调整次序

random_shuffle(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    srand((unsigned int)time(NULL));
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    random_shuffle(v.begin(), v.end());
    for_each(v.begin(), v.end(), myPrint);
}

int main()
{
    test01();
}

merge

两个容器元素合并,并存储到里一个容器中

新的容器要提前分配空间;

merge(iterator beg1, interator end1, iterator beg2, iterator end2, iterator dest);
// 注意:两个容器必须都是有序的
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    vector<int> v2;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v.push_back(i + 1);
    }
    vector<int> v3;
    v3.resize(v.size() + v2.size());
    merge(v.begin(), v.end(), v2.begin(), v2.end(), v3.begin());
    for_each(v3.begin(), v3.end(), myPrint);
}

int main()
{
    test01();
}

reverse

将容器内元素进行反转

reverse(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    reverse(v.begin(), v.end());
    for_each(v.begin(), v.end(), myPrint);
}

int main()
{
    test01();
}

常用拷贝和替换算法

copy

容器中指定范围的元素拷贝到另一个容器中;

目标容器要提前开辟空间;

copy(iterator beg, iterator end, iterator dest);
// beg 开始迭代器
// end 结束迭代器
// dest 目标起始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    vector<int> v2;
    v2.resize(v.size());
    copy(v.begin(), v.end(), v2.begin());
    for_each(v.begin(), v.end(), myPrint);
    cout << endl;
    for_each(v2.begin(), v2.end(), myPrint);
}

int main()
{
    test01();
}

replace

将容器中指定范围的旧元素修改为新元素

replace(iterator beg, iterator end, oldvalue, newvalue);
// beg 开始迭代器
// end 结束迭代器
// oldvalue 旧元素
// newvalue 新元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    replace(v.begin(), v.end(), 1, 200);
    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}

replace_if

将区间内满足条件的元素,替换成指定元素

replace(iterator beg, iterator end, _Pred, newvalue);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
// 替换的新元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
class Greater
{
public:
    bool operator()(int val)
    {
        return val > 1;
    }
};
void test01()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(20);
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    v.push_back(10);
    v.push_back(2);
    v.push_back(11);
    replace_if(v.begin(), v.end(), Greater(), 200);
    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}

swap

互换两个容器中的元素

swap(container c1, container c2);
// c1 容器1
// c2 容器2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};

void test01()
{
    vector<int> v;

    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 100);
    }
    v.push_back(999);
    swap(v, v1);
    for_each(v.begin(), v.end(), MyPrint());
    cout << endl;
    for_each(v1.begin(), v1.end(), MyPrint());
}

int main()
{
    test01();
}


常用算数生成算法

使用头文件#include <numeric>

accumulate

计算区间内容器元素累计总和;

accumulate(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 起始值
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};

void test01()
{
    vector<int> v;

    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    int sum = accumulate(v.begin(), v.end(), 0);
    cout << sum << endl;

    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}

fill

向容器化中填充指定的元素

fill(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 填充的值
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};

void test01()
{
    vector<int> v;
    v.resize(10);

    fill(v.begin(), v.end(), 1);

    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}


常用集合算法

set_intersection

求两个容器的交集

注意:

求交集的两个集合必须是有序列的;

目标容器开辟空间需要从两个容器中取最小;

set_intersection返回值既是交集中最后一个元素;

set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 5);
    }
    vector<int> v2;

    v2.resize(min(v1.size(), v.size()));

    vector<int>::iterator it = set_intersection(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());

    for_each(v2.begin(), it, myPrint);
}

int main()
{
    test01();
}

set_union

求两个容器的并集

注意:

求交集的两个集合必须是有序列的;

目标容器开辟空间需要从两个容器中之和;

set_union返回值既是交集中最后一个元素;

set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 5);
    }
    vector<int> v2;

    v2.resize(v1.size() + v.size());

    vector<int>::iterator it = set_union(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());

    for_each(v2.begin(), it, myPrint);
}

int main()
{
    test01();
}

set_difference

求两个容器的差集

注意:

求交集的两个集合必须是有序列的;

目标容器开辟空间需要从两个容器中取最大;

set_difference返回值既是交集中最后一个元素;

set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 5);
    }
    vector<int> v2;

    v2.resize(max(v1.size(), v.size()));

    vector<int>::iterator it = set_difference(v1.begin(), v1.end(), v.begin(), v.end(), v2.begin());

    for_each(v2.begin(), it, myPrint);
}

int main()
{
    test01();
}
这篇关于C++基础知识的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!