(C++)STL(标准模板库)

  • Post author:
  • Post category:其他



目录


一、STL的概述


1、概述


2、特点


3、string 类


二、容器


1、概述


2、vector


3、deque


4、list


5、stack


6、queue


优先队列


7、set 容器


8、map容器


9、multimap


三、算法


1、算法


(1)遍历算法


(2)查找算法


(3)排序算法


(4)拷贝替换


2、函数对象


3、函数适配器


一、STL的概述

1、概述

//STL是由 容器、迭代器、空间适配器、适配器、算法、仿函数六大组件组成;

//STL包含了诸多在计算机科学领域里常用的基本数据机构和基本算法;并且降低了他们之间的耦合关系。

//STL是由惠普实验室开发的一系列软件的统称,现在主要应用于c++中。

2、特点

1.将数据结构和算法分离

2.不需要关心具体的实现过程,只要熟练使用STL就可以。

3.STL具有高度的可重用性,高性能,高移植性,跨平台

3、string 类

//不是STL容器,但是与STL容器有相似之处。

1. 是一个字符串类型,通常用来标识字符串

2.string和插入*的区别

1> string是一个类,char*是一个指向字符串的指针

2> string封装了char*,管理整个字符串,是一个char*的容器

3> string几乎不需要考虑内存越界和内存释放。

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

int main(int argc, char const *argv[])
{
#if 0
    string s1;  //无参构造函数
    string s2("helloworld");  //有参构造函数
    string s3(10,'a'); //10个a
    string s4(s2);


    cout<<s1<<endl;
    cout<<s2<<endl;
    cout<<s3<<endl;
    cout<<s4<<endl;


    cin>>s1;   //重载了输入运算符
    cout<<s1<<endl; 


    s1 += "hellworld";
    if(s1 == s2)
    {


    }
    s1 = s1 + s2;
    cout<<s1<<endl;


//string的存取
    string s("helloworld");
    cout<<s[1]<<endl;  //重载了下标运算符
    s[1] = 'x';
    cout << s<<endl;


    cout<<s.at(1)<<endl;  //通过成员函数来访问


    //cout<<s[200000]<<endl;   //越界访问会抛出异常
    try
    {
        cout<<s.at(12)<<endl;
    }
    catch(const std::exception& e)
    {
        std::cerr << e.what() << '\n';
    }


// string的c_str
    char buf[32] = {0};
    string s("helloworld");
    strcpy(buf,s.c_str());   //将s 通过c_str() 转化为 char * ;才能与 char *buf 拷贝;
    cout<<buf<<endl;


//string 的copy
    char buf[32] = {0};
    string s("helloworld");
    s.copy(buf,5);             //第三个参数是 拷贝目的地,拷贝的个数,开始位置
    cout<< buf<<endl;
    memset(buf,0,sizeof(buf));
    s.copy(buf,4,5);           //从第5个字符开始,拷贝 4 个字符进入 buf;
    cout<<buf<<endl;


//string的长度 : legth()
    string s("helloworld");
    cout<<s.length()<<endl;
    if(s.empty())
    {
        cout<<"字符串是空"<<endl;
    }
    else
    {
        cout<<"字符串不为空"<<endl;
    }


//string的赋值
    string s1("helloworld");
    s1 = "hello";  //重载了=号运算符
    cout<<s1<<endl;
    const char *s = "this is test";
    s1.assign(s);     //将s 赋值给 s1;
    cout<<s1<<endl;
    s1.assign(s,7);   //把字符串s的前7个字符赋值给当前的字符串
    cout<< s1<<endl;


    s1.assign(5,'a');
    cout<<s1<<endl;


    string s2("hey boy");
    s1.assign(s2);  //将s2对象赋值给s1
    cout<<s1<<endl;


    s1.assign(s2,4,3); //从第四个开始的3个字符赋值给当前字符串
    cout<<s1<<endl;


//string的链接
    string s1("helloworld");
    s1 += "1234";
    cout<<s1<<endl;
    string s2("abcdefg");
    s1 += s2;
    cout<< s1<<endl;
    const char *s = "hahahah";
    s1.append(s);    //将s 连接到s1 后面
    cout<<s1<<endl;
    s1.append(s,2);  //将s 的前两个字符拼接到s1的后面
    cout<<s1<<endl;
    s1.append(s2);
    cout<<s1<<endl;
    s1.append(s2,4,2);  //将第4个字符 的后面两个字符,连接到s2 后面
    cout<<s1<<endl;


    s1.append(10,'x');   //在第10个 后面连接x
    cout<<s1<<endl;


//string的比较
    string s1("helloworld");
    string s2("helloboy");
    const char *s = "hellogirl";
    if(s1.compare(s2) > 0)     //s1 与 s2 比较
    {
        cout<<"s1 > s2"<<endl;
    }
    
    if(s1.compare(s) > 0)
    {
        cout<<"s1> s2"<<endl;
    }


//string字符串
    string s("helloworld");
    cout<<s.substr()<<endl;         //字符串输出
    cout<<s.substr(5,5)<<endl;      //将第5个 后面的 5个 字符输出


//string的查找和替换
    int p; //位置
    string s1("helloworld");
    string s2("world");


    p = s1.find('o');  //返回的是位置
    cout<<p<<endl;


    p = s1.find('o',5);
    cout<<p<<endl;


    p = s1.find('x');   //找不到,返回-1
    cout<<p<<endl;
    p = s1.find("ll");
    cout<<p<<endl;


    p = s1.find(s2);
    cout<<p<<endl;


    p = s1.rfind('o');
    cout<<p<<endl;


    s1.replace(5,5,"xxx");    //替换
    cout<<s1<<endl;
    s1.replace(5,3,s2);
    cout<<s1<<endl;
    string s3("helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld");
    p = s3.find("world");
    while(p != -1)                         //将字符串中的world 替换为 x;
    {
        s3.replace(p,strlen("world"),"x");
        p = s3.find("world",p+strlen("x"));
    }
    cout<< s3<<endl;
#endif
//string的插入和删除
    string s1("helloworld");
    string s2("12345");
    s1.insert(0,"this is ");
    cout<<s1<<endl;
    s1.insert(10,s2);
    cout<<s1<<endl;
    s1.insert(0,5,'x');     //插入
    cout<<s1<<endl;

    s1.erase(10,2);    //删除
    cout<<s1<<endl;
    return 0;
}

二、容器

1、概述

容器就是将各种常用的数据结构,如数组、链表、栈、队列、二叉树等封装成一个个模板类,以方便编程。

2、vector

vector是将元素放置在一个动态数组中加以管理的容易,可以随机存取元素,[]或者at直接存取,vector在尾部存取元素十分迅速,但是在中部或者头部插入或者删除 元素比较费时。

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

int main(int argc, char const *argv[])
{
#if 1
    int data[10] = {1,2,3,4,5,6,7,8,9,10};
    vector<int> v1;                     //创建数组对象(模板类),无参构造函数
    vector<int> v2(data, data + 10);    //显示调用,int类型
    vector<int> v3(10, 1);                

    v1.resize(10);
    for(int i = 0; i < v1.size(); i++)
    {
        v1[i] = i;
    }

    for (int i = 0; i < v1.size(); i++)
    {
        cout<<v1.at(i)<<" ";
    }
    cout<<endl;

    for (int i = 0; i < v2.size(); i++)
    {
        cout<<v2.at(i)<<" ";
    }
    cout<<endl;

    for (vector<int>::iterator it = v3.begin(); it != v3.end(); it++)  //正向迭代
    {
        cout<<*it<<" ";
    }
    cout<<endl;

    for (vector<int>::reverse_iterator rit = v2.rbegin(); rit != v2.rend(); rit++)
    {
        cout<<*rit<<" ";
    }                                           //反向迭代
    cout<<endl;

    for(vector<int>::const_iterator cit = v2.begin(); cit != v2.end(); cit++)
    {
        //(*cit)++;     //只读容器
        cout<<*cit<<" ";
    }
    cout<<endl;

#endif

    const char *str = "this is";
    const char *s = "helloworld";
    vector<char> v(s, s + strlen(s));     //char 类型

    for (vector<char>::iterator it = v.begin(); it != v.end(); it++)  //迭代
    {
        cout<<*it;
    }
    cout<<endl;

    v.insert(v.begin(), 'x');    //在前面插入1个 x
    for (vector<char>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout<<*it;
    }
    cout<<endl;

    v.insert(v.begin(), 5, 'x');     //在前面插入5个 x 
    for (vector<char>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout<<*it;
    }
    cout<<endl;

    v.erase(v.end() - 5, v.end());   //删除后5个
    for (vector<char>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout<<*it;
    }
    cout<<endl;

    v.erase(v.begin(), v.begin() + 6);   //删除前6个
    for (vector<char>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout<<*it;
    }
    cout<<endl;

    v.insert(v.begin(), str, str + strlen(str));  //在前面插入一个 str
    for (vector<char>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout<<*it;
    }
    cout<<endl;
    
    
    return 0;
}

3、deque

deque:双端数组,而vector是单端数组,但是两者在接口上非常非常相似,许多操作可以直接替换,deque可以随机存取元素,使用[]或者at() 在deque中,在头部和尾部添加或者删除元素非常迅速,但是在中部添加或者删除则比较费事,头文件:#include <deque>

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

int main(int argc, char const *argv[])
{
#if 1
    int data[5] = {1,2,3,4,5};

    deque<int> d1;
    deque<int> d2(data, data + 5);     //int 类型
    deque<int> d3(10,1);

    d1.resize(10);
    for (int i = 0; i < d1.size(); i++)
    {
        d1[i] = i + 1;
    }

    for (int i = 0; i < d1.size(); i++)
    {
        cout<<d1[i]<<" ";
    }
    cout<<endl;

    for (deque<int>::iterator it = d2.begin(); it != d2.end(); it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;

    d2.push_back(6);      //从最后进队 6
    d2.push_front(0);     //从前面进队 0
    for (deque<int>::iterator it = d2.begin(); it != d2.end(); it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;

    d2.pop_back();          //从后面出队
    d2.pop_front();        //从前面出队
    for (deque<int>::iterator it = d2.begin(); it != d2.end(); it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;

    d2.front() = 100;      //将首元素改为100
    d2.back() = 200;       //将最后一个元素改为200
    for (deque<int>::iterator it = d2.begin(); it != d2.end(); it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;
    
    deque<int>::iterator it = d2.erase(d2.begin());    //删除第一个元素
    cout<<*it<<endl;
    for (deque<int>::iterator it = d2.begin(); it != d2.end(); it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;

#endif

    int data[10] = {2,1,3,3,4,8,7,1,3,3};
    deque<int> d(data, data + 10);

    for (deque<int>::iterator it = d.begin(); it != d.end();)  //删除所有3
    {
        if (*it == 3)
        {
            d.erase(it);
        }
        else
        {
            it++;
        }
        
    }
    
    for (deque<int>::iterator it = d.begin(); it != d.end() ; it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;
    
    
    return 0;
}

4、list

list:是一个双向链表容器,可高效的进行插入和删除元素,list不支持随机存取元素,所以说不支持[]和at(),也不支持迭代器的随机访问

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

class Student                  //与链表相同,需要自己定义节点的类型(结构体类型)
{                              //在C++中,通常用类,代替结构体类型
    private:
        int id;
        char name[32];

    public:
        Student(){}
        Student(int i, const char *n);
        void show();
        bool operator==(const Student &s);

};

Student::Student(int i, const char *n)
{
    id = i;
    strcpy(name, n);
}

void Student::show()
{
    cout<<"id = "<<id<<" name = "<<name<<endl;
}

bool Student::operator==(const Student &s)
{
    if (s.id == this->id)
    {
        return true;
    }
    else
    {
        return false;
    }
}


int main(int argc, char const *argv[])
{
    Student s1(1, "aaa");
    Student s2(2, "bbb");
    Student s3(3, "ccc");
    Student s4(4, "ddd");
    Student s5(5, "eee");
    Student s6(6, "fff");
    Student s7(7, "ggg");

    list<Student> l;    //创建链表对象

    l.push_back(s1);  //尾插法
    l.push_back(s2);  //尾插法
    l.push_back(s3);  //尾插法
    l.push_back(s4);  //尾插法
    l.push_back(s5);  //尾插法
    l.push_back(s6);  //尾插法

    for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }

    l.pop_back();   //删除最后一个节点
    l.pop_front();   //删除第一个节点

    cout<<"***********************"<<endl;
    //it = it + 1; 不能使用,因为链表是不连续的
    for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  

    cout<<"最后一个元素是:"<<endl;
    l.back().show();

    cout<<"第一个元素是:"<<endl;
    l.front().show();

    cout<<"链表的长度:"<<endl;
    cout<<l.size()<<endl;

    cout<<"链表的扩充:"<<endl;
    l.resize(5,s7);
    for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  
    
    //对象数组
    cout<<"************************"<<endl;
    Student s[5] = {Student{10, "a"},Student{11, "b"},Student{12, "c"},Student{13, "d"},Student{14, "e"}};
    l.insert(l.begin(), s[0]);
    for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  

    cout<<"************************"<<endl;
    l.insert(l.end(), 2, s[1]);                   //在最后插两个s[1]
     for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  

    cout<<"************************"<<endl;
    l.insert(l.end(), s, s + 5);                   //在最后插入s
     for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  

    cout<<"删除一个区间"<<endl;
    list<Student>::iterator it = l.begin();
    for (int i = 0; i < 5; i++)
    {
        it++;
    }
    l.erase(it, l.end());        //删除it 后面全部
     for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  

    cout<<"删除一个位置"<<endl;
    l.erase(l.begin());            //删除地一个
     for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  
    
    cout<<"删除具体元素"<<endl;
    l.remove(s2);        //==运算符重载
     for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  

    cout<<"链表反转"<<endl;
    l.reverse();
     for (list<Student>::iterator it = l.begin(); it != l.end(); it++)  //迭代
    {
        it->show();
    }  

    return 0;
}

5、stack

//包含头文件 #include <stack>

//栈:同样需要显示调用:如:stack<int> s;

//push() 进栈; top() 栈顶元素; size() 栈的大小; empty()  是否为空; pop() 出栈;

#include <iostream>
#include <stack>
#include <time.h>
#include <cstdlib>
using namespace std;

int main(int argc, const char *argv[])
{
    stack<int> s;
    srand(sizeof(time(NULL)));
    
    int num;

    for (int i = 0; i < 10; i++)
    {
        num = rand()%10;
        s.push(num);
        cout<<num<<"进栈成功"<<endl;
    }
    cout<<"栈顶元素是:"<<s.top()<<endl;
    cout<<"栈的大小是:"<<s.size()<<endl;

    while (!s.empty())
    {
        cout<<s.top()<<"出栈"<<endl;
        s.pop();
    }

    return 0;
}

6、queue

//包含头文件 #include <queue>

//push() 进队; front() 队头元素; back() 队尾元素;empty() 是否为空;

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

int main(int argc, const char *argv[])
{
    queue<int> q;

    int num;

    for (int i = 0; i < 10; i++)
    {
        num = i + 1;
        q.push(num);
        cout<<num<<"进队成功!"<<endl;
    }
    cout<<"队头元素"<<q.front()<<endl;
    cout<<"队尾元素"<<q.back()<<endl;

    while(!q.empty())
    {
        cout<<q.front()<<"出队!"<<endl;
        q.pop();
    }
    

    return 0;
}

优先队列

//priority_queue 优先队列;如:priority_queue<int> p;

//pop() 出队;push()进队;top()栈顶;empty()栈空

#include <iostream>
#include <queue>
#include <time.h>
#include <cstdlib>
using namespace std;

int main(int argc, char const *argv[])
{
    //priority_queue<int> p;   //priority_queue<int, vector<int>, less<int>> p; //由大到小排序
    //priority_queue<int, vector<int>, greater<int>> p;  //由小到大排序,由动态数组构成
    priority_queue<int, deque<int>, less<int>> p;      //由队列构成

    srand(sizeof(time(NULL)));
    int num;

    for (int i = 0; i < 10; i++)
    {
        num = rand()%10;
        p.push(num);
        cout<<num<<"进队成功"<<endl;
    }
    cout<<"队头元素"<<p.top()<<endl;
    cout<<"队的长度"<<p.size()<<endl;
    
    while (!p.empty())
    {
        cout<<p.top()<<"出队"<<endl;
        p.pop();
    }
    

    
    return 0;
}

7、set 容器

//包含头文件 #include <set>

//属于链式存储,故而也需要先定义节点(通过类定义);遍历就是要迭代

//链式存储是有序的,(由小到大 或 由大到小)

// insert() 插入数据; begin() 开始元素; end() 结尾元素; erase() 删除元素或区间;find() 查找(返回 地址);count() 统计相同节点个数;lower_bound() 找到一个比当前元素大一个的元素;

upper_bound() 找到一个比当前元素小一个的元素;

//pair 类的使用:如: pair<参数1,参数2>  p; 对象 p 可以通过访问两个参数(p.first;p.second),起到lower_bound();upper_bound()的作用

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

class Student
{
    private:
        int id;
        string name;
    
    public:
        Student(int i, string n);
        void show() const;
        bool operator<(const Student &s) const;
        bool operator>(const Student &s) const;

};

Student::Student(int i, string s)
{
    id = i;
    name = s;
}

void Student::show() const
{
    cout<<"id = "<<id<<" name = "<<name<<endl;
}

bool Student::operator<(const Student &s) const
{
    return this->id < s.id;
}

bool Student::operator>(const Student &s) const
{
    return this->id > s.id;
}

int main(int argc, const char *argv[])
{
    Student s3(3, "cc");
    Student s1(1, "aa");
    Student s4(4, "dd");
    Student s2(2, "bb");
    Student s6(6, "ff");
    Student s5(5, "ee");

    set<Student> s;
    //set<Student, greater<Student>> s;  //greater<> 由小到大排序
    s.insert(s3);
    s.insert(s1);
    s.insert(s4);
    s.insert(s2);
    s.insert(s6);
    s.insert(s5);

    for (set<Student>::iterator it = s.begin(); it != s.end(); it++)
    {
        it->show();
    }
    
    cout<<"集合大小: "<<s.size()<<endl;
    s.erase(s.begin());
    for (set<Student>::iterator it = s.begin(); it != s.end(); it++)
    {
        it->show();
    }

    cout<<"set区间删除"<<endl;
    s.erase(--(s.end()), s.end());
    for (set<Student>::iterator it = s.begin(); it != s.end(); it++)
    {
        it->show();
    }

    cout<<"删除具体的元素"<<endl;
    s.erase(s2);
    for (set<Student>::iterator it = s.begin(); it != s.end(); it++)
    {
        it->show();
    }

    cout<<"set的查找"<<endl;
    set<Student>::iterator it = s.find(s4);
    if (it == s.end())
    {
        cout<<"对象不存在"<<endl;
    }
    else
    {
        it->show();
    }

    cout<<"set的统计"<<endl;
    cout<<s.count(s4)<<endl;

    cout<<"lower_bound"<<endl;
    it = s.lower_bound(s4);
    if (it == s.end())
    {
        cout<<"对象不存在"<<endl;
    }
    else
    {
        it->show();
    }

    cout<<"upper_bound"<<endl;
    it = s.upper_bound(s3);
    if (it == s.end())
    {
        cout<<"对象不存在"<<endl;
    }
    else
    {
        it->show();
    }

    cout<<"**********************"<<endl;
    for (set<Student>::iterator it = s.begin(); it != s.end(); it++)
    {
        it->show();
    }
    cout<<"equl_range"<<endl;
    //pair 类型 模板类 有两个成员变量:相当于 lower_bound , upper_bound;
    pair<set<Student>::iterator, set<Student>::iterator> p;
    p = s.equal_range(s4);
    p.first->show();                //第一个变量:lower_bound
    p.second->show();               //第二个变量:upper_bound

    return 0;
}

8、map容器

//map 容器包含两个部分:键(key)、值(value)

//在访问map 对象的内容时,需要指向 键(key)和值(value)两个数据

//begin() 开始元素; end() 结尾元素; erase() 删除元素或区间;

insert() 插入数据;//在接口括号中,调用其它接口

(1)pair<int, string>(1,”zz”)    //通过pair对组(组合一组数据)插入

(2)make(1,”aa”)    //通过make_pair组合一对数据插入

(3)map<int, string>::value_type(1,”cc”);  //通过map内部的静态成员函数插入

(4)m[1] = “aa”;    //map重载了[ ]运算符,进行插入

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

int main(int argc, char const *argv[])
{
    map<int,string> m;   //key是int型,value是string类型


    m.insert(pair<int,string>(3,"aa"));  //通过pair对组(组合一组数据)插入
    m.insert(pair<int,string>(1,"zz"));


    m.insert(make_pair(5,"cc"));         //通过make_pair组合一对数据插入
    m.insert(make_pair(2,"dd"));


    m.insert(map<int,string>::value_type(6,"hh"));
    m.insert(map<int,string>::value_type(4,"vv"));  //通过map内部的静态成员函数插入


    m[8] = "uu";  //map重载了[]运算符
    m[7] = "qq";


    for(map<int,string>::iterator it = m.begin(); it != m.end();it++)
    {
        //it指向map的一个结点,一个结点就是一个pair对象,即it指向pair对象,pair对象有两个成员,first和second
        cout<<"key: "<<it->first<<" value :"<<it->second<<endl;
    }
    //前三种插入方式,如果数据已经存在则返回错误,第四种方法,如果数据存在,则覆盖之
    pair<map<int,string>::iterator,bool> p = m.insert(make_pair(5,"ll"));
    if(p.second == false)
    {
        cout<<"插入失败"<<endl;  //返回迭代器指向已经存在的结点
       cout<<"key: "<<p.first->first<<" value :"<<p.first->second<<endl;
    }
    else
    {
        cout<<"插入成功"<<endl;
    }
    m[3] = "www";  //直接将原有数据覆盖
    for(map<int,string>::iterator it = m.begin(); it != m.end();it++)
    {
       
        cout<<"key: "<<it->first<<" value :"<<it->second<<endl;
    }


    cout<<"map删除指定位置"<<endl;
    m.erase(m.begin());
    for(map<int,string>::iterator it = m.begin(); it != m.end();it++)
    {
       
        cout<<"key: "<<it->first<<" value :"<<it->second<<endl;
    }
    cout<<"map删除区间"<<endl;
    m.erase(--(m.end()),m.end());
    for(map<int,string>::iterator it = m.begin(); it != m.end();it++)
    {
       
        cout<<"key: "<<it->first<<" value :"<<it->second<<endl;
    }


    cout<<"删除具体的元素"<<endl;
    m.erase(4);  //根据键值来删除
    for(map<int,string>::iterator it = m.begin(); it != m.end();it++)
    {
       
        cout<<"key: "<<it->first<<" value :"<<it->second<<endl;
    }
    return 0;
}

9、multimap

一个key值可以对应多个value

案例:

公司: 销售部:2名

技术研发部:1名

财务部:2名

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

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

分部门显示员工信息

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

class Employee
{
    private:
        int id;
        string name;
    public:
        Employee(int i,string n)
        {
            id = i;
            name = n;
        }
        void show()
        {
            cout<<"工号:"<<id<<" 姓名:"<<name<<endl;
        }
};
int main(int argc, char const *argv[])
{
    Employee e1(1,"aa");
    Employee e2(2,"bb");
    Employee e3(3,"cc");
    Employee e4(4,"dd");
    Employee e5(5,"ee");
    Employee e6(6,"ff");
    Employee e7(7,"gg");
    Employee e8(8,"hh");

    multimap<string,Employee> m;   //对象 m 包含了 string、Employee 两个类
                                   //从而达到一个 key 包含多个 信息(value)
    //销售部有三个员工
    m.insert(make_pair("Sale",e1));
    m.insert(make_pair("Sale",e2));
    m.insert(make_pair("Sale",e3));
    //研发部有一个员工
    m.insert(make_pair("development",e4));
    //财务部门有四个员工
    m.insert(make_pair("Finance",e5));
    m.insert(make_pair("Finance",e6));
    m.insert(make_pair("Finance",e7));
    m.insert(make_pair("Finance",e8));

    cout<<m.count("Finance")<<endl;
    for(map<string,Employee>::iterator it = m.begin();it != m.end();it++)
    {
        cout<<"部门:"<<it->first<<endl;
        it->second.show();
    }
    return 0;
}

总结:

三、算法

1、算法

C++中的算法模板主要在三个头文件中:<algotithm>、<numeric>、<functional>;

<algotithm>:包含:遍历算法(可修改值、不可修改值)、查找算法(重复且相邻元素、按值查找、查找出现次数)、排序算法、

(1)遍历算法

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

void show(int x)
{
    cout<< x<<endl;
}

class print
{
    public:
        void operator()(int x)
        {
            cout<< x<<endl;
        }
};

int main(int argc, char const *argv[])
{
    int a[5] = {1,2,3,4,5};
    vector<int> v(a, a + 5);

    //for_each遍历过程中不能修改数据
    for_each(v.begin(), v.end(), show);   //回调函数形式遍历
    for_each(v.begin(), v.end(), print()); //函数对象形式遍历

    //tramsform遍历过程中可以修改数据
    string s("helloworld");
    transform(s.begin(), s.end(), s.begin(), ::toupper);   //将小写改为大写
    cout<<s<<endl; 
    
    return 0;
}

(2)查找算法

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool GreaterTwo(int x)
{
    return x > 2;
}

class GreaterThree
{
    public:
        bool operator()(int x)
        {
            return x > 3;
        }
};

int main(int argc, char const *argv[])
{
    int a[6] = {1,2,2,3,6,5};
    vector<int> v(a, a+6);

    //查找重复且相邻的元素
    vector<int>::iterator it = adjacent_find(v.begin(), v.end());
    if (it == v.end())
    {
        cout<<"不存在重复且相邻的元素"<<endl;
    }
    else
    {
        cout<<*it<<endl;
    }
    
    //在有序序列里面找值
    bool ret = binary_search(v.begin(),v.end(), 9);
    if (ret)
    {
        cout<<"存在元素"<<endl;
    }
    else
    {
        cout<<"不存在元素"<<endl;
    }

    //查找元素个数
    int num = count(v.begin(), v.end(), 2);
    cout<<num<<endl;

    //查找大于2的个数
    num = count_if(v.begin(), v.end(), GreaterTwo);
    cout<<num<<endl;
    
    //查找元素
    it = find(v.begin(), v.end(), 3);
    if (it == v.end())
    {
        cout<<"不存在元素"<<endl;
    }
    else
    {
        cout<<*it<<endl;
    }

    //查找大于3 的第一个元素
    it = find_if(v.begin(), v.end(), GreaterThree());  //函数对象
    if (it == v.end())
    {
        cout<<"不存在元素"<<endl;
    }
    else
    {
        cout<<*it<<endl;
    }

    return 0;
}

(3)排序算法

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void show(int x)
{
    cout<< x<<" ";
}

int main(int argc, char const *argv[])
{
    vector<int> v1;
    vector<int> v2;

    srand(sizeof(time(NULL)));
    for (int i = 0; i < 5; i++)
    {
        v1.push_back(rand()%10);
        v2.push_back(rand()%10);

    }
    //将两个数组排序
    sort(v1.begin(), v1.end(), less<int>());
    sort(v2.begin(), v2.end(), less<int>());

    cout<<"v1: "<<endl;
    for_each(v1.begin(), v1.end(), show);
    cout<<endl;

    cout<<"v2: "<<endl;
    for_each(v2.begin(), v2.end(), show);
    cout<<endl;

    //合并两个数组
    vector<int> v3;
    v3.resize(10);
    merge(v1.begin(),v1.end(),v2.begin(),v2.end(),v3.begin());
    for_each(v3.begin(), v3.end(), show);
    cout<<endl;
    
    //将数组打乱
    random_shuffle(v1.begin(),v1.end());
    cout<<"v1: "<<endl;
    for_each(v1.begin(), v1.end(), show);
    cout<<endl;

    //转直
    reverse(v3.begin(),v3.end());
     for_each(v3.begin(), v3.end(), show);
    cout<<endl;
    
    return 0;
}

(4)拷贝替换

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void show(int x)
{
    cout<<x<<" ";
}

int main(int argc, char const *argv[])
{
    vector<int> v1(5,1);
    vector<int> v2(5,2);

    //将v2覆盖
    v2.resize(6);
    copy(v1.begin(),v1.end(),++(v2.begin()));
    for_each(v2.begin(),v2.end(),show);
    cout<<endl;

    //将v1和v2互换
    swap(v1,v2);
    for_each(v2.begin(),v2.end(),show);
    cout<<endl;

    return 0;
}

2、函数对象

(1)概念

重载函数调用操作符的类,其对象称为函数对象,即他们的行为类似函数,一个类的对象,表现出一个函数的特征,就是通过 “对象名 +(参数列表)”的方式 使用一个类对象,如果没有上下文,完全可以当成一个函数队列

函数对象:主要通过重载()来实现的

(2)谓词

一元函数对象:函数参数1个;二元函数对象:函数参数2个

一元谓词函数:参数1个,函数返回值是bool类型,可以作为一个判断式

谓词可以是一个仿函数,也可以是一个回调函数

二元谓词:函数参数2个,函数返回值是bool类型

一元谓词函数举例:

判断string对象的长度是否小于6

bool Greater(Const string &s)

3、函数适配器

四大类:绑定适配器,组合适配器,指针函数适配器,成员函数适配器

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool Equal(string str)
{
    return str == "bb";
}

int main(int argc, char const *argv[])
{
    vector<string> v;

    v.push_back("aa");
    v.push_back("bb");
    v.push_back("cc");
    v.push_back("dd");
    v.push_back("ee");

    //查找相同字符串
    //vector<string>::iterator it = find_if(v.begin(),v.end(),Equal);  //调用函数
    vector<string>::iterator it = find_if(v.begin(),v.end(),bind1st(equal_to<string>(),"bb"));  //运用适配器
    if (it == v.end())
    {
        cout<<"不存在"<<endl;
    }
    else
    {
        cout<<*it<<endl;
    }
    

    
    return 0;
}



版权声明:本文为weixin_53812805原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。