[第九天】C++的string类以及STL标准模板库(万字详细解说)

目录

一、STL的概述

二、string容器(类)

1、构造函数以及赋值函数

2、存取字符操作

3、拼接操作

4、查找和替换 

​编辑5、比较操作

​编辑 6、提取子串

7、插入和删除操作

​编辑 8、 string和c风格(c-style)字符串转换

三、vector容器(类模板)

1、概述

 2、相关API

3、巧用swap收缩空间

4、vector容器 嵌套 容器 

5、使用算法 对 vector容器排序 

6、vector存放自定义数据类型

四、deque容器

1、deque的概述

2、deque的API

3、deque容器的案例

 五、stack栈容器

1、stack的概述

 2、stack的API

​编辑

六、queue队列容器

七、list链表容器

八、set/mulitset容器 

1、set/mulitset的概述

2、set/mulitset的API

3、更改set容器的排序规则(定义set容器时 修改) 

4、如果set容器存放自定义数据 必须更改排序规则 

5、multiset容器 键值可以重复

九、pair对组 

十、map/multimap容器

1、概述

2、API

3、multimap实际案例


一、STL的概述

       为提高复用性,建立数据结构和算法的一套标准,诞生了STL(Standard Template Library,标准模板库),STL从广义上分为三大组件:容器(container)、算法(algorithm)、迭代器(iterator),容器和算法之间通过迭代器进行无缝连接。.STL几乎所有的代码都采用.模板类或者模板函数,这相比传统的由函数和类组成的库来说提供了更好的代码重用机会。

STL的6大组件:

  • 容器:存放数据
  • 算法:操作数据
  • 迭代器:算法和容器的桥梁,每个容器对应一个迭代器,算法 通过迭代器 操作 容器
  • 适配器:为算法 提供更多的接口
  • 仿函数:为算法 提供策略
  • 空间配置:为算法、容器提供动态空间

 算法分类:

  • 质变算法:是指运算过程中会更改区间内的元素的内容(会更改容器的值),例如拷贝,替换,删除等等
  • 非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻 找极值等等

二、string容器(类)

        C++标准库定义了一种string类,定义在头文件。String封装了很多实用的成员方法:查找find,搓贝copy,册除delete,替换replace,插入insert,不用考虑内存释放和越界。

1、构造函数以及赋值函数

string 构造函数

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

string基本赋值操作函数

  • string& operator=(const char* s);//char*类型字符串 赋值给当前的字符串
  • string& operator=(const string &s);//把字符串s赋给当前的字符串
  • string& operator=(char c);//字符赋值给当前的字符串
  • string& assign(const char *s);//把字符串s赋给当前的字符串
  • string& assign(const char *s, int n);//把字符串s的前n个字符赋给当前的字符串
  • string& assign(const string &s);//把字符串s赋给当前字符串
  • string& assign(int n, char c);//用n个字符c赋给当前字符串
  • string& assign(const string &s, int start, int n);//将s从start开始n个字符 赋值给字符串

2、存取字符操作

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

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

3、拼接操作

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

4、查找和替换 

 利用string类中find、rfind和repace函数,注pos为缺省参数。

int find(const string& str, int pos = 0) const; //查找str第一次出现位置,从p os开始查找

int find(const char* s, int pos = 0) const; //查找s第一次出现位置,从pos开 始查找

int find(const char* s, int pos, int n) const; //从pos位置查找s的前n个字符 第一次位置

int find(const char c, int pos = 0) const; //查找字符c第一次出现位置

int rfind(const string& str, int pos = npos) const;//查找str最后一次位置,从 pos开始查找

int rfind(const char* s, int pos = npos) const;//查找s最后一次出现位置,从po s开始查找

int rfind(const char* s, int pos, int n) const;//从pos查找s的前n个字符最后 一次位置

int rfind(const char c, int pos = 0) const; //查找字符c最后一次出现位置

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

5、比较操作

> < == != 运算符 可用。

compare函数在>时返回 1,<时返回 ‐1,==时返回 0。

int compare(const string &s) const;//与字符串s比较

int compare(const char *s) const;//与字符串s比较

 6、提取子串

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

7、插入和删除操作

string& insert(int pos, const char* s); //插入字符串

string& insert(int pos, const string& str); //插入字符串

string& insert(int pos, int n, char c);//在指定位置插入n个字符c

string& erase(int pos, int n = npos);//删除从Pos开始的n个字符

 8、 string和c风格(c-style)字符串转换

三、vector容器(类模板)

1、概述

        vector容器:单端动态数组容器。必须包含头文件:#include<vector>

        vector的数据安排以及操作方式,与array非常相似,两者的唯一差别在于空间的运用的灵活性。Array是静态空间,配置后再改变空间复杂,Vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。

push_back尾部插入元素、pop_back尾部删除元素

front()头元素、back()尾元素

begin()得到的是 容器的 起始迭代器(首元素的位置)

end() 得到的是 结束迭代器(尾元素的下一个元素位置)

iterator迭代器 size()容器中元素的个数 capacity()容器的容量


        一旦容量满载,下次再有新增元素,整个vector容器需另外开辟空间。为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求大一些,以备将来可能的扩充。

 2、相关API

构造函数:

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

赋值操作: 

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

大小操作: 

  • size();//返回容器中元素的个数。
  • empty();//判断容器是否为空
  • resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,如果容器变短,则末尾超出容器长度的示素被删除。
  • capacity();//容器的容量
  • reserve(int len);//容器预留len个元素长度,但预留位置不初始化,元素不可访问。

存取操作: 

  • at(int idx);//返返回索引 idx所指的数据,如果idx越界,抛出out of range异常。
  • operator[];返回索引idx所指的数据,越界时,运行直接报错
  • front();//返回容器第一个元素
  • back();//返回容器中最后一个数据元素

插入和删除:

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

 举例说明:

//打印
void printVectorInt(vector<int> &v)
{
    vector<int>::iterator it;
    for(it=v.begin();it!=v.end();it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;
}
void test()
{
    //构造
    vector<int> v1(5,10);
    printVectorInt(v1);

    vector<int> v2=v1;//拷贝构造
    printVectorInt(v2);

    vector<int> v3(v1.begin(),v1.end());
    printVectorInt(v3);

    //赋值
    vector<int> v4;
    //v4=v3;----=运算符重载
    v4.assign(v3.begin(),v3.end());
    printVectorInt(v4);

    v4.assign(5,100);
    printVectorInt(v4);

    //交换
    v3.swap(v4);
    printVectorInt(v3);
    printVectorInt(v4);

    //判断容器是否为空
    vector<int> v5;
    if(v5.empty())
    {
        cout<<"空"<<endl;
    }
    else
    {
        cout<<"非空"<<endl;
    }
    
    ///重新指定容器的长度
    vector<int> v6(10,20);
    cout<<"大小:"<<v6.size()<<"容量:"<<v6.capacity()<<endl;
    printVectorInt(v6);
    v6.resize(15);//过大补零
    //v6.resize(15,30);//过大补30
    cout<<"大小:"<<v6.size()<<"容量:"<<v6.capacity()<<endl;
    printVectorInt(v6);
    v6.resize(10);//容量不变
    cout<<"大小:"<<v6.size()<<"容量:"<<v6.capacity()<<endl;
    printVectorInt(v6);

    //存取
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.at(0)=10;v[1]=20;//可直接赋值
    printVectorInt(v);
    //at越界会抛出异常,[]越界不会抛出异常
    cout<<v.at(0)<<" "<<v[0]<<endl;
    cout<<"头元素:"<<v.front()<<"尾元素:"<<v.back()<<endl;

    //插入和删除
    v.insert(v.begin()+1,3,2);//迭代器指位置pos+1插入3个元素2
    printVectorInt(v);
    v.pop_back();//尾部删除
    printVectorInt(v);
    v.erase(v.begin()+1,v.begin()+4);//删除三个2
    printVectorInt(v);
    v.clear();//大小清0
     cout<<"大小:"<<v.size()<<"容量:"<<v.capacity()<<endl;
}

运行结果: 

3、巧用swap收缩空间

4、vector容器 嵌套 容器 

5、使用算法 对 vector容器排序 

#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
void printVectorInt(vector<int> &v)
{
    vector<int>::iterator it;
    for(it=v.begin(); it!=v.end();it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;
}
bool myCompare(int value1,int value2)
{
    return value1>value2;
}
void test()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(6);
    v.push_back(3);
    v.push_back(9);
    v.push_back(2);
    printVectorInt(v);
    //顺序
    sort(v.begin(),v.end());
    printVectorInt(v);
    //倒序
    //sort(v.begin(),v.end(), greater<int>());
    //sort(v1.begin(), v1.end(), myCompare);
}

int main(int argc, char *argv[])
{
    test();
    return 0;
}

6、vector存放自定义数据类型

class Person
{
    friend void printVectorPerson(vector<Person> &v);
    friend bool myComparePerson(const Person &ob1, const Person &ob2);
private:
    int num;
    string name;
    float score;
public:
    Person(){}
    Person(int num, string name, float score)
    {
        this‐>num = num;
        this‐>name = name;
        this‐>score = score;
    }
    #if 0
    //方法2:重载自定义数据的<运算符
    bool operator<(const Person &ob)
    {
        return this‐>num < ob.num;
    }
    #endif
};
void printVectorPerson(vector<Person> &v)
{
    vector<Person>::iterator it;
    for(it=v.begin(); it!=v.end(); it++)
    {
        //*it == Person
        cout<<(*it).num<<" "<<(*it).name<<" "<<(*it).score<<endl;
    }
}
//方法1:对于自定义容器排序 必须实现 排序规则
bool myComparePerson(const Person &ob1, const Person &ob2)
{
    if(ob1.num == ob2.num)
    return ob1.score>ob2.score;
    return ob1.num > ob2.num;
}
void test()
{
    vector<Person> v;
    v.push_back(Person(1, "lucy", 88.5f));
    v.push_back(Person(3, "tom",  77.5f));
    v.push_back(Person(3, "小明", 85.5f));
    v.push_back(Person(2, "小红", 96.5f));
    printVectorPerson(v);
    //方法1:对于自定义容器排序 必须实现 排序规则
    sort(v.begin(), v.end(), myComparePerson);
    //方法2:重载自定义数据的<运算符
    //sort(v.begin(), v.end());
    cout<<"‐‐‐‐‐‐‐‐‐‐‐‐‐‐"<<endl;
    printVectorPerson(v);
}

四、deque容器

1、deque的概述

        deque:双端动态数组

Deque容器和vector容器的区别:

1、deque允许使用常数项时间对头端进行元素的插入删除操作。

2、deque没有容量的概念。 

        无容量概念是因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来,不会像vector那样”旧空间不足而重新配置一块更大空间,然后复制元素,再释放旧空间"。也因此,deque没有必须要提供所谓的空间保留(reserve)功能。

2、deque的API

构造函数:

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

赋值操作: 

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

大小操作: 

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

存取操作: 

  • at(int idx);//返返回索引 idx所指的数据,如果idx越界,抛出out of range异常。
  • operator[];返回索引idx所指的数据,越界时,运行直接报错
  • front();//返回容器第一个元素
  • back();//返回容器中最后一个数据元素

双端插入删除:

  • push_front(elem);//在容器头部插入一个数据
  • push_back(ele);//尾部插入元素ele
  • pop_front();//删除容器第一个数据
  • pop_back();//删除最后一个元素

插入和删除:

  • insert(const iterator pos,int count,ele);//迭代器指位置pos插入count个元素ele
  • insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值
  • insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值
  • erase(const_iterator start,const_iterator end);//删除迭代器从start到end之间的元素
  • erase(const_iterator pos);/ /删除迭代器指向的元素
  • clear();//删除容器中所有元素

如果迭代器能+X 那么该迭代器 为随机访问迭代器 

vector存放的数据 没有多大规律,只是纪录数据。

deque容器:用于类似竞技的数据 

3、deque容器的案例

        有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中 最低分,取平均分。

1. 创建五名选手,放到vector中

2. 遍历vector容器,取出来每一个选手,执行for循环,可以把10个评分打分存到deque 容器中

3. sort算法对deque容器中分数排序,pop_back pop_front去除最高和最低分

4. deque容器遍历一遍,累加分数,累加分数/d.size()

5. person.score = 平均分

#include<vector>
class Player
{
public:
    string name;
    float score;
public:
    Player(){}
    Player(string name,float score=0.0f)//缺省参数
    {
        this‐>name = name;
        this‐>score=score;
    }
};
void createPlayer(vector<Player> &v)
{
    string seedName = "ABCDE";
    int i=0;
    for(i=0;i<5;i++)
    {
        string tmpName = "选手";
        tmpName+=seedName[i];
        v.push_back(Player(tmpName));//Player(tmpName)为匿名对象
    }
}
#include<stdlib.h>
#include<time.h>
#include<algorithm>
void playGame(vector<Player> &v)
{
    //设置随机数 种子
    srand(time(NULL));
    //每名选手都要参加
    vector<Player>::iterator it;
    for(it=v.begin(); it!=v.end();it++)
    {
        //10个评委打分
        deque<float> d;
        int i=0;
        for(i=0;i<10;i++)
        {
            d.push_back(rand()%41+60);
        }

        // 对d容器排序
        sort(d.begin(),d.end());

        //去掉最高分
        d.pop_back();
        //去掉最低分
        d.pop_front();

        //求总分数
        (*it).score = accumulate(d.begin(),d.end(), 0)/d.size();
    }
}
void showScore(vector<Player> &v)
{
    vector<Player>::iterator it;
    for(it=v.begin(); it!=v.end();it++)
    {
        cout<<(*it).name<<"所得分数:"<<(*it).score<<endl;
    }
}
void test()
{
    //创建5名选手 放入vector容器中
    vector<Player> v;
    createPlayer(v);

    //开始比赛
    playGame(v);

    //公布成绩
    showScore(v);
}

 五、stack栈容器

1、stack的概述

        stack是一种先进后出(First In Last Out,FILO)的数据结构。它只有一个栈顶出口,但是除了栈顶外,没有任何其他方法可以存取stack 的其他元素。换言之,stack不允许有遍历行为。有元素推入栈的操作称为:push,将元素推出stack 的操作称为pop

注: 

操作数据的一端的顶部叫栈顶

top永远指向栈顶元素

栈容器没有迭代器。不支持遍历行为。

 2、stack的API

stack构造函数:

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

stack赋值操作:

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

stack数据存取操作:

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

stack大小操作:

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

六、queue队列容器

        Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口。

出数据的一方叫队头入数据的一方叫队尾

queue容器没有迭代器 不支持遍历行为。 

queue构造函数:

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

queue赋值操作:

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

queue数据存取操作:

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

queue大小操作:

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

七、list链表容器

        list为双向循环链表,迭代器是 双向迭代器。

构造函数:

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

赋值操作: 

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

大小操作: 

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

存取操作: 

  • front();//返回容器第一个元素
  • back();//返回容器中最后一个数据元素

双端插入删除:

  • push_front(elem);//在容器头部插入一个数据
  • push_back(ele);//尾部插入元素ele
  • pop_front();//删除容器第一个数据
  • pop_back();//删除最后一个元素

插入和删除:

  • insert(const iterator pos,ele);//迭代器指位置pos插入元素ele
  • insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值
  • insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值
  • erase(const_iterator start,const_iterator end);//删除迭代器从start到end之间的元素
  • erase(const_iterator pos);/ /删除迭代器指向的元素
  • remove(elem);//删除容器中所有与elem值匹配的元素。
  • clear();//删除容器中所有元素

反转排序:

  • reverse();//反转链表
  • sort(); //list排序 
#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
void printListInt(list<int> &l)
{
    list<int>::iterator it;
    for(it=l.begin();it!=l.end();it++)
    {
        cout<<*it<<" ";
    }
    cout<<endl;
}
void test()
{
    list<int> l;
    l.push_front(1);
    l.push_front(2);
    l.push_front(3);
    l.push_back(4);
    l.push_back(5);
    l.push_back(6);
    printListInt(l);
    
    //list容器 是双向迭代器 不支持+X 支持++
    //不支持l.insert(l.begin()+2,3,10);
    list<int>::iterator it=l.begin();
    it++;
    it++;
    l.insert(it,3,10);
    printListInt(l);
    //删除所有10
    l.remove(10);
    printListInt(l);
    //排序
    //STL提供的算法 只支持 随机访问迭代器,而list是双向迭代器 所以sort不支持list
    //不支持sort(l.begin(),l.end());
    l1.sort();
    // l1.sort(greater<int>());//倒序
    printListInt(l);
    
  
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


 运行结果:

八、set/mulitset容器 

1、set/mulitset的概述

        set容器的特征是所有元素都会根据元素的键值自动被排序。Set 不允许两个元素。set的元素即是键值又是实值。,故不能通过set的迭代器改变set元素的值,会破坏set的数据结构。set容器的迭代器是只读迭代器const_iterator。

        multiset特性及用法和set完全相同,唯一的差别在于它允许键值重复。set和multiset的底层实现是红黑树,红黑树为平衡二叉树的一种。树的简单知识:二叉树就是任何节点最多只允许有两个字节点。分别是左子结点和右子节点。 

        二叉搜索树,是指二叉树中的节点按照一定的规则进行排序,使得对二叉树中元素访问更加高效。二叉搜索树的放置规则是:任何节点的元素值一定大于左子树中的每一个节点的元素值,并且小于其右子树的值。因此从根节点一直向左走,一直到无路可走,即得到最小值,一直向右走,直至无路可走,可得到最大值。那么在儿茶搜索树中找到最大元素和最小元素是非常简单的事情。

2、set/mulitset的API

set构造函数:

  • set<int> st;//set默认构造函数:
  • mulitset mst; //multiset默认构造函数:
  • set(const stack &stk);//拷贝构造函数

set赋值操作:

  • set& operator=(const stack &stk);//重载等号操作符
  • swap(st);//交换两个集合容器

set插入和删除操作

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

set大小操作:

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

set查找操作:

  • find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回se t.end();
  • count(key);//查找键key的元素个数
  • lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
  • upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
  • equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器 

查找元素的上下限:

  用pair对组判断插入是否成功: 

3、更改set容器的排序规则(定义set容器时 修改) 

        一般都是通过 “仿函数” 修改set容器的排序规则。 

set<int,排序规则类>  s1;

4、如果set容器存放自定义数据 必须更改排序规则 

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
class Person
{
    friend ostream& operator <<(ostream &out,Person s);
    friend class myGraterPerson;
private:
    int num;
    string name;
    float score;
public:
    Person(){}
    Person(int num,string name,float score )
    {
        this->name=name;
        this->num=num;
        this->score=score;
    }
};
//仿函数
class myGraterPerson
{
public:
    bool operator()(Person s1,Person s2)
    {
        return s1.num<s2.num;
    }
};
ostream& operator <<(ostream &out,Person s)
{
    out<<s.num<<" "<<s.name<<""<<s.score<<endl;
    return out;
}
void printListPerson(set<Person,myGraterPerson> &s)
{
    set<Person,myGraterPerson>::iterator it;
    for(it=s.begin();it!=s.end();it++)
    {
        cout<<(*it);
    }
    cout<<endl;
}
void test()
{
    set<Person,myGraterPerson> s;
    s.insert(Person(4,"小红",85.5));
    s.insert(Person(1,"小明",75.5));
    s.insert(Person(3,"tom",87.5));
    s.insert(Person(2,"lucy",82.5));
    s.insert(Person(5,"bob",78.5));
    printListPerson(s);
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


关键代码及运行结果: 

5、multiset容器 键值可以重复

九、pair对组 

        对组(pair)将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值 可以分别用pair的两个公有属性first和second访问。

十、map/multimap容器

1、概述

        Map的特性是,所有元素都会根据元素的键值自动排序。Map 所有的元素都是pair,同时拥有实值和键值,pair的第一元素被视为键值,第二元素被视为实值,map不允许两个元素有相同的键值。不能通过map 的迭代器改变map 的键值。Multimap 和map的操作类似,唯一区别multimap键值可重复。底层实现机制是红黑树。

2、API

map构造函数:

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

map赋值操作:

  • map& operator=(const map &mp);//重载等号操作符
  • swap(mp);//交换两个集合容器

map大小操作:

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

map插入操作

  • map.insert(...); //往容器插入元素,返回pair<interator,bool>
  • map<int,string> mapStu;
  • //举例
  • // 第一种 通过pair的方式插入对象
  • mapStu.insert(pair<int,string>(1, "小红"));
  • mapStu.inset(make_pair(2, "小明"));
  • // 第二种 通过value_type的方式插入对象
  • mapStu.insert(map<int,string>::value_type(3, "小李"));
  • // 第四种 通过数组的方式插入值
  • mapStu[1] = "小王";
  • mapStu[3] = "小刘";

 map删除操作:

  • clear();//删除所有元素
  • erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器
  • erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器

map查找操作:

  • find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回se t.end();
  • count(key);//查找键key的元素个数
  • lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
  • upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
  • equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器 

案例: 

#include<iostream>
#include<map>
using namespace std;
class Person
{
    friend void test();
    friend void printmapPerson(map<int,Person> &m);

private:
    int num;
    string name;
    float score;
public:
    Person(){}
    Person(int num,string name,float score)
    {
        this->name=name;
        this->num=num;
        this->score=score;
    }
};

void printmapPerson(map<int,Person> &m)
{
    map<int,Person>::iterator it;
    for(it=m.begin();it!=m.end();it++)
    {
        //*it==pair<int,Person>
        cout<<"学号:"<<(*it).first<<" "<<"姓名:"<<(*it).second.name<<" \
              分数:"<<(*it).second.score<<endl;
    }
    cout<<endl;
}
void test()
{
   map<int,Person> m;
   //插入方式1:
   m.insert(pair<int,Person>(3, Person(3,"小红", 89.5f)));
   m.insert(make_pair(1,Person(1,"小明", 87.5f)));//推荐使用
   //插入方式2:
   m.insert( map<int, Person>::value_type( 2 , Person(2,"tom",
   66.6f)));
   //插入方式3:
   m[4] = Person(4,"小李", 92.5f);
   printmapPerson(m);

   //假如key值存在 m[key]代表对应的实值,若不存在,系统会重新创建。
   cout<< m[7].num<<" "<<m[7].name<<" "<<m[7].score<<endl;
   printmapPerson(m);

   //删除元素
   m.erase(4);
   printmapPerson(m);

   //查找元素对组
   map<int, Person>::const_iterator ret;
   ret=m.find(3);
   if(ret!=m.end())
   {
       cout<<"找到该元素:"<< (*ret).first<<" "<<(*ret).second.name<<" "
          <<(*ret).second.score<<endl;
   }
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}


main关键代码: 

3、multimap实际案例

        公司今天招聘了5个员工,5名员工进入公司之后,需要指派员工在那个部门工 作 人员信息有: 姓名 年龄 电话 工资等组成 通过Multimap进行信息的插入 保存 显示 分部门显示员工信息 显示全部员工信息。

#include<iostream>
#include<map>
#include<vector>
#include<time.h>
#include<stdlib.h>
using namespace std;
class Person
{
    friend void showPartmentPerson(multimap<int,Person> &m);
    friend void personJoinPartment(multimap<int,Person> &m,vector<Person> &v);

private:
    string name;
    int age;
    string tel;
    int salary;
public:
    Person(){}
    Person(string name,int age,string tel,int salary);
};
void personJoinPartment(multimap<int,Person> &m,vector<Person> &v);
void createVectorPerson(vector<Person> &v);
void showPartmentPerson(multimap<int,Person> &m);
void test()
{
    //创建vector容器存放员工
    vector<Person> v;
    createVectorPerson(v);

    //员工加入部门
    multimap<int,Person> m;
    personJoinPartment(m,v);

    //显示部门成员
    showPartmentPerson(m);

}
int main(int argc, char* argv[])
{
    test();
    return 0;
}
void createVectorPerson(vector<Person> &v)
{
    //设置随机数种子
    srand(time(NULL));
    int i=0;
    for(i=0;i<5;i++)
    {
        string seedname="ABCDE";
        string tmpname="员工";
        tmpname+=seedname[i];
        int age=20+i;
        string tel=to_string(rand());
        int salary=10000+rand()%10*1000;
        v.push_back(Person(tmpname,age,tel,salary));
    }
}
void personJoinPartment(multimap<int,Person> &m,vector<Person> &v)
{
    vector<Person>::iterator it;
    for(it=v.begin();it!=v.end();it++)
    {
        //*it=Person
        cout<<"请输入"<<(*it).name<<"要加入的部门:1(销售)、2(研发)、3(财务)";
        int op;
        cin>>op;
        m.insert(make_pair(op,*it));
    }
}
void showPartmentPerson(multimap<int,Person> &m)
{
    cout<<"请输入"<<"要显示的部门:的部门1(销售)、2(研发)、3(财务)";
    int op;
    cin>>op;
    switch (op) {
    case 1:
       cout<<"---销售部门---"<<endl;
        break;
    case 2:
       cout<<"---研发部门---"<<endl;
        break;
    case 3:
       cout<<"---财务部门---"<<endl;
        break;
    default:
        break;
    }
    multimap<int,Person>::const_iterator ret;
    ret=m.find(op);
    int count=m.count(op);
    for(int i=0;i<count;i++,ret++)
    {
        //*ret=pair<int, Person>
        cout<<"\t"<<(*ret).second.name<<" "<<(*ret).second.age<<" "\
        <<(*ret).second.salary<<" "<<(*ret).second.tel<<endl;
    }
    return;
}
Person::Person(string name, int age, string tel, int salary)
{
    this->name=name;
    this->age=age;
    this->tel=tel;
    this->salary=salary;
}

运行案例:

十一、容器的使用时机 

        vector的使用场景:比如软件历史操作记录的存储

        deque的使用场景:比如排队购票系统,支持头端的快速移除,尾端的快速添加

        list的使用场景:比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不 确实位置元素的移除插入

        set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低 分的顺序排列

        map的使用场景:比如按ID号存储十万个用户,想要快速要通过ID查找对应的 用户。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值