STL专栏之C++容器,我的容器我做主,体验容器背后带来的数据结构。vector、string、deque、List、stack、queue、set、map等容器用法大全集以及其案例解析

STl初识

1.STL的诞生

长久以来,软件界一直希望建立一种可重复利用的东西

C++的面向对象泛型编程思想,目的就是复用性的提升

大多情况下,数据结构和算法都未能有一套标准,导致被迫从事大量重复工作

为了建立数据结构和算法的一套标准,诞生了STL

2.STL基本概念

STL(Standard Template Library,标准模板库)

STL从广义上分为:容器(container)算法(algorithm)迭代器(iterator)

容器和算法之间通过迭代器进行无缝连接

STL几乎所有的代码都采用了模板类或者模板函数

3.STL六大组件

STL大体分为六大组件,分别是:容器算法迭代器仿函数适配器(配接器)空间配置器

  1. 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据。

  2. 算法:各种常用的算法,如sort、find、copy、for_each等。

  3. 迭代器:扮演了容器与算法之间的胶合剂。

  4. 仿函数:行为类似函数。可作为算法的某种策略。(重载小括号)

  5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。

  6. 空间配置器:负责空间的配置与管理。

4.STL中容器、算法、迭代器

1.容器

容器:置物之所也

STL容器就是将运用最广泛的一些数据结构实现出来

常用的数据结构:数组,链表,树,栈,队列,集合,映射表等

这些容器分为序列式容器关联式容器两种:

  1. 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。

  2. 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

2.算法

算法:问题之解法也

有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms)

算法分为质变算法非质变算法

质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等

非质变算法:是指运算过程中不会更改区间内的元素内客,例如查找、计数、遍历、寻找极值等等

3.迭代器

迭代器:容器和算法之间粘合剂

提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。

每个容器都有自己专属的迭代器

迭代器使用非常类似于指针,初学阶段我们]可以先理解迭代器为指针

迭代器种类:

种类 功能 支持运算
输入迭代器 对数据的只读访问 只读,支持++、==、!=
输出迭代器 对数据的只写访问 只写,支持++
前向迭代器 读写操作,并能向前推进迭代器 读写,支持++、==、!=
双向迭代器 读写操作,并能向前和向后操作 读写,支持++、--
随机访问迭代器 读写操,可以以跳跃的方式访问任意数据,是功能最强的迭代器 读写,支持++、--、[n]、-n、<、<=、>、>=

常用的容器中迭代器种类为双向迭代器,和随机访问迭代器

vector容器

1.vector基本概念

功能

vector数据结构和数组非常相似,也称为单端数组

vector与普通数组区别

不同之处在于数粗是静态空间,而vector可以动态扩展

动态扩展

并不是在原空间之后接新空间,而是找更大的内存空间。然后将原款据拷贝新空间,释放原空间

 

vector容器的迭代器是支持随机访问的迭代器

2.vector构造函数

功能描述

创建vector客器

函数原型

vector<T>v;采用模板实现类实现,默认构造函数

vector(v.begin(), v.end());将v[begin().end()]区间中的元素拷贝给本身

vector(n, elem)构造函数将n个elem拷贝给本身。

vector(const vector &vec);作拷贝构造函数。

#include<iostream>
#include<vector>
using namespace std;
​
void printVector(vector<int>&v)
{
    for(vector<int>::iterator it = v.begin();it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//vector容器构造
void test01()
{
    vector<int>v1;//默认构造 无参构造
    
    for(int i = 0;i < 10; i++)
    {
        v1.push_back(i);
    }
    
    printVector(v1);
    
    //通过区间的形式进行构造
    vector<int>v2(v1.begin(), v1.end());
    printVector(v2);
    
    //n个elem方式构造
    vector<int>v3(10, 100);
    printVector(v3);
    
    //拷贝构造
    vector<int>v4(v3);
    printVector(v4);
}
​
int main()
{
    test01();
    return 0;
}

3.vector赋值操作

功能描述

给vector容器进行联值

函数原型

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

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

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

#include<iostream>
#include<vector>
using namespace std;
​
//打印函数
void printVextor(vector<int>& v)
{
    for(vrctor::iterator it = v.begin();it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//vector容器赋值操作
void test01()
{
    vector<int>v1;
    for(int i = 0;i < 10; i++)
    {
        v1.push_back(i);
    }
    
    printVector(v1);
    
    //1.赋值 operator
    vector<int>v2;
    v2 = v1;
    printVector(v2);
    
    //2.assign
    vector<int>v3;
    v3.assign(v1.begin(),v2.end());
    printVector(v3);
    
    //3.n个elem方式
    vector<int>v4;
    v4.assign(10, 100);
    printVector(v4);
}
​
int main()
{
    test01();
    return 0;
}

总结:vector赋值方式比较简单,使用operator=或者assign都可以

4.vector容器和大小

功能描述

对vector容器的容量和大小操作

函数原型

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

capacity():容器的容量

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

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

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

示例

#include<iostream>
#include<vector>
using namespace std;
​
void printVector(vector<int>& v)
{
    for(vector<int>::iterator it = v.begin();it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//vector容器的容量和大小操作
void test01()
{
    vector<int>v1;
    for(int i = 0;i < 10; i++)
    {
        v1.push_back(i);
    }
    printVector(v1);
    
    //判断是否为空
    if(v1.empty())//为真 则代表容器为空
    {
        cout << "v1为空" << endl;
    }
    else 
    {
        cout << "v1不为空" << endl;
        cout << "v1的容量为:" << v1.capacity() << endl;
        cout << "v1的大小为:" << v1.size() << endl;
    }
    
    //重新指定大小
    v1.resize(20);//利用重载版本,可以指定默认填充值
    printVector(v1);//如果重新指定的比原来长,默认用0来填充新的位置,也可以自己定义,v1.resize(20,100);后面补充的就全为100
    
    v1.resize(5);
    printVector(v1);//若重新指定的比原来短了,超出部分会被删除
}
​
int main()
{
    test01();
    return 0;
}

总结

  1. 判断是否为空一empty

  2. 返回元素个数一size

  3. 返回容器容量一capacity

  4. 新指定大小resize

5.vector插入和删除

功能描述

对vector容器进行插入、删除操作

函数原型

push_back(ele);尾插入元素ele

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

insert(const_iterator pos,ele);迭代器指向位置pos插入元素ele

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

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

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

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

示例

#include<iostream>
#include<vector>
using namespace std;
​
void printVector(vector<int>v)
{
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//vector容器的插入和删除
void test01()
{
    vector<int>v1;
    for(int i = 0;i < 10; i++)
    {
        v1.push_back(i);
    }
    
    printVector(v1);
    
    //尾插元素ele
    v1.push_back(10);
    printVector(v1);
    
    //删除最后一个元素
    v1.pop_back();
    printVector(v1);
    
    //迭代器指定位置pos插入元素ele
    v1.insert(v1.begin(),11);
    printVector(v1);
    
    //迭代器指向位置pos插入一系列元素
    v1.insert(v1.begin(),2,12);
    printVector(v1);
    
    //删除 参数也是迭代器
    v1.erase(v1.begin());
    printVector(v1);
    
    //清空
    //v1.erase(v1.begin(), v1.end());相当于clear清空
    v1.erase(v1.begin(), v1.end());
    printVector(v1);
    
}
​
int main()
{
    test01();
    return 0;
}

6.vector数据存储

功能描述

对vector中的数据的存取操作

函数原型

at(int idx);返回索引idx所指的数据

operator[];返回索引idx所指的数据

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

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

示例

#include<iostream>
#include<vector>
using namespace std;
​
//vector容器 数据存取
void test01()
{
    vector<int>v1;
    for(int i = 0;i < 10; i++)
    {
        v1.push_back(i);//尾插法
    }
    
    //利用[]方式访问数组中的元素
    for(int i = 0;i < v1.size(); i++)
    {
        cout << v1[i] << " ";
    }
    cout << endl;
    
    //利用at方式访问元素
    for(int i = 0;i < v1.size(); i++)
    {
        cout << v1.at(i) << " ";
    }
    cout << endl;
    
    //输出第一个元素
    cout << "第一个元素为:" << v1.front() << endl;
    
    //输出最后一个元素
    cout << "最后一个元素为:" << v1.back() << endl;
}
​
int main()
{
    test01();
    return 0;
}

总结

除了用迭代器获取vector容器中元素,[]和at也可以

front返回容器第一个元素

back返回容器最后一个元素

7.vector互换容器

功能描述

实现两个容器内元素进行互换

函数原型

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

示例

#include<iostream>
#include<vector>
using namespace std;
​
void printVector(vector<int>&v)
{
    for(vector<int>::iterator it = v.begin();it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//vector容器互换
​
//基本使用
void test01()
{
    vector<int>v1;
    for(int i = 0;i < 10; i++)
    {
        v1.push_back(i);
    }
    cout << "交换前,v1:";
    printVector(v1);
    
    vector<int>v2;
    for(int i = 10;i > 0; i--)
    {
        v2.push_back(i);
    }
    cout << "交换前,v2:";
    printVector(v2);
    
    v1.swap(v2);
    cout << "交换后,v1:";
    printVector(v1);
    
    cout << "交换后,v2:";
    printVector(v2);
}
​
//实际用途
//巧用swap可以收缩内存空间
void test02()
{
    vector<int>v;
    for(int i = 0;i < 100000; i++)
    {
        v.push_back(i);
    }
    cout << "v的容量为:" << v.capacity() << endl;
    cout << "v的大小为:" << v.size() << endl;
    
    //重新指定大小
    v.resize(3);
    cout << "v的容量为:" << v.capacity() << endl;
    cout << "v的大小为:" << v.size() << endl;
    
    //巧用swap收缩内存
    vector<int>(v).swap(v);//vector<int>(v)匿名对象
    cout << "v的容量为:" << v.capacity() << endl;
    cout << "v的大小为:" << v.size() << endl;
}
​
int main()
{
    test01();
    test02();
    return 0;
}
交换前,v1:0 1 2 3 4 5 6 7 8 9
交换前,v2:2 2 2 2 2 2 2 2 2 2
交换后,v1:2 2 2 2 2 2 2 2 2 2
交换后,v2:0 1 2 3 4 5 6 7 8 9

总结:swap可以使两个容器互换,可以达到实用的收缩内存的效果。

8.vector预留空间

功能描述

减少vector在动态扩展容量时的扩展次数

函数原型

reserve(int len);容器预留len个元素长度,预留位置不初始化,元素不可访问。

示例

//没有reserve,那么扩展容量次数就会很多次
#include<iostream>
#include<vector>
using namespace std;
​
//vector容器 预留空间
void test01()
{
    vector<int>v;
    int num = 0;//统计开辟次数
    int *p = NULL;
    for(int i = 0;i < 10000; i++)
    {
        v.push_back(i);
        
        if(p != &v[0])
        {
            p = &v[0];
            num++;
        }
    }
    cout << "num = " << num << endl;
}
​
int main()
{
    test01();
    return 0;
}
//reserve
#include<iostream>
#include<vector>
using namespace std;
​
//vector容器 预留空间
void test01()
{
    vector<int>v;
    
    //利用reserve预留空间
    v.reserve(10000);
    
    int num = 0;//统计开辟次数
    int *p = NULL;
    for(int i = 0;i < 10000; i++)
    {
        v.push_back(i);
        
        if(p != &v[0])
        {
            p = &v[0];
            num++;
        }
    }
    cout << "num = " << num << endl;//输出num = 1
}
​
int main()
{
    test01();
    return 0;
}

总结:如果数据比较大,可以一开始利用reserve预留空间

deque容器

1.deque容器基本概念

功能

双端数组,可以对头端进行插入删除操作

deque与vector区别

  1. vectors对于头部的插入除效率低,数据量越大,效率越低

  2. deque相对而言,对头部的插入删除速度可比vector快

  3. vector访问元素时的速度会比deque快,这和两者内部实现有

 

deque内部工作原理

deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据

中控器维护的盛每个缓冲区的地址,使得使用deque时像一片连续的内存空间

 

deque容器的迭代器也是支持随机访问的

2.deque构造函数

功能描述

dequet容器构造

函数原型

dequec<T>deqT;默认构造形式

deque(beg, end);构造函数将[beg,end)区间中的元拷贝给本身。

deque(n,elem):构造函数将n个elem拷贝给本身.

deque(const deque &deq);拷贝构造函数

示例

#include<iostream>
#include<deque>
using namespace std;
//deque构造函数
​
void printDeque(deque<int>&d)
{
    for(deque<int>::iterator it = d.begin();it != d.end(); it++)
    {
        *it = 100;//会对容器内的值产生影响
        cout << *it << " ";
    }
    cout << endl;
}
​
//为了防止发生在这个函数中对it进行的修改操作,我们可以对代码进行改进
void printDeque1(const deque<int>&d)
{
    for(deque<int>::const_iterator it = d.begin();it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    deque<int>d1;
    for(int i = 0;i < 10; i++)
    {
        d1.push_back(i);
    }
    printDeque1(d1);
    
    //拷贝
    deque<int>d2(d1.begin(),d1.end());
    printDeque1(d2);
    
    deque<int>d3(10, 100);
    printDeque1(d3);
    
    deque<int>d4(d3);
    printDeque1(d4);
}
​
int main()
{
    test01();
    return 0;
}

总结:deque容器和vector容器的构造方式几乎一致,灵活使用即可。

3.deque赋值操作

功能描述

给deque容器进行赋值

函数原型

deque&operator=(const deque &deq);重载等号操作符

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

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

示例

#include<iostream>
#include<deque>
using namespace std;
​
//deque容器赋值
void printDeque(const deque<int>&d)
{
    for(deque<int>::const_iterator it = d.begin();it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    deque<int>d1;
    for(int i = 0;i < 10; i++)
    {
        d1.push_front(i);
    }
    printDeque(d1);
    
    //赋值操作
    deque<int>d2;
    d2 = d1;
    printDeque(d2);
    
    //assign赋值
    deque<int>d3;
    d3.assign(d1.begin(), d1.end());
    printDeque(d3);
    
    deque<int>d4;
    d4.assign(10, 100);
    printDeque(d4);
}
​
int main()
{
    test01();
    return 0;
}

4.deque大小操作

功能描述

对deque容器的大小进行操作

函数原型

deque.empty();判断容器是否为空

deque.size();返回容器中元素的个数

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

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

#include<iostream>
#include<deque>
using namespace std;
​
void printDeque(const deque<int>& d)
{
    for(deque<int>::const_iterator it = d.begin();it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    deque<int>d1;
    for(int i = 0;i < 10; i++)
    {
        d1.push_back(i);
    }
    printDeque(d1);
    
    if(d1.empty())
    {
        cout << "d1为空" << endl;
    }
    else
    {
        cout << "d1不为空" << endl;
        cout << "d1的大小" << d1.size() << endl;
        //没有capacity容量的概念,因为deque容器可以无限地进行存放
    }
    
    //重新指定大小
    d1.resize(15);
    printDeque(d1);
    
    d1.resize(17, 1);
    printDeque(d1);
    
    d1.resize(3);
    printDeque(d1);
}
​
int main()
{
    test01();
    return 0;
}

总结

deque没有容量的概念

判断是否为空——empty

返回元素个数——size

重新指定个数——resize

5.deque插入和删除

功能描述

向deque容器中插入和删除数据

函数原型

两端插入操作:

push_back(elem);在容器尾部添加一个数据

push_front(elem);在容器头部插入一个数据

pop_back();删除容器最后一个数据

pop_front();删除容器第一个数据

指定位置操作:

insert(pos,elem);在pos位置插入一个elem元素的拷贝,返回新数据的位置

insert(pos,n,elem);在pos位置插入n个elem数据,无返回值

insert(pos,beg,end);在pos位置插入beg end区问的数据,无返回值

c1ear();清空容器的所有数据

erase(beg,end);删除[beg,end)区间的数据,返回下一个数据的位置

erase(pos);除pos位置的数据,返回下一个数的位置

示例

#include<iostream>
#include<deque>
using namespace std;
​
void printDeque(const deque<int>& d)
{
    for(deque<int>::const_iterator it = d.begin();it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    deque<int>d1;
    for(int i = 0;i < 5; i++)
    {
        //尾插
        d1.push_back(i);
    }
    printDeque(d1);
    
    for(int i = 10;i > 5; i--)
    {
        //头插
        d1.push_front(i);
    }
    printDeque(d1);
    
    //尾删
    d1.pop_back();
    printDeque(d1);
    //头删
    d1.pop_front();
    printDeque(d1);
    
    //insert插入
    d1.insert(d1.begin(), 100);
    printDeque(d1);
    
    d1.insert(d1.end() - 1, 2, 200);
    printDeque(d1);
    
    //按照区间进行插入
    deque<int>d2;
    d2.push_back(1);
    d2.push_back(2);
    d2.push_back(3);
    d2.push_back(4);
    
    d1.insert(d1.begin(), d2.begin(), d2.end());
    printDeque(d1);
    
    //删除
    deque<int>::iterator it = d1.begin();
    it++;//删除了第二个元素
    d1.erase(it);
    printDeque(d1);
    
    //按照区间的方式删除
    d1.erase(d1.begin() + 3, d1.end() - 3);
    printDeque(d1);
    
    //清空
    d1.clear();
    printDeque(d1);
}
​
int main()
{
    test01();
    return 0;
}

总结:

插入和删除提供的位置是迭代器!

尾插——push_back

尾删——pop_back

头插——push_fron

头删——pop.front

6.deque数据存取

功能描述

对deque中的数据的存取操作

函数原型

at(int idx);返回索引idx所指的数据

operator[];返回索引dx所指的数据

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

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

#include<iostream>
#include<deque>
using namespace std;
​
//deque数据存储操作
void test01()
{
    deque<int>d;
    d.push_back(10);
    d.push_back(20);
    d.push_back(30);
    d.push_back(40);
    d.push_back(50);
    d.push_front(9);
    d.push_front(8);
    d.push_front(7);
    d.push_front(6);
    
    //通过[]
    for(int i = 0;i < d.size(); i++)
    {
        cout << d[i] << " ";
    }
    cout << endl;
    
    //通过at的方式进行访问
    for(int i = 0;i < d.size(); i++)
    {
        cout << d.at(i) << " ";
    }
    cout << endl;
    
    cout << "第一个元素:" << d.front() << endl;
    cout << "最后一个元素:" << d.back() << endl;
}
​
int main()
{
    test01();
    return 0;
}

总结

  1. 除了用送代器获取deque容器中元素,[]和at也可以

  2. front返回容器第一个元素

  3. back返回容器最后一个元素

7.deque排序

功能描述

利用算法实现对deque容器进行排序

算法

sort(iterator beg,iterator lend);对beg和end区间内元素进行排序

#include<iostream>
#include<deque>
#include<algorithm>//标准算法头文件
using namespace std;
​
void printDeque(const deque<int>& d)
{
    for(deque<int>::const_iterator it = d.begin();it != d.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//deque容器排序
void test01()
{
    deque<int>d;
    d.push_back(10);
    d.push_back(20);
    d.push_back(30);
    d.push_front(100);
    d.push_front(200);
    d.push_front(300);
    
    //300 200 100 10 20 30
    printDeque(d);
    
    //排序 默认排序规则 是从小到大 升序
    //支持随机访问的迭代器都可以利用sort算法直接对其进行排序
    //vector容器也可以利用 sort进行排序
    sort(d.begin(), d.end());
    cout << "排序后:" << endl;
    printDeque(d);
}
​
int main()
{
    test01();
    return 0;
}

补充:vector排序

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
​
void printVector(const vector<int>v)
{
    for(vector<int>::const_iterator it = v.begin();it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    vector<int>v;
    v.push_back(1);
    v.push_back(6);
    v.push_back(7);
    v.push_back(3);
    v.push_back(5);
    v.push_back(2);
    v.push_back(4);
    v.push_back(8);
    
    printVector(v);
    
    sort(v.begin(), v.end());
    cout << "排序后:" << endl;
    printVector(v);
}
​
int main()
{
    test01();
    return 0;
}

string容器

字符串,我们都比较熟悉,这里也给大家展示一下具体的用法。

1.string基本概念

本质

string是C++风格的字符串,而string本质上是一个

string和char *区别:

  1. char* 是一个指针

  2. string是一个类,类内部封装了char * ,管理这个字符串,是一个char*型的容器.

特点:

  1. string类内部封装了很多成员方法

    例如:查找find,拷贝copy,删除delete替换replace,插入insert

    string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责

2.string构造函数

构造函数原型:

string();创建一个空的字符串,例如:string str;

string(const char* s);使用字符串s初始化

string(const string & str);使用一个string对象初始化另一个string对象

string(int n, char c)使用n个字符c初始化

示例

#include<iostream>
#include<string>
using namespace std;
​
//string的构造函数
void test01()
{
    string s1;//默认构造
    
    const char* str = "hello world";
    string s2(str);
    
    cout << "s2 = " << s2 << endl;
    
    string s3(s2);
    cout << "s3 = " << s3 << endl;
    
    string s4(10,'a');
    cout << "s4 = " << s4 << endl;
}
​
int main()
{
    test01();
    return 0;
}

总结:string的多种构造方式没有可比性,灵活便用即可

3.string的赋值操作

功能描述:

给string字符串进行赋值

赋值的函数原型string& operator=(const char*s);char类型字符串赋值给当前的字符串

string& operator=(const string &s);把字符串s赋给当前的字符串

string& operator=(char c);字符赋值给当前的字符串

string& assign(const char s);把字符串s赋给当前的字符串

string& ass1gm(const char s,int n);把字符串s的前n个字符赋给当前的字符串

string& assign(const string &s);把字符串s赋给当前字符串

string& assign(int n,char c);用n个字符c赋给当前字符串

示例

#include<iostream>
#include<string>
using namespace std;
​
//string赋值操作
/*
`string& operator=(const char*s);`char类型字符串赋值给当前的字符串
`string& operator=(const string &s);`把字符串s赋给当前的字符串
`string& operator=(char c);`字符赋值给当前的字符串
`string& assign(const char s);`把字符串s赋给当前的字符串
`str1ng& ass1gm(const char·s,intn);`把字符串s的前n个字符赋给当前的字符串
`string& assign(const string &s);`把字符串s赋给当前字符串
`string& assign(int n,char c);`用n个字符c给当前字符串
*/
​
void test01()
{
    string str1;
    str1 = "hello world";
    cout << "str1 = " << str1 << endl;
    
    string str2;
    str2 = str1;
    cout << "str2 = " << str2 << endl;
    
    string str3;
    str3 = 'a';
    cout << "str3 = " << str3 << endl;
    
    string str4;
    str4.assign("hello C++");
    cout << "str4 = " << str4 << endl;
    
    string str5;
    str5.assign("hello C++", 5);
    cout << "str5 = " << str5 << endl;
    
    string str6;
    str6.assign(str5);
    cout << "str6 = " << str6 << endl;
    
    string str7;
    str7.assign(10, 'w');
    cout << "str7 = " << str7 << endl;
}
​
int main()
{
    test01();
    return 0;
}

4.string字符串拼接

功能描述:

实现在字符串末尾拼接字特串

函数原型: string& operator+=(canst char* str);重载+=操作符

string& operator+=(const char c);重戴+=操作符

string& operator+=(const string& str);重载+=操作符

string& append(const char *s);把字符串s连接到当前字符串结尾

string& append(const char *s, int n);把字符串s的前n个字符连接到当前字符串结尾

string& append(const string &s);同operator+=(const string& str)

string& append(const string &s,int pos,int n);字符串s中从pos开始的n个字符连接到字符串结尾

示例

#include<iostream>
#include<string>
using namespace std;
​
//string字符串拼接
/*
`string& operator+=(canst char* str);`重载+=操作符
`string& operator+=(const char c);`重戴+=操作符
`string& operator+=(const string& str);`重载+=操作符
`string& append(const char *s);`把字符串s连接到当前字符串结尾
`string& append(const char *s, int n);`把字符串s的前个字符连接到当前字符串结尾
`string& append(const string &s);`同operator+=(const string& str)
`string& append(const string &s,int pos,int n);`字符串s中从pos开始的n个字符连接到字符串结尾
*/
​
void test01()
{
    string str1 = "我";
    str1 += "爱玩游戏";
    cout << "str1 = " << str1 << endl;
    
    str1 += '!';
    cout << "str1 = " << str1 << endl;
    
    string str2 = "LOL DNF";
    
    str1 += str2;
    cout << "str1 = " << str1 << endl;
    
    string str3 = "I";
    str3.append(" love ");
    cout << "str3 = " << str3 << endl;
    
    str3.append("game abcde",4);
    cout << "str3 = " << str3 << endl;
    
    str3.append(str2, 3, 4);
    cout << "str3 = " << str3 << endl;
}
​
int main()
{
    test01();
    return 0;
}

总结:字符串拼接的重载版本很多,初学阶段记住几种即可。

5.string查找和替换

功能描述:

查找:查找指定字符串是否存在

替换:在指定的位置替换字符串

函数原型:

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

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 chan*s);替换从pos开始的个字符为字符串s

示例:

#include<iostream>
#include<string>
using namespace std;
​
//string查找和替换
//查找
void test01()
{
    string str1 = "hello world";
    //find
    int pos = str1.find("ll");//从0开始索引,如果查的没有的话就会返回-1
    if(pos == -1)
    {
        cout << "未查到所需字符串" << endl;
    }
    else 
    {
        cout << "找到字符串,pos = " << pos << endl;
    }
    
    //rfind
    pos = str1.rfind("ld");
    if(pos == -1)
    {
        cout << "未查到所需字符串" << endl;
    }
    else 
    {
        cout << "找到字符串,pos = " << pos << endl;
    }
    
    //rfind与find之间的区别
    //rfind从右往左查找
    //find从左往右查
    string str2 = "abcdefjhem";
    pos = str2.find("e");
    if(pos == -1)
    {
        cout << "未查到所需字符串" << endl;
    }
    else 
    {
        cout << "找到字符串,pos = " << pos << endl;
    }
    
    pos = str2.rfind("e");
    if(pos == -1)
    {
        cout << "未查到所需字符串" << endl;
    }
    else 
    {
        cout << "找到字符串,pos = " << pos << endl;
    }
}
​
//替换
void test02()
{
    string str1 = "abcdefg";
    //从1号位置起 3个位置替换成1111
    str1.replace(1,3,"1111");//a1111efg
    cout << "str1 = " << str1 <<endl;
}
​
int main()
{
    test01();
    test02();
    return 0;
}

总结:rfind与find之间的区别,rfind从右往左查找,find从左往右查

6.string字符串比较

功能描述:

字符串之间的比较

比较方式:

字符串比较是按字符的ASCLL码进行对比

= 返回 0
> 返回 1
< 返回 -1

函数原型:

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

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

示例

#include<iostream>
#include<string>
using namespace std;
​
//string比较
void test01()
{
    string str1 = "xello";
    string str2 = "hello";
    int flag = str1.compare(str2);
    if(flag == 0)
    {
        cout << "str1 等于 str2" << endl;
    }
    else if(flag > 0)
    {
        cout << "str1 大于 str2" << endl;
    }
    else cout << "str1 小于 str2" << endl;
}
​
int main()
{
    test01();
    test02();
    return 0;
}

总计:字符串对比主要是用于比较两个字符串是否相等,判断谁大谁小意义不大

7.string字符串存取

string中单个字符存取方式有两种

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

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

示例

#include<iostream>
#include<string>
using namespace std;
​
//string字符存取
​
void test01()
{
    string str = "hello";
    
    //cout << "str = " << hello << endl;
    
    //1.通过[]访问单个字符
    for(int i = 0;i < str.size(); i++)
    {
        cout << str[i] << " ";
    }
    cout << endl;
    
    //2.通过at方式访问单个字符
    for(int i = 0;i < str.size(); i++)
    {
        cout << str.at(i) << " ";
    }
    cout << endl;
    
    //修改单个字符
    str[0] = 'x';
    cout << "str = " << endl;//xello
    
    str.at(1) = 'x';
    cout << "str = " << endl;//xxllo
}
​
int main()
{
    test01();
    return 0;
}

总结:string字符串单个字符存取有两种方式,利用[]或at

8.string插入和删除

功能描述:

对string字符串进行插入和删除字符操作

函数原型:

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个字符

示例

#include<iostream>
#include<string>
using namespace std;
​
//插入和删除字符串
void test01()
{
    string str = "hello";
    
    //插入
    str.insert(1,"1111");
    cout << "str = " << str << endl;//h1111ello
    
    string str2 = "wow";
    str.insert(1,str2);
    cout << "str = " << str << endl;//hwow1111ello
    
    //删除
    str.erase(1,3);
    cout << "str = " << str << endl;//h1111ello
    
}
​
int main()
{
    test01();
    return 0;
}

总结:插入和删除的起点下标都从0开始

9.string子串

功能描述:

从字符串中获取想要的子串

函数原型:

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

示例

#include<iostream>
#include<string>
using namespace std;
​
//求子串
void test01()
{
    string str = "abcdef";
    string subStr = str.substr(1,3);
    cout << "subStr = " << subStr << endl;
}
​
//使用操作
void test02()
{
    string email = "[email protected]";
    
    //从邮件地址中 获取 用户名的信息
    int pos = email.find("@");
    
    string userName = email.substr(0,pos-1);
    cout << "userName = " << userName << endl;
}
​
int main()
{
    test01();
    test02();
    return 0;
}

总结:灵活的运用求子串功能,可以在实际开发中获取有效的信息。

stack容器

1.栈的概念

概念:stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口。

 

能中只有顶端的元素才可以被外界使用,因此不允许有遍历行为。

栈不允许有遍历的行为,因为要遍历它的话,必须要把栈顶的元素全部取出才能读取到内部函数。

empty可以判断栈是否为空;

size可以返回栈内的元素个数;

栈中进入数据称为入栈——push 栈中弹出数据称为出栈——pop

2.stack常用接口

功能描述:栈容器常用的时外接口

构造函数 stack<T>stk; stack采用模板类实现,stack对象的默认构造形式

stack(const stack &stk);拷贝构造函数

赋值探作

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

数据存取

push(elem)向栈顶添加元素

pop();从栈顶移除第一个元素

top();返回栈顶元素

大小操作empty();判断堆栈是否为空

size();返回栈的大小

示例

#include<iostream>
#include<stack>
using namespace std;
​
//栈stack容器
​
void test01()
{
    //特点:复合先进后出数据结构
    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 << "出完栈的大小:" << s.size() << endl;
}
​
int main()
{
    test01();
    return 0;
}

queue容器

1.队列的基本概念

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

 

队列Queue符合先进先出,只能从队头和队尾被外界访问,因此不允许有遍历行为。

队列容器允许从一端新增元素,从另一端移除元素

队列中只有队头和队尾才可以被外界便用。因此队列不允许有遍历行为。

队列中进数据称为入队——push 队列中出数据称为出队——pop

2.queue常用接口

功能描述:队列容器常用的时外接口

构造函数

queue<T>que;queue采用模板类实现,queue对象的默认构造形式

queue(const queue &que);拷贝构造函数

赋值操作

queue& operator=(const queue &que);重载等号操作符

数据存取:

push(elem);往队尾添加元素

pop():从队头移除第一个元素

back();返回最后一个元素

front();返回第一个元素

大小操作

empty();判断队列是否为空

size();返回队列的大小

示例

#include<iostream>
#include<string>
#include<queue>
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;
};
​
//队列 Queue
void test01()
{
    //创建队列
    queue<Person>q;
    
    //准备数据
    Person p1("zhangsan",18);
    Person p2("Lisi",19);
    Person p3("wangwu",20);
    Person p4("zhaoliu",21);
    Person p5("tangqi",22);
    
    //入队
    q.push(p1);
    q.push(p2);
    q.push(p3);
    q.push(p4);
    q.push(p5);
    
    cout << "队列大小为:" << 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 << "检测出队后队列大小为:" << q.size() << endl;
}
​
int main()
{
    test01();
    return 0;
}

总结

入队——push

出队——pop

返回队头元素——front

返回队尾元素——back

判断队是否为空——empy

返回队列大小——size

List容器

1.Iist基本概念

功能:将数据进行范式存储

链表(s)是一种物理存储单元上非连续的存储结构,数据元素的逐辑顷序是通过整表中的指针连接实现的

链表的组成:链表由一系列结点组成

结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

STL中的链表是一个双向循环链表

链表的优点:链表很灵活,可以对任意位置进行快速的添加、插入、删除元素;采用的是动态存储分配,不会造成内存浪费和溢出;链表执行插入删除等操作十分方便,修改指针即可,无需移动大量元素。

链表的缺点:容器遍历速度没有数组快;占用时间、速度和空间比数组更长、更慢和更多

 

由于链表的存储方式并不是连续的内存空间,因此链表引list中的迭代器只支持前移和后移,属于双向迭代器

总结:STL中List和vector是两个最常被使用的容器,各有优缺点

2.List构造函数

功能描述

创建List容器

函数原型

list<T>lst;list采用采用模板类实现,对象的默认构造形式;

list(beg,end);构造函数将[beg,end)区间中的元素拷贝给本身;

list(n,elem);构造函数将n个elem拷贝给本身;

list(const list &lst);拷贝构造函数。

示例

#include<iostream>
#include<list>
using namespace std;
//list容器构造函数
​
void printList(const list<int>&L)
{
    for(list<int>::const_iterator it = L.begin();it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    //创建list容器
    list<int>L1;//默认构造
    
    //创建数据
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);
    
    printList(L1);
    
    //区间方式构造
    list<int>L2(L1.begin(), L1.end());
    printList(L2);
    
    //拷贝构造
    list<int>L3(L2);
    printList(L3);
    
    //n个elem
    list<int>L4(10, 100);
    printList(L4);
}
​
int main()
{
    test01();
    return 0;
}

3.list赋值和交换

功能描述

给list容器进行赋值,以及交换list容器

函数原型

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

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

list& operator=(const list &list);重载等号操作符

swap(lst);将lst与本身的元素互换.

示例

#include<iostream>
#include<list>
using namespace std;
//list容器赋值和交换
​
void printList(const list<int>& L)
{
    for(list<int>::const_iterator it = L.begin();it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//赋值
void test01()
{
    //创建容器
    list<int>L1;
    
    //添加元素
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);
    
    printList(L1);
    
    //区间赋值
    list<int>L2;
    L2.assign(L1.begin(), L1.end());
    printList(L2);
    
    //elem拷贝
    list<int>L3;
    L3.assign(10,100);
    printList(L3);
    
    //重载等号
    list<int>L4;
    L4 = L3;
    printList(L4);
    
}
​
//交换操作
void test02()
{
    list<int>L1;
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);
    cout << "交换前L1:" << endl;
    printList(L1);
    
    list<int>L2;
    L2.push_back(1);
    L2.push_back(2);
    L2.push_back(3);
    cout << "交换前L2:" << endl;
    printList(L2);
    
    swap(L1, L2);
    cout << "交换前L1:" << endl;
    printList(L1);
    cout << "交换前L2:" << endl;
    printList(L2);
}
​
int main()
{
    test01();
    test02();
    return 0;
}

4.list大小操作

功能描述

对is容器的大小进行操作

函数原型

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

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

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

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

示例

#include<iostream>
#include<list>
using namespace std;
​
//list大小操作
​
void printList(const list<int>& L)
{
    for(list<int>::const_iterator it = L.begin();it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    list<int>L1;
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);
    
    printList(L1);
    
    //判断是否为空
    if(L1.empty())
    {
        cout << "L1为空!" << endl;
    }
    else
    {
        cout << "L1不为空!" << endl;
        cout << "L1的元素个数为:" << L1.size() << endl;
    }
    
    //重新指定大小
    L1.resize(10);//L1.resize(10,1000);
    printList(L1);
    
    L1.resize(3);
    printList(L1);
}
​
int main()
{
    test01();
    return 0;
}

总结:

  1. 判断是否为空——empty

  2. 返回元素个数——size

  3. 重新指定个数——resize

4.list插入和删除

功能描述

对list容器进行数据的插入和删除

函数原型

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值匹配的元素

示例

#include<iostream>
#include<list>
using namespace std;
​
void printList(const list<int>& L)
{
    for(list<int>::const_iterator it = L.begin();it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    list<int>L;
    
    //尾插
    L.push_back(10);
    L.push_back(20);
    L.push_back(30);
    L.push_back(40);
    
    //头插
    L.push_front(4);
    L.push_front(3);
    L.push_front(2);
    L.push_front(1);
    
    //输出1 2 3 4 10 20 30 40
    printList(L);
    
    //删除
    L.erase(L.begin());
    printList(L);
    
    L.erase(++L.begin());
    printList(L);
    
    //移除
    L.push_back(1000);
    printList(L);
    L.remove(1000);
    printList(L);
    
    //清空
    L.clear();
    printList(L);
}
​
int main()
{
    test01();
    return 0;
}

总结

头插——push_back

尾删——pop_back

头插——push_front

头删——pop_front

插入——insert

删除——erase

移除——remove

清空——clear

5.list数据存取

功能描述

对list容器中数据进行存取

函数原型front();返回第一个元豪。

back();返回最后一个元素。

示例

#include<iostream>
#include<list>
using namespace std;
​
//list容器 数据存取
void test01()
{
    list<int>L;
    L.push_back(10);
    L.push_back(20);
    L.push_back(30);
    L.push_back(40);
    
    cout << "第一个元素:" << L.front() << endl;
    cout << "最后一个元素:" << L.back() << endl;
}
​
int main()
{
    test01();
    return 0;
}

6.list反转和排序

功能描述

将容器中的元素反转,以及将容器中的数据进行排序

函数原型

reverse();反转链表

sort();链表排序

示例

#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
​
//list容器反转和排序
void printList(const list<int>& L)
{
    for(list<int>::const_iterator it = L.begin();it != L.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
bool myCompare(int v1, int v2)
{
    //降序 就让第一个数 > 第二个数
    return v1 > v2;
}
​
void test01()
{
    //反转
    list<int>L1;
    L1.push_back(20);
    L1.push_back(10);
    L1.push_back(50);
    L1.push_back(40);
    L1.push_back(30);
    
    cout << "反转前:" << endl;
    printList(L1);
    
    //不是一个全局函数,而是一个成员函数
    L1.reverse();
    cout << "反转后:" << endl;
    printList(L1);
    
    //排序
    //所以不支持随机访问迭代器的容器,不可以用标准算法
    //不支持随机访问迭代器的容器,内部会提供一些对应的算法
    //sort(L1.begin(), L1.end());是不允许使用的
    
    L1.sort();//默认排序规则 从小到大 升序
    cout << "排序后:" << endl;
    printList(L1);
    
    L1.sort(myCompare);
    printList(L1);
}
​
int main()
{
    test01();
    return 0;
}

7.排序案例

案例描述

将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高 排序规则

按照年龄进行升序,如果年龄相同按照身高进行降序,如果身高年龄都一样,那么按照体重降序。

#include<iostream>
#include<string>
#include<list>
using namespace std;
​
//list容器 排序案例 对自定义数据类型 做排序
//按照年龄进行升序 如果年龄相同那么就按照身高进行降序
​
class Person
{
public:
    Person(string name, int age, double height, double weight)
    {
        this->m_Name = name;
        this->m_Age = age;
        this->m_Height = height;
        this->m_Weight = weight;
    }
    
    string m_Name;//姓名
    int m_Age;//年龄
    double m_Height;//身高
    double m_Weight;//体重
};
​
//指定排序规则
bool comparePerson(Person p1, Person p2)
{
    //按照年龄 升序
    if(p1.m_Age == p2.m_Age && p1.m_Height == p2.m_Height)
    {
        return p1.m_Weight > p2.m_Weight;
    }
    else if(p1.m_Age == p2.m_Age)
    {
        return p1.m_Height > p2.m_Height;
    }
    else
    {
        return p1.m_Age < p2.m_Age;
    }
}
​
//测试
void test01()
{
    //创建容器
    list<Person>L;
    
    //准备数据
    Person p1("zhangsan", 18, 160, 70);
    Person p2("lisi", 19, 162, 80);
    Person p3("wangwu", 20, 164, 50);
    Person p4("zhaoliu", 19, 162, 60);
    Person p5("tangqi", 21, 170, 65);
    Person p6("jiangba", 18, 170, 75);
    
    //插入数据
    L.push_back(p1);
    L.push_back(p2);
    L.push_back(p3);
    L.push_back(p4);
    L.push_back(p5);
    L.push_back(p6);
    
    for(list<Person>::iterator it = L.begin();it != L.end(); it++)
    {
        cout << "姓名:" << (*it).m_Name << " " << "年龄:" << " " << it->m_Age << " " << "身高" << it->m_Height << " " << "体重:" << it->m_Weight << endl;
    }
    
    //排序
    cout << "--------------------------------------" << endl;
    cout << "排序后:" << endl;
    L.sort(comparePerson);
    for(list<Person>::iterator it = L.begin();it != L.end(); it++)
    {
        cout << "姓名:" << (*it).m_Name << " " << "年龄:" << " " << it->m_Age << " " << "身高" << it->m_Height << " " << "体重:" << it->m_Weight << endl;
    }
}
​
int main()
{
    test01();
    return 0;
}

总结

  1. 对于自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序

  2. 高级排序只是在排序规则上再进行一次逻辑规则制定,并不复杂

set/multiset容器

1.set基本概念

简介

所有元素都会在插入时自动被排序

本质

set / multiset属于关联式容器,底层结构是用二叉树实现。

set和multiset区别

  1. set不允许容器中有重复的元素

  2. multiset允许容器中有重复的元素

头文件都是#include<set>

2.set构造和赋值

功能描述:创理set容器以及赋值

构造

set<T>st;默认构造函数;

set(const set &st);作拷贝构造函数

赋值

set&operator=(const set &st);重载等号操作符

示例

#include<iostream>
#include<set>
using namespace std;
​
//set容器构造和赋值
void printSet(set<int>&s)
{
    for(set<int>::iterator it = s.begin();it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    set<int>s1;
    
    //插入数据 只有insert方式
    s1.insert(10);
    s1.insert(40);
    s1.insert(20);
    s1.insert(40);
    s1.insert(30);
    s1.insert(50);
    s1.insert(30);
    
    //遍历容器
    //set容器的特点 所有元素插入的时候会自动被排序
    //set容器不允许插入重复值
    printSet(s1);
    
    //拷贝构造
    set<int>s2<s1>;
    printSet(s2);
    
    //赋值
    set<int>s3;
    s3 = s2;
    printSet(s3);
}
​
int main()
{
    test01();
    return 0;
}

3.set大小和交换

功能描述

统计set容器大小以及交换set容器

函数原型

size();返回容器中元素的数目

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

swap(st);交换两个集合容器

示例

#include<iostream>
#include<set>
using namespace std;
​
//set容器 大小和交换
​
//遍历
void printSet(set<int>& s)
{
    for(set<int>::iterator it = s.begin();it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
//大小
void test01()
{
    set<int>s1;
    
    //插入数据
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    s1.insert(40);
    s1.insert(50);
    
    printSet(s1);
    
    //判断是否为空
    if(s1.empty())
    {
        cout << "s1为空" << endl;
    }
    else
    {
        cout << "s1不为空" << endl;
        cout << "s1的大小为:" << s1.size() << endl;
    }
}
​
//交换
void test02()
{
     set<int>s1;
    
    //插入数据
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    s1.insert(40);
    s1.insert(50);
    
    set<int>s2;
    
    //插入数据
    s2.insert(100);
    s2.insert(200);
    s2.insert(300);
    s2.insert(400);
    s2.insert(500);
    
    cout << "交换前:" << endl;
    printSet(s1);
    printSet(s2);
    
    cout << "交换后:" << endl;
    s1.swap(s2);
    printSet(s1);
    printSet(s2);
}
​
int main()
{
    test01();
    test02();
    return 0;
}

4.set插入和删除

功能描述

set容器进行搭入数据和除数据

函数原型

insert(elem);在容器中插入元素

clear();清除所有元素

erase(pos);删除pos迭代器所指的元素,返回下一个元素的迭代器

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

erase(elem);删除容器中值为elem的元素。

示例

#include<iostream>
#include<set>
using namespace std;
​
//set容器 插入和删除
​
void printSet(set<int>s)
{
    for(set<int>::iterator it = s.begin();it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    set<int>s;
    
    //插入
    s.insert(10);
    s.insert(20);
    s.insert(30);
    s.insert(40);
    
    printSet(s);
    
    s.erase(s.begin());
    printSet(s);
    
    s.erase(++s.begin());
    printSet(s);
    
    s.erase(40);
    printSet(s);
    
    s.clear();
    printSet(s);
}
​
int main()
{
    test01();
    return 0;
}

5.set查找和统计

功能描述

对set容器进行直找数据以及统计数据

函数原型

find(key):查找key是否存在,若存在,返回该键的元素的迭代器:若不存在,返回set.end()

count(key)统计key的元素个数

示例

#include<iostream>
#include<set>
using namespace std;
​
//查找和统计
​
void test01()
{
    set<int>s;
    s.insert(10);
    s.insert(20);
    s.insert(30);
    s.insert(30);
    s.insert(30);
    s.insert(30);
    s.insert(40);
    
    //查找
    //查找
    //set<int>::iterator pos = s1.find(30);
    cout << *s.find(30) << endl;
    cout << *s.find(40) << endl;
    
    //统计
    cout << "值30的个数:" << s.count(30) << endl;
    cout << "值50的个数:" << s.count(50) << endl;
}
​
int main()
{
    test01();
    return 0;
}

6.set和multiset区别

学习目标

掌握set和multiset的区别

区别

  1. set不可以插入重复数据,而multiset可以

  2. set插入数据的同时会返回插入结果,表示插入是否成功

  3. multiset不会检测数据,因此可以插入重复数据

示例

#include<iostream>
#include<set>
using namespace std;
​
//set容器 和 multiset容器的区别
​
void printSet(multiset<int>s)
{
    for(multiset<int>::iterator it = s.begin();it != s.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
void test01()
{
    multiset<int>s;
    s.insert(10);
    s.insert(20);
    s.insert(30);
    s.insert(30);
    s.insert(40);
    s.insert(10);
    
    printSet(s);
}
​
int main()
{
    test01();
    return 0;
}

造成两者不同的结果的原因是,在源码部分存在有_Pairib

_Pairib:所以在insert()过后,如果插入成功,_Pairib的iterator会指向元素插入的位置,bool被置为true;否则,iterator指向重复的元素的位置,且bool为false.所以,“[]”重载函数可以通过insert()间接实现的。但在MS STL中,它没有采用这种方法,其内部虽也通过insert()间接实现,但其采用以map<T1,T2>::iterator为返回值的insert()版本。

详细解法利用对组

#include<iostream>
#include<set>
using namespace std;
​
void test()
{
    set<int>s;
    
    //对组
    pair<set<int>::iterator, bool> ret = s.insert(10);
    if(ret.second)
    {
        cout << "第一次插入成功!" << endl;
    }
    else
    {
        cout << "第一次插入失败!" << endl;
    }
    
    ret = s.insert(10);
    if(ret.second)
    {
        cout << "第二次插入成功!" << endl;
    }
    else
    {
        cout << "第二次插入失败!" << endl;
    }
}
​
int main()
{
    test();
    return 0;
}

总结

如果不允许插入重复数据可以利用set

如果需要插入重复改据利用multiset

7.pair对组创建

功能描述

成对出现的数据,利用对组可以返回两个数据

两种创建方式

pair<type,type>p(value1,value2);

pair<type,type>P = make_pair(valuel,value2);

示例

#include<iostream>
#include<string>
using namespace std;
​
//对组的建立
void test01()
{
    //第一种方式
    pair<string, int>p("Tom",12);
    cout << "姓名:" << p.first << " " << "年龄:" << p.second << endl;
    
    //第二种方式
    pair<string, int>p2 = make_pair("Jerry",10);
    cout << "姓名:" << p2.first << " " << "年龄:" << p2.second << endl;
}
​
int main()
{
    test01();
    return 0;
}

8.set容器排序

学习目标

set容器默认排序规则为从小到大,掌握如何改变排序规则

主要技术点

利用仿函数,可以改变排序规则

1.set存放内置数据类型

#include<iostream>
#include<set>
using namespace std;
​
//set容器排序
​
//仿函数改变排序规则
class MyCompare
{
public:
    bool operator()(int v1,int v2)
    {
        return v1 > v2;
    }
};
​
void test01()
{
    set<int>s1;
    
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    s1.insert(40);
    s1.insert(50);
    
    for(set<int>::iterator it = v.begin();it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    
    //指定排序规则从大到小
    set<int, MyCompare>s2;
    
    s2.insert(40);
    s2.insert(20);
    s2.insert(30);
    s2.insert(10);
    s2.insert(50);
    
    for(set<int,MyCompare>::iterator it = v.begin();it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
​
int main()
{
    test01();
    system("pause");
    return 0;
}

总结:利用仿函数可以指定set容器

2.set存放自定义数据类型

#include<iostream>
#include<set>
#include<string>
using namespace std;
​
//set容器排序 存放自定义数据类型
​
class Person
{
public:
    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    string m_Name;
    int m_Age;
};
​
class comparePerson
{
public:
    bool operator()(const Person&p1, const Person&p2)
    {
        //按照年龄 降序
        return p1.m_Age > p2.m_Age;
    }
};
​
void test01()
{
    set<Person, comparePerson>s;
    
    //创建Person对象
    Person p1("zhangsan",18);
    Person p2("lisi",19);
    Person p3("wangwu",20);
    Person p4("zhaoliu",21);
    
    s.insert(p1);
    s.insert(p2);
    s.insert(p3);
    s.insert(p4);
    
    //排序
    for(set<Person, comparePerson>::iterator it = s.begin();it != s.end(); it++)
    {
        cout << "姓名:" << it->m_Name << " " << "年龄:" << it->m_Age << endl;
    }
    cout << endl;
    
}
​
int main()
{
    test01();
    return 0;
}

map和multimap容器

1.map基本概念

简介

  1. map中所有元素都是pair

  2. pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)

  3. 所有元素都会根据元素的键值自动排序

本质

map/multimap属于关联式容器。底层结构是用二叉树实现.

优点

可以根据key值快速找到value值

map和multimapl区别:

  1. map不允许容器中有重复key值元素

  2. multimap允许容器中有重复key值元素

2.map构造和赋值

功能描述

对map容器进行构造和赋值操作

函数原型

构造map<T1,T2>mp;map默认构造函数:

map(const map &mp);拷贝构造函数

赋值

map&operator=(const map &mp);重载等号操作符

示例

#include<iostream>
#include<map>
using namespace std;
​
void printMap(map<int,int>&m)
{
    for(map<int, int>::iterator it = m.begin();it != m.end(); it++)
    {
        cout << "key = " << (*it).first << " value = " << it->second << endl;
    }
}
​
//map容器 构造和赋值
void test01()
{
    //创建map容器
    map<int, int> m;
    
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(3, 30));
    m.insert(pair<int, int>(4, 40));
    
    printMap(m);
    
    //拷贝构造
    map<int, int>m2(m);
    printMap(m2);
    
    //赋值
    map<int, int>m3;
    m3 = m2;
}
​
int main()
{
    test01();
    return 0;
}

3.map大小和交换

功能描述

统计map客品大小以及交换map容器

函数原型

size();返回容器中元素的数目

empty();条件判新容器是否为空

swap(st);交换两个集合容器

#include<iostream>
#include<map>
using namespace std;
​
void printMap(map<int,int>&m)
{
    for(map<int, int>::iterator it = m.begin();it != m.end(); it++)
    {
        cout << "key = " << (*it).first << " value = " << it->second << endl;
    }
}
​
//map容器 构造和赋值
void test01()
{
    //创建map容器
    map<int, int> m;
    
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(3, 30));
    m.insert(pair<int, int>(4, 40));
    
    printMap(m);
    
    //判断容器是否为空
    if(m.empty())
    {
        cout << "map为空!" << endl;
    }
    else
    {
        cout << "map不为空!" << endl;
        cout << "map大小:" << m.size() << endl;
    }
}
​
//交换
void test02()
{
    map<int, int> m1;
    
    m1.insert(pair<int, int>(1, 10));
    m1.insert(pair<int, int>(2, 20));
    m1.insert(pair<int, int>(3, 30));
    m1.insert(pair<int, int>(4, 40));
    
    map<int, int> m2;
    
    m2.insert(pair<int, int>(5, 100));
    m2.insert(pair<int, int>(6, 200));
    m2.insert(pair<int, int>(7, 300));
    m2.insert(pair<int, int>(8, 400));
    
    cout << "交换前:" << endl;
    cout << "map1:" << endl;
    printMap(m1);
    cout << "map2:" << endl;
    printMap(m2);
    
    m2.swap(m1);
    cout << "交换后:" << endl;
    cout << "map1:" << endl;
    printMap(m1);
    cout << "map2:" << endl;
    printMap(m2);
}
​
int main()
{
    test01();
    test02();
    return 0;
}

4.map插入和删除

功能描述

map容进行插入数据和别除数据

函数原型

insert(elem);在容器中插入元素。

clear();清除所有元素

erase(pos);删除pos迭代器所指的元素,返回下一个元素的迭代器

erase(beg, end);删除区间[beg.end的所有元素,返回下一个元素的迭代器

erase(key);删除容器中值为key的元素

示例

#include<iostream>
#include<map>
using namespace std;
​
//map容器 插入和删除
void printMap(map<int,int>&m)
{
    for(map<int,int>::iterator it = m.begin();it != m.end(); it++)
    {
        cout << "key = " << it->first << " value = " << it->second << endl;
    }
}
​
void test01()
{
    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;
    //存在弊端,系统会帮助插入,不建议插入
    cout << m[5] << endl;
    
    printMap(m);
    
    //删除
    m.erase(m.begin());
    printMap(m);
    
    //按照key删除
    m.erase(3);
    printMap(m);
    
    m.erase(m.begin(),m.end());
    printMap(m);
}
​
int main()
{
    test01();
    return 0;
}

5.map查找和统计

功能描述

对map容器进行查找数据以及统计数据

函数原型

find(key);查找key是否存在,若存在,返回该键的元素的迭代器:若不存在,返回set.end();

count(key);统计key的元素个数

示例

#include<iostream>
#include<map>
using namespace std;
​
//map容器 查找和统计
void test01()
{
    //查找
    map<int, int> m1;
    
    m1.insert(pair<int, int>(1, 10));
    m1.insert(pair<int, int>(2, 20));
    m1.insert(pair<int, int>(3, 30));
    m1.insert(pair<int, int>(3, 50));
    m1.insert(pair<int, int>(4, 40));
    
    map<int, int>::iterator pos = m.find(3);
    
    if(pos != m.end())
    {
        cout << "查找到了元素 key = " << (*pos).first << " value = " << pos->second << endl;
    }
    else
    {
        cout << "未找到元素" << endl;
    }
    
    //统计
    //map不允许插入重复的key元素,count统计而言 结果要么是0,要么是1
    //multimap的count统计则允许
    int num = m.count(3);
    cout << "num = " << num << endl;
}
​
int main()
{
    test01();
    return 0;
}

6.map容器排序

学习目标

map容器默认排序规则为按照key值进行从小到大排序,掌握如何改变排序规则

主要技术点

利用仿函数,可以改变排序规则

示例

#include<iostream>
#include<map>
using namespace std;
​
class MyCompare
{
public:
    bool operator()(int v1,int v2)
    {
        //降序
        return v1 > v2;
    }
};
    
​
//map容器 排序
void test01()
{
    map<int, int, MyCompare> m1;
    
    m1.insert(pair<int, int>(1, 10));
    m1.insert(pair<int, int>(2, 20));
    m1.insert(pair<int, int>(3, 30));
    m1.insert(pair<int, int>(3, 50));
    m1.insert(pair<int, int>(4, 40));
    
    for(map<int,int,MyCompare>::iterator it = m1.begin();it != m1.end(); it++)
    {
        cout << "key = " << it->first << " value = " << it->second << endl;
    }
}
​
int main()
{
    test01();
    return 0;
}

评委打分案例

1.案例描述

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

2.实现步骤

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

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

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

  4. deque容器遍历一遍,累加总分

  5. 获取平均分

3.代码实现

#include<iostream>
#include<string>
#include<vector>
#include<deque>
#include<algorithm>
using namespace std;
​
//评委打分案例
/*
有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
*/
class Person
{
public:
    Person(string name, double score)
    {
        this->m_Name = name;
        this->m_Score = score;
    }
    
    string m_Name;//姓名
    double m_Score;//平均分
};
​
void createPerson(vector<Person>&v)
{
    string nameSeed = "ABCDE";
    for(int i = 0;i < 5; i++)
    {
        string name = "选手";
        name += nameSeed[i];
        
        double score = 0;
        
        Person p(name, score);
        
        //将创建的person对象 放入到容器中
        v.push_back(p);
    }
}
​
//打分
void serSore(vector<Person>&v)
{
    for(vector<Person>::iterator it = v.begin();it != v.end(); it++)
    {
        //将评委的分数 放入deque容器中
        deque<double>d;
        for(int i = 0;i < 10; i++)
        {
            double score = rand() % 41 + 60;//60 ~ 100
            d.push_back(score);
        }
        
        cout << "选手:" << it->m_Name << "  " << "打分:" << endl;
        for(deque<double>::iterator dit = d.begin();dit != d.end(); dit++)
        {
            cout << *dit << " ";
        }
        cout << endl;
        
        //排序
        sort(d.begin(), d.end());
        
        //去掉最高分和最低分
        d.pop_back();
        d.pop_front();
        
        //取平均分
        double sum = 0;
        for(deque<double>::iterator dit = d.begin();dit != d.end(); dit++)
        {
            sum += *dit;//累加每个评委的分数
        }
        
        double avg = sum / d.size();
        
        //将平均分 赋值给选手
        it->m_Score = avg;
    }
}
​
//打印结果
void showScore(vector<Person>&v)
{
    for(vector<Person>::iterator it = v.begin();it != v.end(); it++)
    {
        cout << "姓名:" << it->m_Name << " " << "平均分:" << it->m_Score << endl;
    }
}
​
int main()
{
    //创建5名选手
    vector<Person>v;//存放选手容器
    createPerson(v);
    
    //测试
    //for(vector<Person>::iterator it = v.begin();it != v.end(); it++)
    //{
        //cout << (*it).m_Name << " " << (*it).m_Score << endl;
    //}
    
    
    //给5名选手打分
    serSore(v);
    
    cout << endl;
    //显示最后得分
    showScore(v);
    
    return 0;
}

今天的分享到这里就结束啦,STL标准库还是得靠练习才能巩固、掌握和灵活使用。种类很多,但是具体的调用方法则是大同小异,很多情况下就是属于掌握了一个,就能推出其他的使用情况,区别的地方记牢、会用即可!!!

兄弟萌,加油啊!!!!!

猜你喜欢

转载自blog.csdn.net/Williamtym/article/details/129610835