C++ STL 容器

引言--多看案例

STL概念

STL(Standard Template Library, 标准模板库 ), 是惠普实验室开发的一系列软件的统
称。
STL 6 大组件
容器 :
作用 : 容纳存储数据
分类 :
序列式容器:
强调值的排序,每个元素均有固定的位置, 除非用删除或插入的操
作改变这个位置,
vector, deque/queue, list;
关联式容器 :
非线性,更准确的说是二叉树结构,各元素之间没有严格的物理上
的顺序关系 ;
在数据中选择一个关键字 key ,这个 key 对数据起到索引的作用,方
便查找。
如: set/multiset Map/multimap 容器
注意 : 容器可以嵌套容器
算法 :
作用 : 操作数据 , 如插入数据、删除数据、修改数据、排序等
分类 :
质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替
换,删除等等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、
计数、遍历、寻找极值等等
迭代器
作用 : 容器与算法之间的粘合剂
注意 : 每个容器都有自己的迭代器
分类 :
输入迭代器 提供对数据的只读访问 只读,支持 ++ == 、! =
输出迭代器 提供对数据的只写访问 只写,支持 ++
前向迭代器 提供读写操作,并能向前推进迭代器 读写,支持 ++
== 、! =
双向迭代器 提供读写操作,并能向前和向后操作 读写,支持 ++ --
随机访问迭代器 提供读写操作,并能以跳跃的方式访问容器的任意数
据,是功能最强的迭代器读写,支持 ++ -- [n] - n < <= > >=
仿函数
作用 : 为算法提供策略
适配器
作用 : 为算法提供更多的参数接口
空间配置器
作用 : 为容器和算法管理空间

 常用容器

string

作用

存储字符的容器(字符串)

构造函数

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

using namespace std;

void fun01()

{

    string str01;

    cout<<"str01"<<str01<<endl;

    // string str02("hello");

    string str02("时间里的空白");

    cout<<"str02="<<str02<<endl;

    string str03=str02;

    cout<<"str03="<<str03<<endl;

    string str04(3,'A');

    cout<<"str04="<<str04<<endl;

}

基本赋值操作

语法

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
字符赋值给字符串
示例1

void fun02()

{

    string str01;

    cout<<"str01"<<str01<<endl;

    str01="何必难为自己";

    cout<<"str01"<<str01<<endl;

    string str02;

    str02=str01;

    cout<<"str02="<<str02<<endl;

    string str03;

    str03='a';

    cout<<"str03="<<str03<<endl;

}

示例2

void fun03()

{

// 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个字符赋值给字符串

string str01 = "hello";

cout << "str01 = " << str01 << endl;

str01.assign("world123");

cout<<"str01="<<str01<<endl;

str01.assign("mylove159",5);//mylov

cout<<"str01="<<str01<<endl;

str01.assign(3,'h');

cout<<"str01="<<str01<<endl;

string str02;

str02.assign(str01,0,2);

cout << "str02 = " << str02 << endl;

string str03;

str03.assign(str02);

cout<<"str03:"<<str03<<endl;

}

 获取字符串长度

语法

int size();

int length();

注意:不包含\0

示例

void fun04()

{

    string str="hello";

    int size=str.size();

    cout<<"size="<<size<<endl;

    int len=str.length();

    cout<<"len="<<len<<endl;

}

存取字符操作

语法

 char& operator[](int n);//通过[]方式取字符,下标越界不会抛出异常

 char& at(int n);// 通过 at 方法获取字符 , 下标越界会抛出异常
 示例

void fun05()

{

    string str="hello";

    cout<<str[2]<<endl;

    cout<<str.at(1)<<endl;

}

拼接操作

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

 void fun06()

{

    string str01="Hi";

    str01+="C++";

    cout<<"str01="<<str01<<endl;

    string str02="STL";

    str01+=str02;

    cout<<"str01="<<str01<<endl;

    str01+='A';

    cout<<"str01="<<str01<<endl;

}

void fun07()

{

    // string& append(const char *s);

    //把字符串s连接到当前字符串结尾

    string str01;

    str01.append("hi");

    cout<<"str01="<<str01<<endl;

    str01.append("C++");

    cout<<"str01="<<str01<<endl;

    // string& append(const char *s, int n);

    //把字符串s的前n个字符连接到当前字符串结尾

    string str02;

    str02.append("ggbang",5);

    cout<<"str02="<<str02<<endl;

    // string& append(const string &s);

    //同operator+=()

    // string& append(const string &s, int pos, int n);

    //把字符串s中从pos开始的n个字符连接到当前字符串结尾

    string str03="1234567890";

    string str04;

    str04.append(str03,3,2);

    cout<<"str04="<<str04<<endl;

    // string& append(int n, char c);

    //在当前字符串结尾添加n个字符c

    str04.append(2,'p');

    cout<<"str04="<<str04<<endl;

 查找和替换

语法
int find(const string& str, int pos = 0) const; // 查找 str 第一次出现位置 ,
pos 开始查找
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 最后一次出现位置 ,
pos 开始查找
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
string& replace(int pos, int n, const char* s); // 替换从 pos 开始的 n 个字符
为字符串 s
注意 : 查找是不存在返回 -1
 示例

void fun08()

{

    string str="456love456";

    int i01=str.find('4');

    cout<<"i01="<<i01<<endl;

    int i02=str.rfind('4');

    cout<<"i02="<<i02<<endl;

    int i03=str.find("6l");

    cout<<"i03="<<i03<<endl;

    str.replace(3,3,"15587554");

    cout<<"str="<<str<<endl;

}

比较操作

/**
*compare 函数在 > 时返回 1 < 时返回 -1 == 时返回 0
* 比较区分大小写,比较时参考字典顺序,排越前面的越小。大写的 A 比小写的 a 小。
**/
int compare(const string &s) const;// 与字符串 s 比较
int compare(const char *s) const;// 与字符串 s 比较

 截取操作

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

 void fun09()

{

    string str01="a.txt";

    string str03="baby.go";

    string str02=str01.substr(1,4);

    string str04=str03.substr(1,3);

    cout<<str02<<endl;

    cout<<str04<<endl;

}

插入与删除

语法
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 个字符
示例

 void fun10()

{

// 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 str01 = "11";

//开始位置不要超出字符串下标范围

// str01.insert(1,"abc");

str01.insert(1,3,'A');

cout << "str01 = " << str01 << endl;

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

str01.erase(1,3);

cou

 string与char* 转换

//string转char*

string str="itcast";

const char* cstr=str.c_str();

//char*转string

char* s="itcast";

string str(s);

示例

void fun11()

{

string str01 = "abc";

string str02("abc");

cout<<str02<<endl;

char* str03 = (char* )str01.c_str();

cout<<str03<<endl;

}

重要案例

//解析字符串

void fun13()

{

    string str="www.itcast.com.cn";

    vector<string> v;

    int start=0;

    int pos=-1;

    while (true)

    {

        //www.itcast.com.cn

        pos=str.find(".",start);

        if (pos==-1)

        {

            //将cn截取出来

            string tempStr=str.substr(start,str.size()-start);

            v.push_back(tempStr);

            start=pos+1;

            break;

        }

        string tempStr=str.substr(start,pos-start);

        v.push_back(tempStr);

        start=pos+1;

    }

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

        {

            cout<<*it<<endl;

        }

   

}

/*

写一个函数,函数内部将string字符串中所有的小写字母都变成大写字母

*/

void fun14()

{

    string str="abcDEF";

    for (int i = 0; i < str.size(); i++)

    {

        // str[i]=toupper(str[i]);//全部转大写

        str[i]=tolower(str[i]);//全部转小写

    }

    cout<<str<<endl;

   

}

Vector

概述

连续开辟 , 单向开口 , 随机访问迭代器 , 有容量 , 每次扩容是原来的 2
底层数据结构 : 数组

 与数组区别

vector 的结构类同于数组,数组是静态的,在定义时确定的数组的大小;
vector 是动态的,添加元素时如果空间不足时,则会自动扩容器( 2^n); 这被称为
vector 的未雨绸缪机制
整体来说, vector 比较灵活的,而且 vector 是类模板,可以存放任意类型的元素

 迭代器

 构造函数

语法
vector<T> v; // 采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());// v[begin(), end()) 区间中的元素拷贝给本
身。
vector(n, elem);// 构造函数将 n elem 拷贝给本身。
vector(const vector &vec);// 拷贝构造函数
 示例

void fun01()

{

    vector<int> v01;

    v01.push_back(1);

    v01.push_back(5);

    v01.push_back(3);

    vector<int>::iterator it=v01.begin();//获取开始位置的迭代器

    while (it!=v01.end())//end():结束位置

    {

        cout<<*it<<endl;//*it获取当前迭代器指向的位置的值

        it++;//迭代器后移1位

    }

}

void fun02()

{

    vector<int> v01;

    v01.push_back(6);//尾部添加

    v01.push_back(5);

    v01.push_back(12);

    vector<int> v02(v01.begin()+1,v01.begin()+2);//包含开始位置,不包含结束位置(前闭后开)

    //vector<int>::iterator it=v02.begin();

    auto it=v02.begin();//c++11及以上版本,编译时需加-std=c++11

    while (it!=v02.end())

    {

        cout<<*it<<endl;

        it++;

    }

}

void fun03()

{

    vector<int> v(10,5);

    auto it=v.begin();

    while (it!=v.end())

    {

        cout<<*it<<endl;

        it++;

    }

}

 赋值操作

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

void fun04()

{

    // assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。

    // assign(n, elem);//将 n 个 elem 拷贝赋值给本身。

    // vector& operator=(const vector &vec);//重载等号操作符

    // swap(vec);// 将 vec 与本身的元素互换

    vector<int> v01;

    v01.push_back(1);

    v01.push_back(6);

    v01.push_back(9);

    v01.push_back(1);

    v01.push_back(3);

    v01.push_back(4);

    vector<int> v02;

    // v02.assign(v01.begin(),v01.begin()+3);

    // v02.assign(5,3);

    // v02 = v01;

    v02.push_back(2);

    v02.push_back(4);

    v02.swap(v01);

    auto it=v02.begin();

    while (it!=v02.end())

    {

        cout<<*it<<endl;

        it++;

    }

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

    auto it01=v01.begin();

    while (it01!=v01.end())

    {

        cout<<*it01<<endl;

        it01++;

    }

}

 插入与删除

语法
push_back(ele); // 尾部插入元素 ele
insert(const_iterator pos, int count, T ele); // 迭代器指向位置 pos 插入
count 个元素 ele.
pop_back();// 删除最后一个元素
erase(const_iterator start, const_iterator end); // 删除迭代器从 start
end 之间的元素 , 删除 [start, end) 区间的所有元素
erase(const_iterator pos); // 删除迭代器指向的元素
clear(); // 删除容器中所有元素
示例

void fun05()

{

    vector<int> v;

    // push_back(ele); //尾部插入元素 ele

    v.push_back(1);

    v.push_back(3);

    v.push_back(6);

    v.push_back(7);

    v.push_back(9);

    // insert(const_iterator pos, int count, T ele); //迭代器指向位置 pos 插入count个元素ele.

    v.insert(v.begin(),4,0);

    // pop_back();//删除最后一个元素

    v.pop_back();

    // erase(const_iterator start, const_iterator end); //删除迭代器从 start到 end 之间的元素,删除[start, end)区间的所有元素

    v.erase(v.begin()+1,v.begin()+3);

    // erase(const_iterator pos); //删除迭代器指向的元素

    // v.clear();

    // clear(); //删除容器中所有元素

    auto it=v.begin();

    while (it!=v.end())

    {

        cout<<*it<<endl;

        it++;

    }

}

 取值操作

语法
at(int idx); // 返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range
异常。
operator[](int idx); // 返回索引 idx 所指的数据,越界时 , 不会直接报错
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素
 示例

void fun06()

{

    vector<int> v;

    v.push_back(1);

    v.push_back(12);

    v.push_back(7);

    v.push_back(6);

    v.push_back(2);

    // at(int idx); //返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range异常。

    cout<<"v.at(3)="<<v.at(3)<<endl;

    // operator[](int idx); //返回索引 idx 所指的数据,越界时,不会直接报错

    cout<<"v[2]="<<v[100]<<endl;

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

    cout<<v.front()<<endl;

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

    cout<<v.back()<<endl;

}

 大小相关

语法
int size(); // 返回容器中元素的个数
bool empty(); // 判断容器是否为空, 返回 bool 值( 0 1
void resize(int num); // 重新指定容器的长度为 num ,若容器变长,则以默认值填
充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
void resize(int num, elem); // 重新指定容器的长度为 num ,若容器变长,则以
elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
int capacity(); // 容器的容量
void reserve(int len); // 容器预留 len 个元素长度
 示例

void fun07()

{

    vector<int> v;

    v.push_back(1);

    v.push_back(9);

    v.push_back(6);

    v.push_back(2);

    v.push_back(7);

    // cout<<v.size()<<endl;

    // int size(); // 返回容器中元素的个数

    cout<<v.empty()<<endl;

    // bool empty(); //判断容器是否为空, 返回bool值(0, 1)

    void resize(int num);

    // void resize(int num); //重新指定容器的长度为 num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。

    v.resize(2);

    // void resize(int num, elem); //重新指定容器的长度为 num,若容器变长,则以elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。

    v.resize(10,10);

    // int capacity(); //容器的容量

    cout<<v.capacity()<<endl;

    // void reserve(int len); //容器预留 len 个元素长度

    v.reserve(10);

    cout<<v.capacity()<<endl;

    auto it = v.begin();

    while(it != v.end())

    {

    cout << *it << endl;

    it++;

    }

}

void fun08()

{

    vector<int> v;

    v.push_back(1);

    v.push_back(3);

    v.push_back(5);

    v.push_back(7);

    v.push_back(9);

    cout << "v的大小 = " << v.size() << endl;

    cout << "v的容量 = " << v.capacity() << endl;

    vector<int>(v).swap(v);

    cout << "v的大小 = " << v.size() << endl;

    cout << "v的容量 = " << v.capacity() << endl;

}

 存储自定义类型

示例

void fun09()

{

    vector<Per> ps;

    ps.push_back(Per("张三"));

    ps.push_back(Per("李四"));

    ps.push_back(Per("王五"));

    ps.push_back(Per("赵六"));

    for (auto it=ps.begin();it!=ps.end();it++)

    {

        cout<<(*it).name<<endl;

    }

}

 容器嵌套

void fun10()

{

    vector<int> v1;

    v1.push_back(10);

    v1.push_back(20);

    v1.push_back(30);

    v1.push_back(40);

    v1.push_back(50);

    v1.push_back(60);

    vector<int> v2;

    v2.push_back(100);

    v2.push_back(200);

    v2.push_back(300);

    v2.push_back(400);

    v2.push_back(500);

    vector<int> v3;

    v3.push_back(1000);

    v3.push_back(2000);

    v3.push_back(3000);

    v3.push_back(4000);

    v3.push_back(5000);

    vector<vector<int>> v;

    v.push_back(v1);

    v.push_back(v2);

    v.push_back(v3);

    vector<vector<int>>::iterator it=v.begin();

    for (; it!=v.end();it++)

    {

        //*it==vector<int>

        vector<int>::iterator mit=(*it).begin();

        for (;mit!=(*it).end();mit++)

        {

            //*mit==int

            cout<<*mit<<"";

        }

        cout<<endl;

    }

}

重要案例

void fun11()

{

    vector<int> v;

    v.push_back(10);

    v.push_back(20);

    v.push_back(30);

    v.push_back(40);

    v.push_back(50);

    v.push_back(60);

    //逆序遍历

    for (vector<int>::reverse_iterator it=v.rbegin();it!=v.rend();it++)

    {

       cout<<*it<<endl;

    }

    //vector的迭代器是随机访问迭代器,支持跳跃访问

    vector<int>::iterator itBegin=v.begin();

    itBegin=itBegin+3;

    cout<<*itBegin<<endl;

}

 deque

概述

deque 则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分
别做元素的插入和删除操作
数据结构 : 数组

与vector的区别

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

二在于 deque 没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以
增加一段新的空间并链接起来

 api

// 构造函数
deque<T> deqT;// 默认构造形式
deque(beg, end);// 构造函数将 [beg, end) 区间中的元素拷贝给本身。
deque(n, elem);// 构造函数将 n elem 拷贝给本身。
deque(const deque &deq);// 拷贝构造函数
// 赋值操作
assign(beg, end);// [beg, end) 区间中的数据拷贝赋值给本身。
assign(n, elem);// n elem 拷贝赋值给本身。
deque& operator=(const deque &deq); // 重载等号操作符
swap(deq);// deq 与本身的元素互换
// 大小操作
deque.size();// 返回容器中元素的个数
deque.empty();// 判断容器是否为空
deque.resize(num);// 重新指定容器的长度为 num, 若容器变长,则以默认值填充新
位置。如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); // 重新指定容器的长度为 num, 若容器变长,则以 elem
值填充新位置 , 如果容器变短,则末尾超出容器长度的元素被删除。
// 双端插入和删除操作
push_back(elem);// 在容器尾部添加一个数据
push_front(elem);// 在容器头部插入一个数据
pop_back();// 删除容器最后一个数据
pop_front();// 删除容器第一个数据
// 数据存取
at(idx);// 返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range
operator[];// 返回索引 idx 所指的数据,如果 idx 越界,不抛出异常,直接出
错。
front();// 返回第一个数据。
back();// 返回最后一个数据
// 插入操作
insert(pos,elem);// pos 位置插入一个 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);// pos 位置插入 n elem 数据,无返回值。
insert(pos,beg,end);// pos 位置插入 [beg,end) 区间的数据,无返回值。
// 删除操作
clear();// 移除容器的所有数据
erase(beg,end);// 删除 [beg,end) 区间的数据,返回下一个数据的位置。
erase(pos);// 删除 pos 位置的数据,返回下一个数据的位置。

stack

概念

(先进后出,又名水桶),单向开口,没有迭代器

 

 api

构造函数
stack<T> stkT;//stack 采用模板类实现, stack 对象的默认构造形式:
stack(const stack &stk);// 拷贝构造函数
赋值操作
stack& operator=(const stack &stk);// 重载等号操作符
数据存取操作
push(elem);// 向栈顶添加元素
pop();// 从栈顶移除第一个元素
top();// 返回栈顶元素
大小操作
empty();// 判断堆栈是否为空
size();// 返回堆栈的大小

 示例

void fun01()

{

    stack<int> s;

    //入栈

    s.push(10);

    s.push(20);

    s.push(30);

    s.push(40);

    while (!s.empty())

    {

        //访问栈顶元素

        cout<<s.top()<<endl;

        //出栈

        s.pop();

    }

    cout<<"size="<<s.size()<<endl;

}

 queue

概念

队列 ( 先进先出 ), 又名水管 , 双向开口 , 没有迭代器
队头 : 出数据
队尾 : 入数据

api

构造函数
queue<T> queT;//queue 采用模板类实现, queue 对象的默认构造形式:
queue(const queue &que);// 拷贝构造函数
存取、插入和删除操作
push(elem);// 往队尾添加元素
pop();// 从队头移除第一个元素
back();// 返回最后一个元素
front();// 返回第一个元素
赋值操作
queue& operator=(const queue &que);// 重载等号操作符
大小操作
empty();// 判断队列是否为空
size();// 返回队列的大小

示例

 #include<iostream>

#include<queue>

#include<string>

using namespace std;

class Person

{

public:

    Person(string name,int age)

    {

        this->m_Name=name;

        this->m_Age=age;

    }

    string m_Name;

    int m_Age;

};

void fun01()

{

    queue<Person> Q;//队列容器

    Person p1("张三",18);

    Person p2("李四",10);

    Person p3("王五",12);

    Person p4("赵六",28);

    Person p5("二狗",30);

    //入队

    Q.push(p1);

    Q.push(p2);

    Q.push(p3);

    Q.push(p4);

    Q.push(p5);

    cout<<"size="<<Q.size()<<endl;

    while (!Q.empty())

    {

        cout<<"队头元素--姓名"<<Q.front().m_Name<<"年龄:"<<Q.front().m_Age<<endl;

        cout<<"队尾元素--姓名"<<Q.back().m_Name<<"年龄:"<<Q.back().m_Age<<endl;

        //出队

        Q.pop();

    }

    cout<<"size="<<Q.size()<<endl;

}

int main(int argc, char const *argv[])

{

    fun01();

    return 0;

}

list 

概念

基于双向链表的 , 离散存储的 , 双向迭代器 , 元素可重复
数据结构 : 链表
双向迭代器 : 可以 ++,--, 但是不能 +,-,不支持随机访问

 

api 

构造函数
list<T> lstT;//list 采用采用模板类实现 , 对象的默认构造形式:
list(beg,end);// 构造函数将 [beg, end) 区间中的元素拷贝给本身。
list(n,elem);// 构造函数将 n elem 拷贝给本身。
list(const list &lst);// 拷贝构造函数。
数据元素插入和删除操作
push_back(elem);// 在容器尾部加入一个元素
pop_back();// 删除容器中最后一个元素
push_front(elem);// 在容器开头插入一个元素
pop_front();// 从容器开头移除第一个元素
insert(pos,elem);// pos 位置插 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);// pos 位置插入 n elem 数据,无返回值。
insert(pos,beg,end);// pos 位置插入 [beg,end) 区间的数据,无返回值。
clear();// 移除容器的所有数据
erase(beg,end);// 删除 [beg,end) 区间的数据,返回下一个数据的位置。
erase(pos);// 删除 pos 位置的数据,返回下一个数据的位置。
remove(elem);// 删除容器中所有与 elem 值匹配的元素。
大小操作
size();// 返回容器中元素的个数
empty();// 判断容器是否为空
resize(num);// 重新指定容器的长度为 num ,若容器变长,则以默认值填充新位
置。如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);// 重新指定容器的长度为 num, 若容器变长,则以 elem
填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
赋值操作
assign(beg, end);// [beg, end) 区间中的数据拷贝赋值给本身。
assign(n, elem);// n elem 拷贝赋值给本身。
list& operator=(const list &lst);// 重载等号操作符
swap(lst);// lst 与本身的元素互换。
数据的存取
front();// 返回第一个元素。
back();// 返回最后一个元素。
反转排序
reverse();// 反转链表,比如 lst 包含 1,3,5 元素,运行此方法后, lst 就包
5,3,1 元素。
sort(); //list 排序

示例

//遍历链表

void printList(list<int> & L)

{

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

    {

        cout<<*it<<endl;

    }

}

void fun01()

{

    list<int> nums;

    nums.push_back(1);

    nums.push_back(5);

    nums.push_back(3);

    nums.push_back(7);

    nums.reverse();

    printList(nums);

}

void fun02()

{

    list<int> nums;

    nums.push_back(1);

    nums.push_back(5);

    nums.push_back(3);

    nums.push_back(7);

    nums.sort();

    printList(nums);

}

void fun03()

{

    list<int> nums;

    nums.push_back(1);

    nums.push_back(5);

    nums.push_back(3);

    nums.push_back(7);

    nums.sort();

    nums.reverse();

    printList(nums);

}

void fun04()

{

    list<int> nums;

    nums.push_back(1);

    nums.push_back(5);

    nums.push_back(3);

    nums.push_back(7);

    printList(nums);

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

    nums.push_front(22);

    nums.push_front(33);

    nums.push_front(66);

    printList(nums);

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

    nums.pop_back();//尾删

    nums.pop_front();//头删

    printList(nums);

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

    //插入

    nums.insert(nums.begin(),8888);

    printList(nums);

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

    nums.erase(nums.begin());

    printList(nums);

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

    //remove 直接删除数组内该元素,将一样的也一起删除

    nums.push_back(22);

    nums.push_back(22);

    nums.remove(22);

    nums.remove(33);

    printList(nums);

}

//遍历链表

void printList(list<int> & L)

{

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

    {

        cout<<*it<<endl;

    }

}

bool myCompare(int v1,int v2)

{

    return v1>v2;

}

void fun05()

{

    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);

    //反转

    L.reverse();

    printList(L);

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

    //排序 如果容器的迭代器支持随机访问,可以使用系统提供的标志算法

    //不支持随机访问的迭代器容器,内部会提供对应的算法接口

    //sort(L.begin(),L.end());

    L.sort(myCompare);

    printList(L);

}

//遍历链表

void printList(list<int> & L)

{

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

    {

        cout<<*it<<endl;

    }

}

class Person

{

public:

    Person(string name,int age,int height)

    {

        this->m_Name=name;

        this->m_Age=age;

        this->m_Height=height;

    }

    bool operator==(const Person & p)

    {

        if (this->m_Name==p.m_Name&&this->m_Age==p.m_Age&&this->m_Height==p.m_Height)

        {

            return true;

        }

        return false;

    }

    string m_Name;

    int m_Age;

    int m_Height;

};

bool myComparePerson(Person &p1,Person &p2)

{

    if (p1.m_Age==p2.m_Age)

    {

        return p1.m_Height<p2.m_Height;

    }

   

    return p1.m_Age>p2.m_Age;

}

void fun06()

{

    list<Person> L;

    Person p1("王尼玛",17,178);

    Person p2("法外狂徒",27,153);

    Person p3("李大奔",22,168);

    Person p4("沙巴特",44,172);

    Person p5("杀马特",5,145);

    Person p6("狗哥",36,197);

    Person p7("刘备",26,170);

    Person p8("关羽",26,217);

    Person p9("张飞",26,194);

   

    L.push_back(p1);

    L.push_back(p2);

    L.push_back(p3);

    L.push_back(p4);

    L.push_back(p5);

    L.push_back(p6);

    L.push_back(p7);

    L.push_back(p8);

    L.push_back(p9);

    //按照年龄进行降序   从大到小,如果年龄相等,按照身高进行升序

    //对于自定义数据类型,必须要指定排序规则

    L.sort(myComparePerson);

    for (list<Person>::iterator it=L.begin();it!=L.end();it++)

    {

        cout<<"姓名:"<<(*it).m_Name<<"  年龄:"<<it->m_Age<<"  身高:"<<it->m_Height<<endl;

    }

    //删除杀马特

    L.remove(p5);

    cout<<"删除杀马特后"<<endl;

    for (list<Person>::iterator it=L.begin();it!=L.end();it++)

    {

        cout<<"姓名:"<<(*it).m_Name<<"  年龄:"<<it->m_Age<<"  身高:"<<it->m_Height<<endl;

    }

}

 注意:如果利用remove删除自定义数据类型,需要重载==

set/multiset

set特点

Set 的特性是所有元素都会根据元素的键值自动被排序。
set 容器的键值和实值 是同一个值。
Set 不允许两个元素 有相同的键值。
Set 容器的迭代器 是只读迭代器。 插入数据后 不允许修改 set 的键值。
数据结构 : 红黑树
注意 :
如果存入的值大于原有的值 , 此时 x > y 为真 , 存入的值在原有值左边
如果存储的值小于原有的值 , 此时 x > y 为假 , 交换在比较
如果交换后 , 存储的值为 y, 原有值的为 x, 此时 x > y 为真 , 存入的值不应该在原有
值左边
如果交换后 , 存储的值为 y, 原有值的为 x, 此时 x > y 为假 , 此时证明不符合其存储
原则

 multiset特点

multiset 特性及用法和 set 完全相同,唯一的差别在于它允许键值重复。
数据结构 : 红黑树

api

 构造函数

set<T> st;//set 默认构造函数:
mulitset<T> mst; //multiset 默认构造函数 :
set(const set &st);// 拷贝构造函数
赋值操作
set& operator=(const set &st);// 重载等号操作符
swap(st);// 交换两个集合容器
大小操作
size();// 返回容器中元素的数目
empty();// 判断容器是否为空
插入和删除操作
insert(elem);// 在容器中插入元素。 clear();// 清除所有元素
erase(pos);// 删除 pos 迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);// 删除区间 [beg,end) 的所有元素 ,返回下一个元素的迭代器。
erase(elem);// 删除容器中值为 elem 的元素。
查找操作
find(key);// 查找键 key 是否存在 , 若存在,返回该键的元素的迭代器;若不存在,
返回 set.end();
count(key);// 查找键 key 的元素个数
lower_bound(keyElem);// 下限返回第一个 key>=keyElem 元素的迭代器。
upper_bound(keyElem);// 上限返回第一个 key>keyElem 元素的迭代器。
equal_range(keyElem);// 返回容器中 key keyElem 相等的上下限的两个迭代
器。

示例

 void printSet(set<int>&s)

{

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

    {

        cout<<*it<<endl;

    }

}

void fun01()

{

    set<int>s;

    s.insert(10);

    s.insert(30);

    s.insert(20);

    s.insert(40);

    s.insert(90);

    s.insert(60);

    printSet(s);

    if (s.empty())

    {

        cout<<"set容器为空"<<endl;

    }

    else

    {

        cout<<"set容器不为空 大小为:"<<s.size()<<endl;

    }

    s.erase(40);

    printSet(s);

}

void fun02()

{

    set<int>s;

    s.insert(10);

    s.insert(30);

    s.insert(20);

    s.insert(40);

    s.insert(90);

    s.insert(60);

    set<int>::iterator pos=s.find(30);

    if (pos!=s.end())

    {

        cout<<"找到了元素"<<*pos<<endl;

    }

    else

    {

        cout<<"没找到"<<endl;

    }

    //对于set而言,要么0 要么1

    int num=s.count(40);

    cout<<"key为40的个数为:"<<num<<endl;

    //lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器

    set<int>::iterator pos2=s.lower_bound(30);

    if (pos2!=s.end())

    {

        cout<<"lower_bound的值为:"<<*pos2<<endl;

    }

    else

    {

        cout<<"未找到"<<endl;

    }

    //upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器

    pos2=s.upper_bound(30);

        if (pos2!=s.end())

    {

        cout<<"lower_bound的值为:"<<*pos2<<endl;

    }

    else

    {

        cout<<"未找到"<<endl;

    }

    //equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器

    pair<set<int>::iterator,set<int>::iterator>ret=s.equal_range(30);

    if (ret.first!=s.end())

    {

        cout<<"equal_range中的lower_bound的值为:"<<*ret.first<<endl;

    }

      if (ret.second!=s.end())

    {

        cout<<"equal_range中的upper_bound的值为:"<<*ret.second<<endl;

    }

   

}

map/multimap

map概述

 键值对的形式存储数据,一个键值对称为一个对组

这一对值可以具有不同的数据类型,两个值可以分别用 pair( 对组 ) 的两个公共的成员
变量 first( ) second( ) 访问。
不允许键重复

multimap概述

 允许键重复

api

map 构造函数

map<T1, T2> mapTT;//map 默认构造函数 :
T1: 键的数据类型 , 要有可比较性 , 基本数据类型都有可比性
T2: 值的数据类型
map(const map &mp);// 拷贝构造函数
map 赋值操作
map& operator=(const map &mp);// 重载等号操作符
swap(mp);// 交换两个集合容器
map 大小操作
size();// 返回容器中元素的数目
empty();// 判断容器是否为空
map 插入数据元素操作
map.insert(...); // 往容器插入元素,返回 pair<iterator,bool>
map 删除操作
clear();// 删除所有元素
erase(pos);// 删除 pos 迭代器所指的元素,返回下一个元素的迭代器。
erase(beg,end);// 删除区间 [beg,end) 的所有元素 ,返回下一个元素的迭代器。
erase(keyElem);// 删除容器中 key keyElem 的对组。
map 查找操作
find(key);// 查找键 key 是否存在 , 若存在,返回该键的元素的迭代器;若不存在,
返回 map.end();
count(keyElem);// 返回容器中 key keyElem 的对组个数。对 map 来说,要么
0 ,要么是 1 。对 multimap 来说,值可能大于 1
lower_bound(keyElem);// 返回第一个 key>=keyElem 元素的迭代器。
upper_bound(keyElem);// 返回第一个 key>keyElem 元素的迭代器。
equal_range(keyElem);// 返回容器中 key keyElem 相等的上下限的两个迭代
器。

示例

void fun01()

{

    map<int,int>m;

    //第一种插入方式

    m.insert(pair<int,int>(1,10));

    //第二种插入方式  推荐

    m.insert(make_pair(2,20));

    //第三种插入方式

    m.insert(map<int,int>::value_type(3,30));

    //第四种

    m[4]=40;

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

    {

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

    }

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

    m.erase(3);//删除传入key的值

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

    {

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

    }

   

}

void fun02()

{

    map<int,int>m;

    //第一种插入方式

    m.insert(pair<int,int>(1,10));

    //第二种插入方式  推荐

    m.insert(make_pair(2,20));

    //第三种插入方式

    m.insert(map<int,int>::value_type(3,30));

    //第四种

    m[4]=40;

    map<int,int>::iterator ret=m.find(3);

    if (ret!=m.end())

    {

        cout<<"找到了key为"<<ret->first<<"value="<<ret->second<<endl;

    }

    else

    {

        cout<<"未找到"<<endl;

    }

    int num=m.count(4);

    cout<<"key为4的对组个数为:"<<num<<endl;

    //lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器

    map<int,int>::iterator pos=m.lower_bound(3);

    if (pos!=m.end())

    {

        cout<<"找到了lower_bound key:"<<pos->first<<"value="<<pos->second<<endl;

    }

    else

    {

        cout<<"未找到"<<endl;

    }

    //upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器

    pos=m.upper_bound(3);

    if (pos!=m.end())

    {

        cout<<"找到了upper_boun key:"<<pos->first<<"value="<<pos->second<<endl;

    }

    else

    {

        cout<<"未找到"<<endl;

    }

    //equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器

    pair<map<int,int>::iterator,map<int,int>::iterator> ret2=m.equal_range(3);

    if (ret2.first!=m.end())

    {

        cout<<"找到了equal_range中的lower_bound的key="<<ret2.first->first<<"value="<<ret2.first->second<<endl;

    }

    else

    {

        cout<<"未找到"<<endl;

    }

    if (ret2.second!=m.end())

    {

        cout<<"找到了equal_range中的upper_boun的key="<<ret2.second->first<<"value="<<ret2.second->second<<endl;

    }

    else

    {

        cout<<"未找到"<<endl;

    }

   

}

class myCompareInt

{

public:

    bool operator()(int v1,int v2)

    {

        return v1>v2;

    }

};

void fun03()

{

    map<int,int,myCompareInt>m;

    //第一种插入方式

    m.insert(pair<int,int>(1,10));

    //第二种插入方式  推荐

    m.insert(make_pair(2,20));

    //第三种插入方式

    m.insert(map<int,int>::value_type(3,30));

    //第四种

    m[4]=40;

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

    {

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

    }

   

}

总结

 vector 单端动态数组 随机访问迭代器 (重点)

比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次
的记录,但却不会去删除记录,因为记录是事实的描述。
数据结构 : 数组
deque :双端动态数组 随机访问迭代器
deque 的使用场景:比如排队购票系统,对排队者的存储可以采用 deque ,支持头端
的快速移除,尾端的快速添加
stack 栈容器 没有迭代器 先进后出
queue 队列容器 没有迭代器 先进先出
list 链表容器 双向迭代器 ( 重点 )
比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入
数据结构 : 双链表
set 容器 只有键值 键值不能重复 自动排序 只读迭代器
比如对手机游戏的个人得分记录的存储,存储要求从高 分到低分的顺序排列。
数据结构 : 红黑树
map 容器: 键值 - 实值成对出现 键值不能重复 自动排序 只读迭代器 ( 重点 )
比如按 ID 号存储十万个用户,想要快速要通过 ID 查找对应的用户。
数据结构 : 红黑树

评委打分案例 

​​​​​​​#include<iostream>

#include<vector>

#include<string>

#include<deque>

#include<stdlib.h>

#include<algorithm>

#include<time.h>

using namespace std;

/*

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

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

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

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

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

5.person.score=平均分

*/

class Player

{

public:

    Player(string name,int score)

    {

        this->m_Name=name;

        this->m_Score=score;

    }

    string m_Name;//姓名

    int m_Score;//平均分

};

void createPlayer(vector<Player>&v)  //必须用引用的方式接收

{

    string nameSeed="ABCDE";

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

    {

        string name="选手";

        name+=nameSeed[i];

        int score=0;

        Player player(name,score);

        v.push_back(player);

    }

}

void setScore(vector<Player>&v)

{

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

    {

        deque<int>d;//存放评委打分的容器

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

        {

            int score=rand()%41+60;//60~100

            d.push_back(score);

        }

        cout<<it->m_Name<<"打分情况"<<endl;

        for (deque<int>::iterator dit=d.begin();dit!=d.end();dit++)

        {

            cout<<*dit<<" ";

        }

        cout<<endl;

    //排序

    sort(d.begin(),d.end());

    //去除最高最低分

    d.pop_back();//最高分

    d.pop_front();//最低分


 

    //总分

    int sum=0;

    for (deque<int>::iterator dit=d.begin();dit!=d.end();dit++)

    {

        sum+=*dit;

    }

    //平均分

    int avg=sum/d.size();

    it->m_Score=avg;

    }

   

}

void showScore(vector<Player> &v)

{

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

    {

         cout<<"姓名:"<<(*it).m_Name<<" 平均分数:"<<(*it).m_Score<<endl;

    }

   

}

int main(int argc, char const *argv[])

{

    //设置随机数种子

    srand((unsigned int)time(NULL));

    //1.创建5名选手

    vector<Player> v;

    createPlayer(v);

    //2.打分

    setScore(v);


 

    //3.显示平均分

    showScore(v);

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

    // {

    //     cout<<"姓名:"<<(*it).m_Name<<" 分数:"<<(*it).m_Score<<endl;

    // }

   

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值