更多教程笔记请查看我的上一篇文章:点击跳转

C++自学之旅3.0(STL模板)开始!

下面介绍的是algorithm这个C++内置的算法函数模板

algorithm:

for_each遍历算法

// algorithm算法模板-for_each
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
//普通函数
// for_each会不断的调用这个函数进行输出,这里用到了函数指针
void print01(int val)
{
    cout << val << " ";
}
//仿函数
class Print02
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    //常用遍历算法 for_each
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    //遍历,前两个参数是要遍历的容器区间,第三个参数可以是函数也可以是仿函数的函数对象
    for_each(v.begin(), v.end(), print01);
    cout << endl;
    //传入的是仿函数的匿名对象
    for_each(v.begin(), v.end(), Print02());
}
int main()
{
    test01();
    return 0;
}

transform搬运算法

// algorithm算法模板-transform
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class Transform
{
public:
    //因为操作的是vector里int类型的数据,所以要返回int类型
    int operator()(int v)
    {

        // return v;
        //可以在搬运过程中加上逻辑运算让结果不一样
        return v + 100;
    }
};
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);
    }
    //目标容器
    vector<int> vTarget;

    //重新指定容量,目标容器必须大于原容器
    vTarget.resize(v.size());

    //利用transform将第一个容器搬运到第二个容器,最后一个参数是匿名对象
    transform(v.begin(), v.end(), vTarget.begin(), Transform());

    //输出
    for_each(vTarget.begin(), vTarget.end(), Myprint());
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

find查找算法

// algorithm算法模板-find查找算法
#include <iostream>
using namespace std;
//使用find需要包含algorithm头文件
#include <algorithm>
#include <string>
#include <vector>
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
//查找内置的数据类型
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }

    //查找容器中是否有5这个元素,前两个参数是容器区间,第三个参数是要查找的值
    //返回的是一个容器的迭代器
    vector<int>::iterator it = find(v.begin(), v.end(), 5);

    //如果it指向容器的尾指针则表示没有找到这个元素
    if (it == v.end())
    {
        //查找失败
        cout << "find NULL!" << endl;
    }
    else
    {
        //查找成功
        cout << "find success!" << *it << endl;
    }
    // printVector(v);
}
//查找自定义的数据类型
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    //重载operator==符号,让find知道如何查找Person的数据类型
    // const是为了防止它修改底层代码
    bool operator==(const Person &p)
    {
        //如果名字和年龄都相等那么就是要找的那个数
        if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    string m_Name;
    int m_Age;
};
void test02()
{
    vector<Person> v;
    //创建数据
    Person p1("aaa", 10);
    Person p2("bbb", 20);
    Person p3("ccc", 30);
    Person p4("ddd", 40);
    //将数据放入到容器中
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);

    Person pp("bbb", 20);

    //查找容器里面是否有p2这个对象
    //知识点 自定义数据类型不能直接比较需要重载
    // vector<Person>::iterator it = find(v.begin(), v.end(), p2);

    //或者直接创建一个一样的其他对象进行比较
    vector<Person>::iterator it = find(v.begin(), v.end(), pp);

    if (it == v.end())
    {
        cout << "find NULL" << endl;
    }
    else
    {
        cout << "find success! name: " << it->m_Name << " age: " << it->m_Age << endl;
    }
}
int main()
{
    // test01();
    test02();
    return 0;
}

find_if查找算法

// algorithm算法模板-find_if查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <string>
//仿函数
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);
    }
    //查找容器里大于5的数,前两个参数是容器的区间,第三个参数是函数对象
    //返回的是容器的迭代器
    vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
    //如果it等于尾指针就是没有找到
    if (it == v.end())
    {
        //没有找到
        cout << "find NULL" << endl;
    }
    else
    {
        //找到了!
        cout << "find success!" << endl;
        for (; it != v.end(); it++)
        {
            cout << *it << " ";
        }
    }
}
//查找自定义的数据类型
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};
class Greater20
{
public:
    bool operator()(Person &p)
    {
        return p.m_Age > 20;
    }
};
void test02()
{
    vector<Person> v;
    //创建数据
    Person p1("aaa", 10);
    Person p2("bbb", 20);
    Person p3("ccc", 30);
    Person p4("ddd", 40);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);

    //查找容器中年龄大于20的对象
    vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater20());

    if (it == v.end())
    {
        cout << "find NULL!" << endl;
    }
    else
    {
        cout << "find success!" << endl;
        for (; it != v.end(); it++)
        {
            cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
        }
    }
}
int main()
{
    // test01();
    test02();
    return 0;
}

adjacent_find查找算法

// algorithm算法模板-adjacent_find查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <string>
void test01()
{
    // adjacent_find作用是查找相邻的重复元素
    vector<int> v;
    v.push_back(0);
    v.push_back(2);
    v.push_back(0);
    v.push_back(3);
    v.push_back(1);
    v.push_back(4);
    v.push_back(3);
    v.push_back(3);

    //查找相邻的重复元素,返回的是一个容器的迭代器
    vector<int>::iterator it = adjacent_find(v.begin(), v.end());
    //如果it等于尾指针则表示查找失败
    if (it == v.end())
    {
        cout << "find NULL!" << endl;
    }
    else
    {
        //查找成功
        cout << "find success!" << endl;
        for (; it != v.end(); it++)
        { // 3 3
            cout << *it << endl;
        }
    }
}
int main()
{
    test01();
    return 0;
}

binary_search二分查找算法

// algorithm算法模板-binary_search二分查找算法
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
//常用的查找算法 binary_search
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    //查找容器中是否有9这个元素,前两个参数是容器的区间,第三个参数是要查找的值
    //返回的是一个bool类型
    //注意容器这里必须是有序且升序排序的序列,不可以是降序的
    //降序的话可以使用重载版本,在后面添加greater<int>()这个仿函数
    bool ret = binary_search(v.begin(), v.end(), 9);
    //如果找到了就为真,未找到为假
    if (ret)
    {
        cout << "find success!" << endl;
    }
    else
    {
        cout << "find NULL!" << endl;
    }
}
int main()
{
    test01();
    return 0;
}

count统计查找算法

// algorithm算法模板-count统计查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
//统计内置数据类型
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        for (int j = 10; j >= i; j--)
        {
            v.push_back(j);
        }
    }

    //利用count统计出容器中4的元素个数
    //返回值是一个整型
    int num = count(v.begin(), v.end(), 4);

    cout << "4 num: " << num << endl;
}
//统计自定义的数据类型
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    //统计自定义的数据类型时需要仿函数operator重载==号,返回类型是bool
    //注意:为了防止修改底层代码需要加const
    bool operator==(const Person &p)
    {
        if (this->m_Age == p.m_Age)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    string m_Name;
    int m_Age;
};
void test02()
{
    vector<Person> v;
    Person p1("aaa", 35);
    Person p2("bbb", 35);
    Person p3("ccc", 35);
    Person p4("ddd", 30);
    Person p5("eee", 40);

    Person p("vvv", 35);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);

    //统计与p年龄相同的人有多少个
    //注意:统计自定义的数据类型时需要仿函数operator重载==号
    int num = count(v.begin(), v.end(), p);

    cout << "and vvv age num: " << num << endl;
}
int main()
{
    // test01();
    test02();
    return 0;
}

count_if统计查找算法

// algorithm算法模板-count_if统计查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
//统计内置的数据类型
class Greater20
{
public:
    //仿函数
    bool operator()(int val)
    {
        return val > 20;
    }
};
void test01()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(40);
    v.push_back(30);
    v.push_back(20);
    v.push_back(40);
    v.push_back(20);

    //查找容器里有多少个大于20的数,前两个参数是容器的区间,第三个参数是仿函数的函数对象
    //返回值是一个int类型
    int num = count_if(v.begin(), v.end(), Greater20());

    cout << ">20 num: " << num << endl;
}
//统计自定义的数据类型
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};
//创建谓词供count_if使用
class AgeGreater20
{
public:
    bool operator()(const Person &p)
    {
        return p.m_Age > 20;
    }
};
void test02()
{
    vector<Person> v;
    Person p1("aaa", 35);
    Person p2("bbb", 35);
    Person p3("ccc", 35);
    Person p4("ddd", 40);
    Person p5("eee", 20);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);

    //统计 年龄大于20的人员个数 传入的是一个仿函数的匿名函数对象
    int num = count_if(v.begin(), v.end(), AgeGreater20());
    cout << ">20 age num: " << num << endl;
}
int main()
{
    // test01();
    test02();
    return 0;
}

sort排序算法

// algorithm算法模板-sort排序算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <functional>
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(50);
    v.push_back(20);
    v.push_back(40);

    //利用sort进行升序
    sort(v.begin(), v.end());

    //打印
    for_each(v.begin(), v.end(), myPrint);
    cout << endl;

    //利用sort仿函数进行降序
    sort(v.begin(), v.end(), greater<int>());

    //打印
    for_each(v.begin(), v.end(), myPrint);
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

random_shuffle洗牌算法

// algorithm算法模板-random_shuffle洗牌算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <ctime>
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);
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

merge合并排序算法

// algorithm算法模板-merge合并排序算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v1;
    vector<int> v2;
    //注意:使用merge时合并的两个容器必须是有序序列
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
        v2.push_back(i + 1);
    }
    //目标容器,将上面两个容器放入目标容器中
    vector<int> vTarget;

    //要将目标容器的大小扩大到上面两个容器合并的大小
    vTarget.resize(v1.size() + v2.size());

    //前四个参数是两个容器的区间,第五个参数是目标容器的头部
    //当两个容器合并后会自动按升序排序
    //如果要合并后降序排序需要在第六个参数加greater<int>()
    merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
    //输出
    for_each(vTarget.begin(), vTarget.end(), myPrint);
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

reverse反转算法

// algorithm算法模板-reverse反转算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(50);
    v.push_back(20);
    v.push_back(40);

    //反转前
    cout << "open: " << endl;
    for_each(v.begin(), v.end(), myPrint);
    cout << endl;
    //反转,传递的是容器的区间
    reverse(v.begin(), v.end());
    //反转后
    cout << "end: " << endl;
    for_each(v.begin(), v.end(), myPrint);
}
int main()
{
    test01();
    return 0;
}

copy拷贝算法

// algorithm算法模板-copy拷贝算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(30);
    v1.push_back(50);
    v1.push_back(20);
    v1.push_back(40);

    vector<int> v2;

    //在拷贝前目标容器要开辟空间
    v2.resize(v1.size());

    //拷贝前
    cout << "open: " << endl;
    for_each(v2.begin(), v2.end(), myPrint);
    cout << endl;

    //拷贝,前两个参数传递的是容器的区间,第三个参数是目标容器的头部
    copy(v1.begin(), v1.end(), v2.begin());

    //拷贝后
    cout << "end: " << endl;
    for_each(v2.begin(), v2.end(), myPrint);
}
int main()
{
    test01();
    return 0;
}

replace替换算法

// algorithm算法模板-replace替换算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(50);
    v.push_back(20);
    v.push_back(40);
    v.push_back(10);
    v.push_back(20);

    //替换前
    cout << "open: " << endl;
    for_each(v.begin(), v.end(), myPrint());
    cout << endl;

    //替换,前两个参数传递的是容器的区间,第三个参数是要被替换的数值,第四个参数是要替换的数值
    //将容器的区间内部所有的20替换为2000
    replace(v.begin(), v.end(), 20, 2000);

    //替换后
    cout << "end: " << endl;
    for_each(v.begin(), v.end(), myPrint());
}
int main()
{
    test01();
    return 0;
}

replace_if指定替换算法

// algorithm算法模板-replace_if指定替换算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
//写一个谓词当作判断条件
class Greater30
{
public:
    bool operator()(int val)
    {
        return val >= 30;
    }
};
void test01()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(50);
    v.push_back(20);
    v.push_back(40);
    v.push_back(10);
    v.push_back(20);

    //替换前
    cout << "open: " << endl;
    for_each(v.begin(), v.end(), myPrint());
    cout << endl;

    //替换,前两个参数传递的是容器的区间,第三个参数是要被替换的仿函数规则(谓词),第四个参数是要替换的数值
    //将容器的区间内部所有大于等于30的数 替换为3000
    replace_if(v.begin(), v.end(), Greater30(), 3000);

    //替换后
    cout << "end: " << endl;
    for_each(v.begin(), v.end(), myPrint());
}
int main()
{
    test01();
    return 0;
}

swap交换算法

// algorithm算法模板-swap交换算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    vector<int> v1;
    vector<int> v2;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
        v2.push_back(i + 100);
    }

    //交换前
    cout << "open: " << endl;
    cout << "v1: " << endl;
    for_each(v1.begin(), v1.end(), myPrint());
    cout << endl;
    cout << "v2: " << endl;
    for_each(v2.begin(), v2.end(), myPrint());
    cout << endl;

    //交换,注意:在交换时两个容器的类型必须相同
    swap(v1, v2);

    //交换后
    cout << "--------------------------------------" << endl;
    cout << "end: " << endl;
    cout << "v1: " << endl;
    for_each(v1.begin(), v1.end(), myPrint());
    cout << endl;
    cout << "v2: " << endl;
    for_each(v2.begin(), v2.end(), myPrint());
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

set_intersection交集算法

// algorithm算法模板-set_intersection交集算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    //所谓交集就是两个容器中相同的部分
    //注意:两个容器必须是有序的
    vector<int> v1;
    vector<int> v2;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);     // 0~9
        v2.push_back(i + 5); // 5~14
    }

    //将两个容器的交集部分存入到第三个容器中
    vector<int> vTarget;

    //需要提前指定大小
    //最坏的情况 大容器包含小容器 开辟空间 取小容器的size即可
    vTarget.resize(min(v1.size(), v2.size()));

    //获取交集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
    //返回值是一个迭代器,itEnd指向的是重复的最后位置,但是容器没完,后面还有初始化的0
    vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());

    //输出 用itend 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
    for_each(vTarget.begin(), itEnd, myPrint());
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

set_union并集算法

// algorithm算法模板-set_union并集算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    //所谓并集就是两个容器中不相同的部分,如果有相同的部分会优先去掉另一个相同的部分
    //只保留一个原来的相同的部分
    //注意:两个容器必须是有序的
    vector<int> v1;
    vector<int> v2;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);     // 0~9
        v2.push_back(i + 5); // 5~14
    }

    //将两个容器的并集部分存入到第三个容器中
    vector<int> vTarget;

    //需要提前指定大小
    //最坏的情况 两个容器没有交集 并集就是两个容器相加
    vTarget.resize(v1.size() + v2.size());

    //获取并集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
    //返回值是一个容器的迭代器,指向目标容器的并集的最后部分
    vector<int>::iterator it = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());

    //输出 用it 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
    for_each(vTarget.begin(), it, myPrint());
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

set_difference差集算法

// algorithm算法模板-set_difference差集算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    //所谓差集就是两个容器中不相同(不属于交集)的部分
    //按照顺序如果是v1和v2的差集那就只保留v1中和v2不同的部分
    //如果是v2和v1的差集那就只保留v2中和v1不同的部分,也就是:
    // v1和v2的差集:0 1 2 3 4
    // v2和v1的差集: 10 11 12 13 14
    //它们各自都把相同的部分去掉了,只保留自身
    vector<int> v1;
    vector<int> v2;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);     // 0~9
        v2.push_back(i + 5); // 5~14
    }

    //将两个容器的差集部分存入到第三个容器中
    vector<int> vTarget;

    //需要提前指定大小
    //最坏的情况 两个容器没有交集 要取两个容器中大的size作为目标容器开辟的空间
    vTarget.resize(max(v1.size(), v2.size()));

    // v1和v2的差集为:
    cout << "v1 n v2: " << endl;

    //获取差集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
    //返回值是一个容器的迭代器,指向目标容器的差集的结束位置
    vector<int>::iterator it = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());

    //输出 用it 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
    for_each(vTarget.begin(), it, myPrint());
    cout << endl;

    // v2和v1的差集为:
    cout << "v2 n v1: " << endl;

    //获取差集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
    //返回值是一个容器的迭代器,指向目标容器的差集的结束位置
    it = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());

    //输出 用it 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
    for_each(vTarget.begin(), it, myPrint());
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

下面介绍的是vector这个C++内置的动态数组容器

vector:

vector的用法

// vector的用法
#include <iostream>
using namespace std;
//用vector的容器需要包含这个头文件
#include <vector>
//用其他的STL模板算法需要包含这个头文件
#include <algorithm>

void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    //<>括号里面是要操作的数据类型
    vector<int> arr;
    //从尾部插入数据
    arr.push_back(10);
    arr.push_back(20);
    arr.push_back(30);
    arr.push_back(40);
    //通过迭代器访问容器中的数据,arr.begin()指向容器中的第一个元素
    vector<int>::iterator itBegin = arr.begin();
    // arr.end()指向容器中的最后一个元素的下一个位置
    vector<int>::iterator itEnd = arr.end();

    //第一种遍历方式:
    // while (itBegin != itEnd)
    // {
    //     cout << *itBegin << " ";
    //     itBegin++;
    // }

    //第二种遍历方式
    // for (vector<int>::iterator it = arr.begin(); it != arr.end(); it++)
    // {
    //     cout << *it << " ";
    // }

    //第三种遍历方式,用algorithm里面提供的模板
    //第一个参数是数组的起始位置,第二个参数是数组的结束位置,第三个参数是自定义的函数名
    //在遍历的时候它会不停的调用这个函数,向这个函数传参数,再在函数里面进行输出
    for_each(arr.begin(), arr.end(), myPrint);
}

int main()
{

    test01();
    return 0;
}

vector操作自定义的数据类型

// vector操作自定义的数据类型
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <string>
//自定义一个Person的数据类型
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};

void test01()
{
    Person p1("aaa", 10);
    Person p2("bbb", 20);
    Person p3("ccc", 30);
    Person p4("ddd", 40);
    Person p5("eee", 50);

    vector<Person> v;
    //通过尾插的方式插入自定义的数据类型
    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++)
    {
        //迭代器指向的是一个对象,所以可以用对象的方式获得属性
        // cout << "name: " << (*it).m_Name << " age: " << (*it).m_Age << endl;
        //因为it本身就是一个指针,所以可以通过指针的方式直接访问对象里的属性

        cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
    }
}

void test02()
{
    Person p1("aaa", 10);
    Person p2("bbb", 20);
    Person p3("ccc", 30);
    Person p4("ddd", 40);
    Person p5("eee", 50);
    //第二种方式:存放自定义数据类型的指针
    vector<Person *> v;
    //通过尾插的方式插入自定义的数据类型的地址
    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;
    }
}

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

vector嵌套vector

// vector嵌套vector
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <string>

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++)
    {
        //(*it)----vector<int> 当it解引用后出来的是小容器,所以还要遍历一遍小容器
        for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
        {
            // vit---vector<int> v1[0]  此时vie就等于小容器里面的首地址,通过解引用的方式拿到数组里面的值
            //当一层循环遍历完了后也就是把大容器中的第一个数组遍历完了,然后就会遍历下一个数组
            cout << *vit << " ";
        }
        cout << endl;
    }
}

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

vector实战

// vector实战
#include <iostream>
using namespace std;
#include <vector>
//输出
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    //默认构造 无参构造
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);

    //通过区间的方式进行构造,也就是把v1中从第1号位置到倒数第1号位置之间的全部数据复制到v2中
    vector<int> v2(v1.begin(), v1.end());
    printVector(v2);

    //通过elem方式构造,也就是把10个100赋值给v3
    vector<int> v3(10, 100);
    printVector(v3);

    //拷贝构造,将v3中的内容拷贝到v4中
    vector<int> v4(v3);
    printVector(v4);
}
int main()
{
    test01();
    return 0;
}

vector函数重载

#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);
    //赋值 operator=
    vector<int> v2;
    //其底层是函数重载,将v1的内容赋值给v2
    v2 = v1;
    printVector(v2);
    // assign
    vector<int> v3;
    //通过成员函数assign,将v1区间里的内容复制到v3中
    v3.assign(v1.begin(), v1.end());
    printVector(v3);

    // n个elem方式赋值
    vector<int> v4;
    //将10个100赋值到v4中
    v4.assign(10, 100);
    printVector(v4);
}
int main()
{
    test01();
    return 0;
}

vector指定大小

#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);
    //为真,代表容器为空
    if (v1.empty())
    {
        cout << "v1 NULL" << endl;
    }
    else
    {
        //容器不为空
        cout << "v1 not NULL" << endl;
        //输出数组的容量,容量机制是快要插满时就扩展至原来的1.5倍
        cout << "v1 area: " << v1.capacity() << endl;
        //输出数组的长度
        cout << "v1 size:" << v1.size() << endl;
    }
    //重新指定大小,会默认用0来填充数组剩余的位置
    // v1.resize(15);
    //也可以用100或者其他数替换0的位置作为填充值
    v1.resize(15, 100);
    printVector(v1);
    //如果重新指定的比原来短了,超出部分会删除掉
    v1.resize(5);
    printVector(v1);
}
int main()
{
    test01();
    return 0;
}

vector插入和删除

#include <iostream>
using namespace std;
#include <string>
#include <vector>
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50);
    printVector(v1);
    //尾删
    v1.pop_back();
    printVector(v1);
    //插入,在头部最前面插入一个100
    v1.insert(v1.begin(), 100);
    printVector(v1);
    //利用重载的版本,在头部最前面插入2个1000
    v1.insert(v1.begin(), 2, 1000);
    printVector(v1);
    //删除,删除最前面头部的元素
    v1.erase(v1.begin());
    printVector(v1);
    //利用重载的版本,将数组从开始到结束区间的所有数据全部删除
    // v1.erase(v1.begin(), v1.end());
    //清空,效果和上面一样
    // v1.clear();
    //删除倒数第二个位置上的元素
    v1.erase(v1.end() - 2);
    //删除中间位置的元素
    v1.erase(v1.begin() + v1.size() / 2);
    printVector(v1);
}
int main()
{
    test01();
    return 0;
}

vector用at的方式访问元素

// vector实战
#include <iostream>
using namespace std;
#include <vector>
void test01()
{
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    //利用[]符号的方式访问数组中的元素,其底层是重载[]
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;
    //利用at方式访问元素
    for (int i = 0; i < v1.size(); i++)
    {
        cout << v1.at(i) << " ";
    }
    cout << endl;
    //利用front成员函数,获取第一个元素
    cout << "one: " << v1.front() << endl;
    //利用back成员函数,获取最后一个元素
    cout << "end: " << v1.back() << endl;
}
int main()
{
    test01();
    return 0;
}

vector巧用swap收缩内存

// vector实战
#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v1.push_back(i);
    }
    //交换前
    cout << "open:" << endl;
    printVector(v1);
    vector<int> v2;
    for (int i = 10; i > 0; i--)
    {
        v2.push_back(i);
    }
    printVector(v2);
    //交换后
    cout << "end:" << endl;
    //通过swap成员函数,把v1和v2的元素交换
    v1.swap(v2);
    printVector(v1);
    printVector(v2);
}
// swap的调用时机
void test02()
{
    vector<int> v;
    for (int i = 0; i < 100000; i++)
    {
        v.push_back(i);
    }
    //输出容量
    cout << "v area: " << v.capacity() << endl;
    //输出长度
    cout << "v size: " << v.size() << endl;
    //重新指定大小
    v.resize(3);
    //输出容量,重新指定大小后,容量并不会缩小,浪费空间
    cout << "v area: " << v.capacity() << endl;
    //输出长度
    cout << "v size: " << v.size() << endl;

    //巧用swap收缩内存
    //利用拷贝构造创建一个匿名对象,让匿名对象和原本的数组进行交换
    //在用完后匿名对象就自动释放了,然后原本的数组的容量就变成了匿名对象的容量
    vector<int>(v).swap(v);
    //输出容量
    cout << "v area: " << v.capacity() << endl;
    //输出长度
    cout << "v size: " << v.size() << endl;
}
int main()
{
    // test01();
    test02();
    return 0;
}

vector利用reverse预留空间

// vector实战
#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    vector<int> v;

    //利用reserve预留空间
    v.reserve(100000);
    //当利用reserve为动态数组预留了空间以后,编译器就不会自动开辟内存了,减少了内存的占用

    //统计开辟的次数
    int num = 0;
    int *p = NULL;
    for (int i = 0; i < 100000; i++)
    {
        v.push_back(i);
        //因为内存不连续,所以就会挪地方。用头部指针来确定位置
        if (p != &v[0])
        {
            //每次扩容释放原来的空间并重新申请空间,指针指向的地址就会和v[0]不同
            p = &v[0];
            //所以在它重新开辟的时候判断指针就可以得到它开辟的次数
            num++;
        }
        // Vector的扩容策略是找一块更大的空间复制原来的东西过去,所以首地址会变
    }
    //如果没有利用reserve预留空间,那么编译器要new18次内存,但是预留了之后只需要new一次
    cout << "num = " << num << endl;

    //总结:如果一开始数据量比较大可以用reserve预留空间来减少编译器new的次数
}
int main()
{
    test01();
    return 0;
}

下面介绍的是string这个C++内置的字符串容器

string:

string的本质

// string本质是一个类,底层是一个char*在维护
#include <iostream>
using namespace std;
//用string必须包含这个头文件
#include <string>
#include <algorithm>

void test01()
{
    //默认构造
    string s1;

    //可以用一个c语言风格的字符串来初始化string
    const char *str = "hello,world";
    //有参构造
    string s2(str);
    cout << "s2 = " << s2 << endl;

    //拷贝构造
    string s3(s2);
    cout << "s3 = " << s3 << endl;

    //成员函数,其本质是复制10个字符a到数组中
    string s4(10, 'a');
    cout << "s4 = " << s4 << endl;
}
int main()
{
    test01();
    return 0;
}

string的赋值操作

// string的赋值操作
#include <iostream>
using namespace std;
#include <algorithm>
#include <string>
void test01()
{
    string str1;
    //正常赋值
    str1 = "hello,world";
    cout << "str1  = " << str1 << endl;

    string str2;
    //拷贝构造,其底层利用的函数重载=号
    str2 = str1;
    cout << "str2 = " << str2 << endl;

    string str3;
    str3 = 'a';
    cout << "str3 = " << str3 << endl;

    string str4;
    //利用内置的模板函数赋值
    str4.assign("hello C++");
    cout << "str4 = " << str4 << endl;

    string str5;
    //将字符串的前5个字符拿过来保存到str5中
    str5.assign("hello C++", 5);
    cout << "str5 = " << str5 << endl;

    string str6;
    //利用拷贝构造函数赋值
    str6.assign(str5);
    cout << "str6 = " << str6 << endl;

    string str7;
    //复制10个v字符到str7中
    str7.assign(10, 'v');
    cout << "str7 = " << str7 << endl;
}
int main()
{
    test01();
    return 0;
}

string 字符串拼接

// string 字符串拼接
#include <iostream>
using namespace std;
#include <algorithm>
#include <string>
void test01()
{
    string str1 = "i";
    //通过+=号实现字符串拼接
    str1 += " love you";
    cout << "str1 = " << str1 << endl;
    //追加字符
    str1 += ':';
    cout << "str1 = " << str1 << endl;

    string str2 = "LOL DNF";
    str1 += str2;
    cout << "str1 = " << str1 << endl;

    string str3 = "T";
    //通过成员函数拼接字符串
    str3.append(" Love ");
    cout << "str3 = " << str3 << endl;
    str3.append("game abcde", 4);
    //将字符串中的前4个字符拼接到str3原本的字符串的后面
    cout << "str3 = " << str3 << endl;
    //将str2字符串中的内容追加到str3后面
    // str3.append(str2);
    //将str2中从0号位置开始到3号位置结束的0~2下标的3个字符串截取到str3中
    // str3.append(str2, 0, 3);
    //将str2中的从第4号位置开始(0~3)往后的3个字符截取到str3字符串中,参数1是从哪个位置开始截取,参数2是截取字符的个数
    str3.append(str2, 4, 3);
    cout << "str3 = " << str3 << endl;
}
int main()
{
    test01();
    return 0;
}

string的查找和替换

// string的查找和替换
#include <iostream>
using namespace std;
#include <string>
// 1.查找
void test01()
{
    string str1 = "abcdefgde";
    //查找str1字符串中有没有de这个字符串,从0号位置开始查找,返回值是一个下标
    int pos = str1.find("de");
    //如果没有这个字符串存在就返回-1
    if (pos == -1)
    {
        cout << "find error!" << endl;
    }
    else
    {
        // 3 返回的是字符第一次出现的位置
        cout << "pos = " << pos << endl;
    }

    // rfind和find的区别是:find是从左往右查,rfind是从右往左查
    pos = str1.rfind("de");
    cout << "pos = " << pos << endl;
}
// 2.替换
void test02()
{
    string str1 = "abcdefg";
    // replace替换函数,把从1号位置起,往后3个字符(bcd)替换成1111
    str1.replace(1, 3, "1111");
    // a1111efg
    cout << "str1 = " << str1 << endl;
}
int main()
{
    // test01();
    test02();
    return 0;
}

string字符串比较

// string字符串比较
#include <iostream>
using namespace std;
#include <string>

void test01()
{
    //字符串比较是按ASCII进行比较的,一个一个字符的比
    string str1 = "hello";
    string str2 = "xello";
    //调用成员函数进行比较,如果是相等则返回0
    if (str1.compare(str2) == 0)
    {
        cout << "str1==str2" << endl;
    }
    else if (str1.compare(str2) > 0) //这里的意思是说把str1的所有字符按ASCII值逐个跟str2进行比较,如果出现str1当中的某个ASCII值大于str2的情况则返回1
    {
        cout << "str1>str2" << endl;
    }
    else
    {
        cout << "str1<str2" << endl;
    }
}
int main()
{
    test01();
    return 0;
}

string的字符存取

// string 字符存取
#include <iostream>
using namespace std;
#include <string>

void test01()
{
    string str = "hello";
    // cout << "str = " << str << endl;
    // 1.通过[]访问单个字符,其底层是函数重载,size()获取字符串的长度
    for (int i = 0; i < str.size(); i++)
    {
        cout << str[i] << " ";
    }
    cout << endl;
    // 2.通过成员函数at的方式访问单个字符
    for (int i = 0; i < str.size(); i++)
    {
        cout << str.at(i) << " ";
    }
    cout << endl;

    //修改单个字符,[]的方式
    str[0] = 'x';
    // xello
    cout << "str = " << str << endl;

    //修改单个字符,at的方式:
    str.at(1) = 'x';
    // xxllo
    cout << "str = " << str << endl;
}
int main()
{

    test01();
    return 0;
}

string的插入和删除

// string的插入和删除
#include <iostream>
using namespace std;
#include <string>

void test01()
{
    string str = "hello";
    //插入,在第1号位置(e)的前面插入111
    str.insert(1, "111");
    // h111ello
    cout << "str = " << str << endl;

    //删除,把从第1号位置(1)起,往后3个字符(111)删除
    str.erase(1, 3);
    // hello
    cout << "str = " << str << endl;
}
int main()
{
    test01();
    return 0;
}

string子串(字符串截取)

// string子串(字符串截取)
#include <iostream>
using namespace std;
#include <string>
void test01()
{
    string str = "abcdef";
    //把从第1号位置开始起,往后3个字符(bcd)截取到substr中
    string substr = str.substr(1, 3);
    cout << "substr = " << substr << endl;
}
//实用操作
void test02()
{
    string email = "zhangsan@email.com";
    //从邮件的地址中获取用户名的信息,也就是获取@字符前面的字符串
    //先找到@字符的下标
    int pos = email.find("@");
    //从0开始起,截取pos(8)个字符到userName中
    //因为从0号位置起是包含0的,所以截取8个实际上截取的是0~7
    string userName = email.substr(0, pos);
    cout << "userName = " << userName << endl;
}
int main()
{
    // test01();
    test02();
    return 0;
}

下面介绍的是stack这个C++内置的栈容器

stack:

stack容器的用法

// stack容器
#include <iostream>
using namespace std;
//使用栈容器需要包含的头文件
#include <stack>
void test01()
{
    //创建一个栈
    stack<int> s;
    //栈是一种先进后出,后进先出的容器
    //入栈
    s.push(10);
    s.push(20);
    s.push(30);
    s.push(40);

    //查看栈的长度
    cout << "s size:" << s.size() << endl;

    //判断栈是否为空,为空返回真,不为空返回假,通过取反的操作循环遍历出栈,直到栈为空为止
    while (!s.empty())
    {
        //查看栈顶元素 40 30 20 10 因为是先进后出,40是最后进的栈,所以先输出40
        cout << "top: " << s.top() << endl;
        //出栈
        s.pop();
    }

    //查看栈的长度
    cout << "s size:" << s.size() << endl;
}
int main()
{
    test01();
    return 0;
}

下面介绍的是queue这个C++内置的队列容器

queue:

queue容器的基本用法

// queue容器
#include <iostream>
using namespace std;
//使用队列容器需要包含的头文件
#include <queue>
#include <string>
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};
void test01()
{
    //队列是一个先进先出的容器
    //创建一个队列
    queue<Person> q;
    //队列也可以存储自定义的数据类型
    Person p1("tanshen", 30);
    Person p2("swk", 100);
    Person p3("zbj", 900);
    Person p4("sashen", 800);
    //入队
    q.push(p1);
    q.push(p2);
    q.push(p3);
    q.push(p4);

    //查看队列的大小
    cout << "q size: " << q.size() << endl;

    //判断队列是否为空,为空返回真,通过取反的操作一直循环出队,直到队列为空为止
    while (!q.empty())
    {
        //查看队头
        cout << "top--name: " << q.front().m_Name << " age: " << q.front().m_Age << endl;
        //查看队尾
        cout << "back--name: " << q.back().m_Name << " age: " << q.back().m_Age << endl;

        //出队
        q.pop();
    }
    //查看队列的大小
    cout << "q size: " << q.size() << endl;
}
int main()
{
    test01();
    return 0;
}

下面介绍的是set这个C++内置的集合容器

set:

set容器的构造和赋值

// set容器的构造和赋值
#include <iostream>
using namespace std;
//使用set集合容器必须要加这个头文件
#include <set>
void printSet(const set<int> &s)
{
    for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    // set容器不允许插入重复的数据,且容器内部是有序的,其底层是一个二叉树
    set<int> s1;
    //插入数据,注意:set没有尾插和头插,只有insert插入方式
    s1.insert(100);
    s1.insert(20);
    s1.insert(300);
    s1.insert(40);
    s1.insert(500);
    //这里最后的20不会显示,因为set不允许插入重复值
    s1.insert(20);
    //无论插入的是否有序,set内部都会自动排序
    printSet(s1);

    //拷贝构造 将s1的数据全部拷贝到s2中
    set<int> s2(s1);
    printSet(s2);

    // operator=赋值
    set<int> s3;
    s3 = s2;
    printSet(s3);
}
int main()
{
    test01();
    return 0;
}

set大小和交换

// set大小和交换
#include <iostream>
using namespace std;
#include <set>
void printSet(const set<int> &s)
{
    for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
//大小
void test01()
{
    set<int> s1;
    //插入数据
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    s1.insert(40);

    //打印容器
    printSet(s1);

    //判断set是否为空,为空返回真
    if (s1.empty())
    {
        cout << "s1 NULL" << endl;
    }
    else
    {
        cout << "s1 not NULL" << endl;
        //查看set的元素个数
        cout << "s1 size: " << s1.size() << endl;
    }
}
//交换
void test02()
{
    set<int> s1;
    //插入数据
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    s1.insert(40);
    set<int> s2;
    //插入数据
    s2.insert(100);
    s2.insert(200);
    s2.insert(300);
    s2.insert(400);
    //交换前
    cout << "open: " << endl;
    printSet(s1);
    printSet(s2);
    //交换
    s1.swap(s2);
    //交换后
    cout << "end: " << endl;
    printSet(s1);
    printSet(s2);
}
int main()
{
    // test01();
    test02();
    return 0;
}

set插入和删除

// set插入和删除
#include <iostream>
using namespace std;
#include <set>
void printSet(const set<int> &s)
{
    for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    set<int> s1;
    //插入
    s1.insert(30);
    s1.insert(30);
    s1.insert(20);
    s1.insert(40);
    //输出
    printSet(s1);

    //删除 set中的第一个元素 因为set内部会自动排序,所以删除的其实是20,不是第一个插入的30
    s1.erase(s1.begin());
    printSet(s1);

    //删除的重载版本,直接传入数据就可以自动删除容器中对应的数据
    s1.erase(40);
    printSet(s1);

    //清空区间的值
    s1.erase(s1.begin(), s1.end());
    printSet(s1);

    //清空,跟上面一样的效果
    s1.clear();
    printSet(s1);
}
int main()
{
    test01();
    return 0;
}

set的查找和统计

// set的查找和统计
#include <iostream>
using namespace std;
#include <set>
void test01()
{
    set<int> s1;
    //插入数据
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    s1.insert(40);
    //查找 返回的是一个迭代器
    set<int>::iterator pos = s1.find(40);
    //如果返回的不是容器当中的尾指针则表示找到了
    if (pos != s1.end())
    {
        cout << "find success!" << *pos << endl;
    }
    else
    {
        cout << "find error!" << endl;
    }
}
//统计
void test02()
{
    set<int> s1;
    //插入数据
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    s1.insert(30);
    s1.insert(30);
    s1.insert(30);
    s1.insert(40);
    s1.insert(30);

    //统计30的个数
    int num = s1.count(300);
    // 1 不过插入多少相同的数在set里面都只有1个
    cout << "num: " << num << endl;
}
int main()
{
    // test01();
    test02();
    return 0;
}

set与multiset的区别

// set与multiset的区别
#include <iostream>
using namespace std;
#include <set>
void test01()
{
    set<int> s;

    // set的底层是一个pair的数据类型,而pair是一个成对出现的数据类型
    //下面定义一个pair的数据类型,第一个数据类型是迭代器,第二个数据类型是bool
    //可以用这个数据类型定义一个变量用来接收set插入返回的结果
    pair<set<int>::iterator, bool> ret = s.insert(10);

    // ret是一个set+bool的数据类型,如果为真则表示set插入成功
    if (ret.second)
    {
        //插入成功
        cout << "insert success!" << endl;
    }
    else
    {
        //插入失败
        cout << "insert error!" << endl;
    }

    ret = s.insert(10);
    //在第二次向set容器插入相同的数据时插入失败了
    if (ret.second)
    {
        //插入成功
        cout << "insert2 success!" << endl;
    }
    else
    {
        //插入失败
        cout << "insert2 error!" << endl;
    }

    //这是multiset,允许往容器中插入相同的数据
    multiset<int> ms;
    //允许插入重复值,其它的成员函数和set相同
    ms.insert(10);
    ms.insert(10);
    ms.insert(10);
    ms.insert(10);
    for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
int main()
{
    test01();
    return 0;
}

set容器排序

// set容器排序
#include <iostream>
#include <set>
using namespace std;
class MyCompare
{
public:
    //利用函数重载进行排序,第一个()代表重载()符号,第二个()代表函数的参数列表
    //仿函数的返回值是一个bool类型
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void printSet(const set<int> &s)
{
    for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
//因为原本的模板列表变了,所以不能再用上面的,要重写输出函数
void printSet2(const set<int, MyCompare> &s)
{
    for (set<int, MyCompare>::const_iterator it = s.begin(); it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    // set容器本身是有序的,但是可以通过仿函数修改它的排序规则
    set<int> s1;
    for (int i = 10; i < 15; i++)
    {
        for (int j = 15; j >= i; j--)
        {
            s1.insert(j);
        }
    }
    //排序前
    cout << "open: " << endl;
    printSet(s1);

    //默认是升序排序,指定排序规则为降序排序
    set<int, MyCompare> s2;
    for (int i = 10; i < 15; i++)
    {
        for (int j = 15; j >= i; j--)
        {
            s2.insert(j);
        }
    }
    //排序后:
    cout << "end: " << endl;
    printSet2(s2);
}
int main()
{
    test01();
    return 0;
}

set容器排序2—自定义数据类型排序

// set容器排序2--自定义数据类型排序
#include <iostream>
using namespace std;
#include <set>
#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 comparePerson
{
public:
    //在对比过程中不可修改,所以要加上const
    bool operator()(const Person &p1, const Person &p2)
    {
        //按照年龄 降序
        return p1.m_Age > p2.m_Age;
    }
};
//输出
void printSet(const set<Person, comparePerson> &s)
{
    for (set<Person, comparePerson>::const_iterator it = s.begin(); it != s.end(); it++)
    {
        cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
    }
}

void test01()
{
    //利用仿函数修改排序规则
    set<Person, comparePerson> s;
    //创建Perosn对象
    Person p1("liubei", 24);
    Person p2("zs", 28);
    Person p3("lisi", 25);
    Person p4("wangwu", 21);
    //插入数据
    s.insert(p1);
    s.insert(p2);
    s.insert(p3);
    s.insert(p4);

    //遍历数据
    printSet(s);
}
int main()
{
    test01();
    return 0;
}

下面介绍的是pair这个C++内置的对组容器,一般都和map哈希表容器配合使用

pair:

pair容器的基本用法

// pair对组容器
#include <iostream>
using namespace std;
#include <string>
void test01()
{
    //使用pair不需要引入其他头文件
    //创建pair,<>括号里面是两个不同的数据类型,()括号里面是给这两个不同的类型赋初值,也可以理解为有参构造函数
    pair<string, int> p("Tom", 20);
    //输出pair里面的值,第一个值是first,第二个值是second
    cout << "name: " << p.first << " age: " << p.second << endl;

    //第二种方式: 在make_pair里面赋值
    pair<string, int> p2 = make_pair("Jerry", 30);
    //访问第一个数据是first,访问第二个数据是second
    cout << "name: " << p2.first << " age: " << p2.second << endl;
}
int main()
{
    test01();
    return 0;
}

下面介绍的是map这个C++内置哈希表容器

map:

map容器构造和赋值

// map容器构造和赋值
#include <iostream>
using namespace std;
//要使用哈希容器需要引入这个头文件
#include <map>
void printMap(const map<int, int> &m)
{
    for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
    {
        //在map输出时要输出一个对组,可以用(*it).的方式,也可以用->指针的方式,first是对组左边的值,second是对组右边的值
        cout << "key: " << (*it).first << " value: " << it->second << endl;
    }
    cout << endl;
}
void test01()
{
    // map底层是用二叉树实现的
    //创建一个map,<>符号里面的值是成对出现的,第一个是key值,起到索引作用,第二个是value值,起到实值的作用
    map<int, int> m;

    //插入数据,因为map里面的值是成对出现的,所以要使用pair成对的插入值
    //可以理解为一个map里面存放着多个pair,其中左边的1起到的是索引key的作用,右边的10起到的是value实值的作用
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(3, 30));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(4, 40));
    //输出 注意:无论插入的顺序是什么,最后还是会按照key的顺序排序
    printMap(m);

    //拷贝构造
    map<int, int> m2(m);
    printMap(m);

    //赋值
    map<int, int> m3;
    m3 = m2;
    printMap(m3);
}
int main()
{
    test01();
    return 0;
}

map容器大小和交换

// map容器大小和交换
#include <iostream>
using namespace std;
#include <map>
void printMap(const map<int, int> &m)
{
    for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
    {
        cout << "key: " << it->first << " value: " << it->second << endl;
    }
    cout << endl;
}
//大小
void test01()
{
    map<int, int> m;
    //通过pair往map里插入数据
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(3, 30));

    //判断map是否为空,如果为空则返回真
    if (m.empty())
    {
        //为空
        cout << "map NULL!" << endl;
    }
    else
    {
        //不为空
        cout << "map not NULL!" << endl;
        //查看map的长度
        cout << "m size: " << m.size() << endl;
    }
}
//交换
void test02()
{
    map<int, int> m;
    //通过pair往map里插入数据
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(3, 30));

    map<int, int> m2;
    //通过pair往map里插入数据
    m2.insert(pair<int, int>(4, 100));
    m2.insert(pair<int, int>(5, 200));
    m2.insert(pair<int, int>(6, 300));

    //交换前
    cout << "open: " << endl;
    printMap(m);
    printMap(m2);

    //交换
    m.swap(m2);

    //交换后
    cout << "end: " << endl;
    printMap(m);
    printMap(m2);
}
int main()
{
    // test01();
    test02();
    return 0;
}

map的插入和删除

// map的插入和删除
#include <iostream>
using namespace std;
#include <map>
void printMap(const map<int, int> &m)
{
    for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
    {
        cout << "key: " << it->first << " value: " << it->second << endl;
    }
    cout << endl;
}
void test01()
{
    map<int, int> m;
    //第一种插入方式:
    m.insert(pair<int, int>(1, 10));

    //第二种插入方式: make_pair也可以创建出一个对组
    m.insert(make_pair(2, 20));

    //第三种 通过迭代器插入
    m.insert(map<int, int>::value_type(3, 30));

    //第四种: 通过重载运算符[]的方式插入,[]里面的值代表key,=右边的值代表value
    m[4] = 40;

    //也可以利用[] 访问到value,但是要注意key下标越界的问题,如果越界了那么value会默认为0
    cout << m[4] << endl;

    //输出
    printMap(m);

    //删除 将map中第一个元素删除
    m.erase(m.begin());
    printMap(m);

    //通过key的方式删除,将map中key为3的数据删除,注意:不能按照value删除
    m.erase(3);
    printMap(m);

    //按照区间的方式清空
    m.erase(m.begin(), m.end());

    //清空,跟上面一样
    m.clear();
}
int main()
{
    test01();
    return 0;
}

map的查找和统计

// map的查找和统计
#include <iostream>
using namespace std;
#include <map>
void test01()
{
    map<int, int> m;
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(3, 30));

    //通过key查找,返回一个迭代器
    map<int, int>::iterator pos = m.find(3);

    //如果迭代器不等于尾指针则表示找到了
    if (pos != m.end())
    {
        //输出找到的key和value值
        cout << "find success! key = " << (*pos).first << " value = " << (*pos).second << endl;
    }
    else
    {
        cout << "find error!" << endl;
    }
    //统计,通过key找到对应的值的个数
    m.insert(pair<int, int>(3, 30));
    m.insert(pair<int, int>(3, 40));
    m.insert(pair<int, int>(3, 50));
    //注意:map不允许插入重复的key的元素,无论插入多少,只要key是相同的那么就只会保留第一个插入的数据
    // multimap的统计个数可能会大于1
    int num = m.count(3);
    //所以统计map的key的个数num永远是1
    cout << "num = " << num << endl;
    cout << m[3] << endl;
}
int main()
{
    test01();
    return 0;
}

map容器排序

// map容器排序
#include <iostream>
using namespace std;
#include <map>
class MyCompare
{
public:
    //仿函数
    bool operator()(int v1, int v2)
    {
        //降序
        return v1 > v2;
    }
};
void printMap(const map<int, int, MyCompare> &m)
{
    for (map<int, int, MyCompare>::const_iterator it = m.begin(); it != m.end(); it++)
    {
        cout << "key: " << it->first << " value: " << it->second << endl;
    }
    cout << endl;
}
void test01()
{
    // map默认的排序规则是按key值从小到大升序排序,要改变排序规则需要借助仿函数
    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));

    printMap(m);
}
int main()
{
    test01();
    return 0;
}

map容器排序-自定义数据类型排序

// map容器排序-自定义数据类型排序
#include <iostream>
using namespace std;
#include <map>
#include <string>
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Age = age;
        this->m_Name = name;
    }
    string m_Name;
    int m_Age;
};
class MyCompare
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void printMap(const map<int, Person, MyCompare> &m)
{
    for (map<int, Person, MyCompare>::const_iterator it = m.begin(); it != m.end(); it++)
    {
        cout << "key-age: " << it->first << " value-name: "
             << it->second.m_Name << " age: " << it->second.m_Age << endl;
    }
    cout << endl;
}
void test01()
{
    //利用仿函数修改排序规则
    map<int, Person, MyCompare> m;
    Person p1("zs", 18);
    Person p2("lisi", 20);
    Person p3("wangwu", 28);
    Person p4("zaoliu", 19);
    //将对象里的年龄作为key
    m.insert(make_pair(p1.m_Age, p1));
    m.insert(make_pair(p2.m_Age, p2));
    m.insert(make_pair(p3.m_Age, p3));
    m.insert(make_pair(p4.m_Age, p4));
    printMap(m);
}
int main()
{
    test01();
    return 0;
}

下面介绍的是list这个C++内置双向链表容器

list:

list容器的基本使用

// list容器
#include <iostream>
using namespace std;
//使用链表需要包含的头文件
#include <list>
//输出
void printList(const list<int> &L)
{
    for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    //链表可以对任意位置插入和删除元素
    //缺点:遍历元素没有数组快,占用的空间比数组大
    //创建一个链表
    list<int> L1;
    // STL中的链表是一个双向链表,也就是每个节点有两个指针,一个指向前,一个指向后

    //利用尾插添加数据
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);

    //遍历
    printList(L1);

    //利用区间的方式构造,将L1区间中所有的数据复制到L2中
    list<int> L2(L1.begin(), L1.end());
    printList(L2);

    //拷贝构造
    list<int> L3(L2);
    printList(L3);

    // n个elem,将10个1000复制到L4中
    list<int> L4(10, 1000);
    printList(L4);
}
int main()
{
    test01();
    return 0;
}

list赋值和交换

// list赋值和交换
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
    for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    list<int> L1;
    //利用尾插添加数据进链表
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);
    printList(L1);

    //利用operator=赋值
    list<int> L2;
    L2 = L1;
    printList(L2);

    //利用区间赋值
    list<int> L3;
    L3.assign(L2.begin(), L2.end());
    printList(L3);

    list<int> L4;
    // n个elem方式,也就是10个100赋值给L4
    L4.assign(10, 100);
    printList(L4);
}
//交换
void test02()
{
    list<int> L1;
    //利用尾插添加数据进链表
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);

    list<int> L2;
    //将10个100赋值给L2
    L2.assign(10, 100);
    //交换前:
    cout << "open: " << endl;
    printList(L1);
    printList(L2);

    //交换,将L1和L2中的元素进行交换
    L1.swap(L2);

    //交换后
    cout << "end: " << endl;
    printList(L1);
    printList(L2);
}
int main()
{
    // test01();
    test02();
    return 0;
}

list大小操作

// list大小操作
#include <iostream>
using namespace std;
#include <list>
//输出
void printList(const list<int> &L)
{
    for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    list<int> L1;
    //利用尾插添加数据进链表
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);
    //输出
    printList(L1);

    //判断list容器是否为空,如果为空返回真
    if (L1.empty())
    {
        cout << "L1 NULL" << endl;
    }
    else
    {
        cout << "L1 not NULL" << endl;
        //输出list容器的长度(个数)
        cout << "L1 size:" << L1.size() << endl;
    }
    //重新指定大小,默认用0填充剩余空间
    // L1.resize(10);
    //重新指定大小,用1来填充剩余空间
    L1.resize(10, 1);
    printList(L1);
    //重新指定大小,如果超出则将超出的部分删除
    L1.resize(2);
    printList(L1);
}
int main()
{
    test01();
    return 0;
}

list插入和删除

// list插入和删除
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
    for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    list<int> L;
    //尾插
    L.push_back(10);
    L.push_back(20);
    L.push_back(30);

    //头插
    L.push_front(100);
    L.push_front(200);
    L.push_front(300);

    //输出 300 200 100 10 20 30 因为100~300是头插的,10~30是尾插的,所以300在最前面
    printList(L);

    //尾删 300 200 100 10 20 将最后一个元素30给删除了
    L.pop_back();
    printList(L);

    //头删 200 100 10 20 将第一个元素300给删除了
    L.pop_front();
    printList(L);

    //指定位置插入,在头部第一个元素的前面插入1000
    L.insert(L.begin(), 1000);
    // 1000 200 100 10 20
    printList(L);

    //通过迭代器插入
    list<int>::iterator it = L.begin();
    //在第二个元素(200)的前面插入2000
    L.insert(++it, 2000);
    // 1000 2000 200 100 10 20
    printList(L);

    //删除
    it = L.begin();
    //将头部第一个元素(1000)删除
    L.erase(it);
    // 2000 200 100 10 20
    printList(L);

    //通过迭代器将第二个元素(200)删除
    it = L.begin();
    L.erase(++it);
    printList(L);

    //移除
    //尾插10000
    L.push_back(10000);
    L.push_back(10000);
    L.push_back(10000);
    L.push_back(10000);
    printList(L);
    //利用成员函数remove直接把10000删除,括号里面写要删除的数据,所有匹配的值都会被删除
    L.remove(10000);
    printList(L);

    //清空
    L.clear();
    printList(L);
}
int main()
{
    test01();
    return 0;
}

list数据存取

// list数据存取
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
    for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    list<int> L1;
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);

    // L1[0] 不可以用中括号的方式访问list中的元素
    // L1.at(0) 不可以用at的方式访问list中的元素
    //原因:链表的数据不是连续存储的,不能用访问数组的方式访问链表
    printList(L1);

    //访问第一个元素
    cout << "top: " << L1.front() << endl;
    //访问最后一个元素
    cout << "back: " << L1.back() << endl;

    //迭代器不支持随机访问
    list<int>::iterator it = L1.begin();
    //错误,不允许直接+数,只能++或者--
    // it = it + 1;
    it++;
    it--;
}
int main()
{
    test01();
    return 0;
}

list反转和排序

// list反转和排序
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
    for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
//反转
void test01()
{
    list<int> L1;
    for (int i = 1; i < 5; i++)
    {
        for (int j = 5; j >= i; j--)
        {
            L1.push_back(j);
        }
    }
    //反转前
    cout << "open: " << endl;
    printList(L1);

    //反转
    L1.reverse();
    //反转后
    cout << "end: " << endl;
    printList(L1);
}
//函数重载,使list的排序降序排序
bool myCompare(int v1, int v2)
{
    return v1 > v2;
}
//排序
void test02()
{
    list<int> L1;
    for (int i = 1; i < 5; i++)
    {
        for (int j = 5; j >= i; j--)
        {
            L1.push_back(j);
        }
    }
    //排序前:
    cout << "open: " << endl;
    printList(L1);
    //默认升序排序,注意:不能用algorithm里面的sort排序模板,因为list不支持随机访问迭代器
    //可以用内置的成员函数sort进行排序
    L1.sort();
    //排序后
    cout << "end: " << endl;
    printList(L1);
    //利用函数重载降序排序
    L1.sort(myCompare);
    //降序排序后:
    printList(L1);
}
int main()
{
    // test01();
    test02();
    return 0;
}

list排序案例-自定义数据类型排序

// 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;
    }
    else
    {
        //按照年龄 升序排序:
        return p1.m_Age < p2.m_Age;
    }
}
void printList(list<Person> &L)
{
    for (list<Person>::const_iterator it = L.begin(); it != L.end(); it++)
    {
        cout << "name: " << (*it).m_Name << " age: " << (*it).m_Age << " height: " << (*it).m_Height << endl;
    }
}
void test01()
{
    list<Person> L1;
    Person p("swk", 20, 181);
    Person p1("zbj", 29, 190);
    Person p2("tanshen", 19, 175);
    Person p3("shashen", 18, 165);
    Person p4("zs", 18, 200);
    Person p5("lisi", 29, 195);
    //向容器中插入数据
    L1.push_back(p);
    L1.push_back(p1);
    L1.push_back(p2);
    L1.push_back(p3);
    L1.push_back(p4);
    L1.push_back(p5);
    //输出排序前:
    cout << "open: " << endl;
    printList(L1);
    cout << "------------------------------" << endl;
    //排序,括号里面的是通过函数重载指定排序规则:
    L1.sort(comparePerson);
    //排序后:
    cout << "end: " << endl;
    printList(L1);
}
int main()
{
    test01();
    return 0;
}

下面介绍的是deque这个C++内置双端队列容器

deque:

deque容器的基本使用

// deque构造函数
#include <iostream>
using namespace std;
//使用deque容器必须包含这个头文件
#include <deque>

//输出,加了const后就变成了只读的一个迭代器
void printDeque(const deque<int> &d)
{
    //通过迭代器输出
    for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
    {
        //错误,加了const后容器中的数据就只读不可修改了
        //*it = 100;
        
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    deque<int> d1;
    //通过尾插法插入数据
    for (int i = 0; i < 10; i++)
    {
        d1.push_back(i);
    }
    printDeque(d1);
    //通过两个成员函数把d1所有区间的数据都赋值给d2
    deque<int> d2(d1.begin(), d1.end());
    printDeque(d2);

    //将10个100赋值给d3
    deque<int> d3(10, 100);
    printDeque(d3);
    //拷贝构造,把d3赋值给d4
    deque<int> d4(d3);
    printDeque(d4);
}
int main()
{
    test01();
    return 0;
}

deque赋值操作

// deque赋值操作
#include <iostream>
using namespace std;
#include <deque>
void printDeque(const deque<int> &d)
{
    for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    deque<int> d1;
    for (int i = 0; i < 10; i++)
    {
        d1.push_back(i);
    }
    //打印
    printDeque(d1);
    // operator=号赋值
    deque<int> d2;
    d2 = d1;
    printDeque(d2);

    // assign赋值
    deque<int> d3;
    d3.assign(d1.begin(), d1.end());
    printDeque(d3);

    deque<int> d4;
    //赋值10个100
    d4.assign(10, 100);
    printDeque(d4);
}
int main()
{
    test01();
    return 0;
}

deque判断元素大小和长度

// deque判断元素大小和长度
#include <iostream>
using namespace std;
#include <deque>
void printDeque(const deque<int> &d)
{
    for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    // deque其底层有一个中控器来控制里面的容器,无论增加多少个元素进去只要中控器能管理到就可以一直增加
    deque<int> d1;
    for (int i = 0; i < 10; i++)
    {
        d1.push_back(i);
    }
    //打印
    printDeque(d1);

    //判断是否为空,空返回真
    if (d1.empty())
    {
        cout << "d1 NULL" << endl;
    }
    else
    {
        cout << "d1 not NULL" << endl;
        //获取容器的长度
        cout << "d1 size: " << d1.size() << endl;
        
        //注意:deque没有返回容量的成员函数
    }
    //重新指定大小,用0来填充多余的空间
    d1.resize(15);
    printDeque(d1);
    //重新指定大小,指定用1来填充多余的空间
    d1.resize(15, 1);
    //重新指定大小,超出的部分会被删除
    d1.resize(5);
}
int main()
{
    test01();
    return 0;
}

deque的插入和删除

// deque的插入和删除
#include <iostream>
using namespace std;
#include <deque>
void printDeque(const deque<int> &d)
{
    for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    deque<int> d1;
    //尾插
    d1.push_back(10);
    d1.push_back(20);
    d1.push_back(30);
    d1.push_back(40);
    //头插
    d1.push_front(100);
    d1.push_front(200);

    //打印 200 100 10 20 30 40  因为10~40是从尾部插入的,而200和100是从头部插入的,所以顺序不同
    printDeque(d1);
    //尾删
    d1.pop_back();
    printDeque(d1);
    //头删
    d1.pop_front();
    printDeque(d1);
}
void test02()
{
    deque<int> d1;
    d1.push_back(10);
    d1.push_back(20);
    d1.push_front(100);
    d1.push_front(200);
    // 200 100 10 20
    printDeque(d1);
    //在头部第一个元素的前面插入1000
    d1.insert(d1.begin(), 1000);
    //在头部第一个元素的前面插入2个10000
    d1.insert(d1.begin(), 2, 10000);
    // 10000 10000 1000 200 100 10 20
    printDeque(d1);

    //按照区间进行插入
    deque<int> d2;
    d2.push_back(1);
    d2.push_back(2);
    d2.push_back(3);
    //在d1的头部第一个元素的前面插入d2的全部数据
    d1.insert(d1.begin(), d2.begin(), d2.end());
    printDeque(d1);
}
void test03()
{
    deque<int> d1;
    d1.push_back(10);
    d1.push_back(20);
    d1.push_front(100);
    d1.push_front(200);

    //删除
    deque<int>::iterator it = d1.begin();
    //迭代器一开始指向容器中第一个元素,it++后迭代器指向第二个元素
    it++;
    //利用迭代器将第二个元素删除
    d1.erase(it);
    // 200 10 20
    printDeque(d1);

    //按照区间的方式删除,其实也就是清空
    d1.erase(d1.begin(), d1.end());
    printDeque(d1);

    //利用成员函数清空
    d1.clear();
}
int main()
{
    // test01();
    // test02();
    test03();
    return 0;
}

deque的数据存取

// deque的数据存取
#include <iostream>
using namespace std;
#include <deque>
void test01()
{
    deque<int> d;
    d.push_back(10);
    d.push_back(20);
    d.push_back(30);
    d.push_front(100);
    d.push_front(200);
    d.push_front(300);
    //通过[]方式访问元素
    for (int i = 0; i < d.size(); i++)
    {
        // 300 200 100 10 20 30
        cout << d[i] << " ";
    }
    cout << endl;
    //通过at方式访问元素
    for (int i = 0; i < d.size(); i++)
    {
        cout << d.at(i) << " ";
    }
    cout << endl;
    //访问第一个元素
    cout << "one: " << d.front() << endl;
    //访问最后一个元素
    cout << "end: " << d.back() << endl;
}
int main()
{
    test01();
    return 0;
}

deque排序

// deque排序
#include <iostream>
using namespace std;
//标准算法头文件
#include <algorithm>
#include <deque>
void printDeque(const deque<int> &d)
{
    for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
bool cmp(int a, int b)
{
    return a > b;
}
void test01()
{
    deque<int> d;
    d.push_back(10);
    d.push_back(20);
    d.push_back(30);
    d.push_front(100);
    d.push_front(200);
    d.push_front(300);
    //升序排序
    sort(d.begin(), d.end());
    printDeque(d);
    //降序排序
    sort(d.begin(), d.end(), cmp);
    printDeque(d);
}
int main()
{
    test01();
    return 0;
}

下面介绍的是operator()这个C++内置仿函数重载的用法,以及谓词的概念。

operator():

仿函数重载()

//仿函数重载()
#include <iostream>
using namespace std;
#include <string>
class MyAdd
{
public:
    int operator()(int v1, int v2)
    {
        return v1 + v2;
    }
};
void test01()
{
    //当一个类里有operator()重载函数,那么创建出来的对象就称为函数对象
    //函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
    MyAdd myAdd;
    cout << myAdd(10, 10) << endl;
}

//函数对象超出普通函数的概念,可以有自己的状态
class MyPrint
{
public:
    MyPrint()
    {
        this->count = 0;
    }
    void operator()(string test)
    {
        cout << test << endl;
        //统计使用次数
        this->count++;
    }
    //记录内部的状态
    int count;
};
void test02()
{
    MyPrint myPrint;
    myPrint("hello world");
    myPrint("hello world");
    myPrint("hello world");
    myPrint("hello world");
    cout << "myPrint count: " << myPrint.count << endl;
}
//函数对象可以作为参数传递
void doPrint(MyPrint &mp, string test)
{
    //函数传了一个自定义类型数据,在传一个字符串,然后自定义数据在内部执行重载
    mp(test);
}
void test03()
{
    MyPrint myPrint;
    doPrint(myPrint, "Hello c++");
}
int main()
{
    // test01();
    // test02();
    test03();
    return 0;
}

一元谓词

//一元谓词
#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>
class GreaterFive
{
public:
    //一元谓词:只有一个参数,返回类型是bool
    bool operator()(int val)
    {
        return val > 5;
    }
};
void test01()
{
    //仿函数,返回值类型是bool类型,称为谓词
    //在operator()仿函数重载时小括号里一个参数就是一元,两个参数就是二元
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }

    //查找容器中大于5的数字
    // find_if是algorithm里面的模板算法,参数是传容器的区间,第三个参数传的是仿函数的函数对象
    //可以用匿名的函数对象GreaterFive()替代,返回的是一个迭代器,传入什么容器就用什么容器的迭代器接收
    vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
    //如果迭代器指向容器的尾指针则表示未找到
    if (it == v.end())
    {
        cout << "find error!" << endl;
    }
    else
    {
        //查找成功
        cout << "find success!" << endl;
        for (; it != v.end(); it++)
        {
            cout << *it << " ";
        }
    }
}
int main()
{
    test01();
    return 0;
}

二元谓词

//二元谓词
#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>
class MyCompare
{
public:
    //在对象里面重载()符号,是bool类型并有两个参数就是二元谓词
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void PrintVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(40);
    v.push_back(20);
    v.push_back(30);
    v.push_back(50);

    sort(v.begin(), v.end());
    //升序排序后:
    cout << "open: " << endl;
    PrintVector(v);

    //使用函数对象 修改算法规则 变为从大到小降序排序
    //这里的MyCompare就是正常的函数调用,只不过是匿名对象,在sort里面会调用这个函数,
    //这时用到就是函数重载运算符
    sort(v.begin(), v.end(), MyCompare());
    cout << "--------------------------------------" << endl;
    //降序排序后:
    cout << "end: " << endl;
    PrintVector(v);
}
int main()
{
    test01();
    return 0;
}

内建函数对象,算术仿函数

//内建函数对象,算术仿函数
#include <iostream>
using namespace std;
//使用内建函数对象需要包含这个头文件
#include <functional>
// negate 一元仿函数,取反仿函数
// plus 二元仿函数,加法
void test01()
{
    //容器,内建仿函数都是类模板
    //通过内置的函数创建一个函数对象
    negate<int> n;
    //对50进行取反: -50
    cout << n(50) << endl;
}
void test02()
{
    plus<int> p;
    //两个整型相加: 30
    cout << p(10, 20) << endl;

    /*
    类似的内置仿函数还有很多:
    minus<T> 减法
    multiplies<T> 乘法
    divides<T> 除法
    modulus<T> 取模
    */
}
int main()
{
    // test01();
    test02();
    return 0;
}

内建函数对象,关系仿函数

//内建函数对象,关系仿函数
#include <iostream>
using namespace std;
#include <functional>
#include <vector>
#include <algorithm>
class MyCompare
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void printVector(vector<int> &v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
void test01()
{
    //大于 greater<T>
    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(20);
    v.push_back(50);
    v.push_back(40);
    printVector(v);

    //利用自定义函数对象实现降序排序
    // sort(v.begin(), v.end(), MyCompare());

    //利用内置函数对象实现降序排序
    sort(v.begin(), v.end(), greater<int>());

    printVector(v);

    /*
    类似的关系仿函数还有很多:
    equal_to<T> 等于
    not_equal_to<T> 不等于
    greater<T> 大于
    greater_equal<T> 大于等于
    less<T> 小于
    less_equal<T> 小于等于
    */
}
int main()
{
    test01();
    return 0;
}

内建仿函数-逻辑仿函数

//内建仿函数-逻辑仿函数
#include <iostream>
using namespace std;
#include <functional>
#include <vector>
#include <algorithm>
void printVector(vector<bool> &v)
{
    for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
    {
        //可以在输出前面加上boolalpha让输出0/1变为输出false/true
        cout << boolalpha << *it << " ";
    }
    cout << endl;
}
void test01()
{
    //逻辑非 logical_not  也就是取反!
    vector<bool> v;
    // 在vector容器里:true为1,false为0
    v.push_back(true);
    v.push_back(false);
    v.push_back(true);
    v.push_back(false);
    printVector(v);

    //利用逻辑非 将容器v搬运到容器v2中,并执行取反操作
    vector<bool> v2;

    //将v2的大小变为v1的大小
    v2.resize(v.size());

    // transform包含在algorithm算法模板中
    //其作用是将第一个容器的内容搬运到第二个容器中,其中第一个参数和第二个参数是第一个容器的区间
    //第三个参数是要搬运到的容器的开始区间,第四个参数是逻辑仿函数用来取反,用来之后就
    //可以将第一个容器中搬运到第二个容器的数据全部取反
    transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());

    printVector(v2);

    /*
    类似的逻辑仿函数还有很多:
    logical_and<T> 逻辑与
    logical_or<T> 逻辑或
    */
}
int main()
{
    test01();
    return 0;
}