zoukankan      html  css  js  c++  java
  • C++进阶 STL(2) 第二天 一元/二元函数对象、一元/二元谓词、stack容器、queue容器、list容器(双向链表)、set容器、对组、map容器

    01 上次课程回顾

    昨天讲了三个容器

    string  string是对char*进行的封装

    vector 单口容器 动态数组

    deque(双端队列) 

    函数对象/谓词:

     

    一元函数对象:

    for_each:

    谓词: predicate

     

    一元谓词:

    find_if

     

    二元函数对象: transform

    transform操作: 两个容器相加 放到第三个

     

    class myplus {

    public:

        int operator()(int v1,int v2){

            return v1 + v2;

        }

    private:

    };

     

    void test03() {

     

        vector<int> v1,v2,v3;

        for (int i = 0; i < 10; i++)

        {

            v1.push_back(i);

            v2.push_back(i+1);

        }

     

     

        /*

        template<class _InIt1,

        class _InIt2,

        class _OutIt,

        class _Fn> inline

        _OutIt transform(const _InIt1 _First1, const _InIt1 _Last1,

            const _InIt2 _First2, _OutIt _Dest, _Fn _Func)

        {   // transform [_First1, _Last1) and [_First2, ...) with _Func

        _Adl_verify_range(_First1, _Last1);

        auto _UFirst1 = _Get_unwrapped(_First1);

        const auto _ULast1 = _Get_unwrapped(_Last1);

        const auto _Count = _Idl_distance<_InIt1>(_UFirst1, _ULast1);

        auto _UFirst2 = _Get_unwrapped_n(_First2, _Count);

        auto _UDest = _Get_unwrapped_n(_Dest, _Count);

        for (; _UFirst1 != _ULast1; ++_UFirst1, (void)++_UFirst2, ++_UDest)

            {

            *_UDest = _Func(*_UFirst1, *_UFirst2);  ←!最后的处理,这里是二元函数对象

            }

     

        _Seek_wrapped(_Dest, _UDest);

        return (_Dest);

        }

       

        v1+v2 放到v3的开始位置

     

        */

     

        v3.resize(v1.size());

     

     

        for_each(v1.begin(), v1.end(), print2);

        cout << endl;

        for_each(v2.begin(), v2.end(), print2);

        cout << endl;

        for_each(v3.begin(), v3.end(), print2);

        cout << endl;

     

     

     

        transform(v1.begin(), v1.end(), v2.begin(),v3.begin(), myplus()); // 匿名函数对象

     

        cout << "--------------" << endl;

     

        for_each(v1.begin(), v1.end(), print2);

        cout << endl;

        for_each(v2.begin(), v2.end(), print2);

        cout << endl;

        for_each(v3.begin(), v3.end(), print2);

        cout << endl;

    }

    二元谓词:

    class mycompare04 {

    public:

        bool operator()(int v1,int v2) {

            return v1 > v2; // 从大到小排序

        }

     

    };

     

    // 二元谓词 应用举例: sort

    void test04()

    {

       

        vector<int> v;

        v.push_back(5);

        v.push_back(2);

        v.push_back(7);

        v.push_back(9);

     

        /*

            template<class _RanIt,

            class _Pr> inline

            void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred)

            {   // order [_First, _Last), using _Pred

            _Adl_verify_range(_First, _Last);

            const auto _UFirst = _Get_unwrapped(_First);

            const auto _ULast = _Get_unwrapped(_Last);

            _Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred));

            }

       

        */

        sort(v.begin(), v.end(),mycompare04());

     

        for (vector<int>::iterator it = v.begin(); it != v.end(); it++ )

        {

     

            cout << *it << endl;

        }

    }

    02 stack容器课堂练习

    03 queue容器课堂练习

     

    04list容器概念

    STL中的list是双向链表

    一个节点有两个指针

    05 list容器基本操作

    mylist.sort(); // 默认从小到大

    传入函数对象或者函数指针让他从大到小

    对于对象的排序要指定排序方法。

    示例:

    06 set集合概念

      二叉树:

      一个节点 每个节点最多有两个子节点

      二叉搜索树:

    左子树都比父节点小

    右子树都比父节点大

    这个就叫二叉搜索树

    有可能出现左边深度很高 右边深度没那么高的清空

    平衡二叉搜索树(平衡二叉树)(尽量保证左子树和右子树深度一样):

    红黑树是平衡二叉树的一种 也是达到上面的效果

    set容器:

    内部是树,自动形成平衡二叉搜索树的机制,

    以平衡二叉树(红黑树)为底层实现机制

    set容器元素唯一

    multiset可以插入重复元素

    07 set初始化_插入和删除_find查找

    功能:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置.

    注意:如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!

    功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置

    注意:返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置。同样,如果val大于数组中全部元素,返回的是last。(注意:数组下标越界)

    equal_range返回的是一个pair

    pair.first 是lower_bound

    pair.second 是 upper_bound

    从大到小排序:

    方法一:

    方法二:

    其实内部就是等价于这个:

    实现对特定类的排序:

    multiset:

    08 上午课程回顾

    栈和队列没提供迭代器 因为内部有自己的实现规则

    09 对组

    10 map集合概念和四种插入方式区别

     

    #define _CRT_SECURE_NO_WARNINGS

    #include <iostream>

    #include <map>

    #include <string>

     

    using namespace std;

     

    // map容器初始化

    void test01()

    {

        // map容器的模板参数 需要制定key类型 value类型

        map<int, string> mymap; // 默认构造

        map<int, string> mymap2(mymap); // 拷贝构造

    }

     

    // map插入操作

    void test02() {

       

        map<int, int> mymap;

       

        // 第一种插入方式

       

        //pair<int, int> mypair(1, 5);

        //mymap.insert(mypair);

     

        mymap.insert(pair<int,int>(1,5));

        // 第二种

     

       

        pair<map<int,int>::iterator,bool> ret = mymap.insert(make_pair(2,10));

        if (ret.second) {

            cout << "插入成功" << endl;

        }

        else {

            cout << "插入失败" << endl;

        }

     

       

        // 第三种

        mymap.insert(map<int, int>::value_type(3, 15));

        // 第四种

        mymap[4] = 20;

        mymap[2] = 100;  // 如果key存在,会修改容器指定key元素的值

     

        // 如果你访问的key不存在,他会帮你把这个数据插入进去

     

     

        pair<map<int, int>::iterator, bool> ret2 = mymap.insert(map<int, int>::value_type(2, 210)); // 不能再插入了 已经有2这个key了

        if (ret2.second) {

            cout << "插入成功" << endl;

        }

        else {

            cout << "插入失败" << endl;

        }

     

     

        for (map<int, int>::iterator it = mymap.begin(); it != mymap.end(); it++)

        {

            cout << "key:" << it->first << " value:" << it->second << endl;

        }

     

        cout << endl;

    }

     

    int main(void)

    {

     

        test02();

     

        return 0;

    }

    12  multimap课堂案例

     

    /*

    公司今天照片了5个员工

    5个员工进入公司之后 需要指派员工在哪个部门工作

    人员信息有:姓名 年龄 电话 工资等组成

    通过Multimap进行信息的插入 保存 显示

    分部门显示员工信息 显示全部员工信息

    */

    #include <iostream>

    #include <vector>

    #include <map>

    using namespace std;

    /*

        公司今天入职了5个员工

        5个员工进入公司之后需要指派员工在哪个部门工作

        人员信息有:姓名年龄电话工资等组成

        通过multimap进行信息的插入保存显示

        分部门显示员工信息显示全部员工信息

    */

     

    #define SALE_DEPARTMENT 1 // 销售部

    #define DEVELOP_DEPARTMENT 2 // 开发部

    #define FINACIAL_DEPARTMENT 3 // 财务部

     

    class Yuangong

    {

        public:

        string name;

        int age;

        string tele;

        double salary;

    };

     

    // 创建员工 5

    // 返回值 void

    void Create_Yuangong( vector<Yuangong> &v )

    {

        // 名字的随机数种子

        string nameseed = "ABCDE";

     

        for(int i = 0;i<5;i++)

        {

            // 循环创建员工

            Yuangong yg;

            yg.name = "员工";

            // 名字加随机数种子

            yg.name += nameseed[i];

     

            // 年龄是随机数

            yg.name = rand() %30;

            // 薪水是随机数

            yg.salary = rand() %10000 + 10000;

            // 手机号是固定的

            yg.tele = "+86-88888888";

     

            // 把这名员工放到vector

            v.push_back(yg);

        }

    }

     

    // 给员工指派部门

    //  入参:存放员工的vector容器, multimap<int,Yuangong>

    void Set_YG_Group(vector<Yuangong>& v,multimap<int,Yuangong> & group){

     

        for(vector<Yuangong>::iterator it = v.begin();it != v.end(); it++){

                cout << "当前员工信息:" << endl;

                cout << "名字:" << it->name << "年龄: " << it->age << "工资:" <<it->salary << "电话:" << it->tele << endl;

     

                int departmentID = -1;

     

                while(true){

                        cout << "请输入部门(1 销售部 2 开发部 3 财务部) : " << endl;

                        scanf("%d",& departmentID);

     

                        if(departmentID == SALE_DEPARTMENT){

                            group.insert(make_pair(SALE_DEPARTMENT,*it));

                            break;

                        }

                        else if(departmentID == DEVELOP_DEPARTMENT)

                        {

                            group.insert(make_pair(DEVELOP_DEPARTMENT,*it));

                            break;

                        }

                        else if(departmentID == FINACIAL_DEPARTMENT)

                        {

                            group.insert(make_pair(FINACIAL_DEPARTMENT,*it));

                            break;

                        }

                        else{

                            cout << "输入错误,请重新输入:" << endl;

                        }

                }

        }

    }

     

    // 打印各部门员工信息

    void show_YG_Info(multimap<int,Yuangong> & group){

       

            int departmentID = -1;

     

            while(true){

     

                cout << "请输入要查看的部门(1 销售部 2 开发部 3 财务部) : " << endl;

                scanf("%d", &departmentID);

     

                // 验证输入有效性

                if (departmentID < 1 || departmentID > 3){

                    continue;

                }

     

                multimap<int,Yuangong>::iterator pos = group.find(departmentID);

     

                int ygcount = group.count(departmentID);

     

                int num =0;

     

                while( pos != group.end() && num < ygcount){

                    cout << "姓名: " << pos->second.name << " 年龄:" << pos->second.age << " 工资:" << pos->second.salary << " 电话:" << pos->second.tele << endl;

                    num++;

                    pos++;

                }

            }

    }



    int main(void)

    {

        vector<Yuangong> v; // 1.存放员工的容器未分组之前

     

        multimap<int,Yuangong> Ygroup; // 2.存放分组后的员工信息

     

        Create_Yuangong(v); // 3.创建员工并存到容器v

     

        Set_YG_Group(v,Ygroup); // 4.员工分组

     

        show_YG_Info(Ygroup); // 5.按分组显示员工信息

     

        return 0;

    }

     

     

     

     

    13 容器元素深拷贝和浅拷贝问题

    14 容器的共性机制

     

    1. 1.      除了queue和stack 每个容器都有迭代器
    2. 2.      通常STL不会抛出异常 需要使用者传入正确参数
    3. 3.      每个容器都提供了一个默认的构造函数和默认的拷贝构造函数
    4. 4.      大小相关的构造方法: 

    1 size() 返回容器中元素的个数

       2 empty() 判断容器是否为空

    15函数对象课堂基本练习

     

    容器是值语义的

    拷贝是值拷贝,push_back的时候是直接把值给原封不动拷贝了一份

    执行的是原对象的拷贝构造函数

    报错代码:

    原因:test01执行完毕的时候执行了两次析构 释放了相同的内存区域 导致报错

    解决办法:

    重载拷贝构造函数:

    (这里把等号操作符也重载了 因为声明变量的时候使用=调用的也是拷贝构造函数

    16 stl预定义函数对象

    (减法:minus)

    (谓词)

    #define _CRT_SECURE_NO_WARNINGS

    #include <iostream>

    #include <functional>

    #include <string>

    #include <vector>

    #include <algorithm> // 欧狗瑞泽姆

     

    using namespace std;

     

    /*

        template<class T> T plus<T> // 加法仿函数

        template<class T> T minute<T> // 减法仿函数

        template<class T> T multiplies<T> // 乘法仿函数

        template<class T> T divides<T> // 除法仿函数

        template<class T> T modules<T> // 取模仿函数

        template<class T> T negate<T> // 取反仿函数

    */

     

     

    void test01() {

     

        plus<int> myplus;

        int ret = myplus(10, 20);

        cout << ret << endl;

     

        plus<string> myplus2;

        string s1 = "aaa";

        string s2 = "bbb";

        string ret2 = myplus2(s2, s1);

        cout << ret2 << endl;

     

        cout << plus<int>()(10,20) << endl;

       

    }

     

     

    // transform

    void print(int v) {

        cout << v << " ";

    }

     

    void test02() {

        vector<int> v1, v2,v3;

     

        for (int i = 0; i < 10;i++) {

            v1.push_back(i);

            v2.push_back(i + 1);

        }

     

        v3.resize(v1.size()); //

     

     

        for_each(v3.begin(), v3.end(), print);

        cout << endl;

     

        cout << " -------------- " << endl;

     

        transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), plus<int>());

     

        for_each(v3.begin(), v3.end(), print);

        cout << endl;

     

    }

     

     

    int main(void)

    {

     

        test02();

     

        return 0;

    }

  • 相关阅读:
    巧妇难为无米之炊( Model数据)
    jsp后台取出request请求头
    JSP本质的理解(浏览器调试,response里面的文本都是out.write写入网络流)
    【JZOJ6405】【NOIP2019模拟11.04】c
    【JZOJ6404】【NOIP2019模拟11.04】B
    【JZOJ6403】【NOIP2019模拟11.04】a
    【JZOJ6385】【NOIP2019模拟2019.10.23】B
    【JZOJ6379】【NOIP2019模拟2019.10.06】小w与密码(password)
    【JZOJ6373】【NOIP2019模拟2019.10.04】式神[八云蓝]
    【JZOJ6376】【NOIP2019模拟2019.10.05】樱符[完全墨染的樱花]
  • 原文地址:https://www.cnblogs.com/eret9616/p/10654668.html
Copyright © 2011-2022 走看看