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;

    }

  • 相关阅读:
    开放源码的对象关系映射工具ORM.NET 插入数据 Insert/Update Data
    开放源码的对象关系映射工具ORM.NET 快档开发入门 Quick Start
    .NET 动态脚本语言Script.NET 开发指南
    开放源码的对象关系映射工具ORM.NET 删除数据 Deleting Records using ORM.NET
    .NET Remoting过时了吗?为什么公司的项目还是选择用.NET Remoting,而不是WCF?
    开放源码的对象关系映射工具ORM.NET 查看和显示数据 View and Display data using ORM.NET
    开放源码的对象关系映射工具ORM.NET 查询表 调用存储过程 增加自定义代码
    技术人生:坚持,每日一博
    CQRS:CQRS + DDD + MDP 实现快速应用程序开发
    NodeJs:Happy代码生成器,重构了代码,更新了文档,完善了示例,欢迎下载使用
  • 原文地址:https://www.cnblogs.com/eret9616/p/10654668.html
Copyright © 2011-2022 走看看