首页 > 技术文章 > STL容器

chendeqiang 2020-05-11 06:40 原文

顺序容器:是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集。顺序性容器中的每个元素均有固定的位置,除非用删除或插入的操作改变这个位置。顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定。

顺序容器包括:vector(向量)、list(列表)、deque(队列)。

容器类自动申请和释放内存,因此无需new和delete操作。

vector

vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。
vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,
简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。
使用vector,必须在你的头文件中包含下面的代码:

#include <vector>

属于std命名域的,因此需要通过命名限定,如下完成你的代码:

using std::vector;
vector vInts;
或者连在一起,使用全名
std::vector vInts;

初始化

vector                 // 创建一个空的vector。
vector c1(c2)          // 复制一个vector
vector c(n)            // 创建一个vector,含有n个数据,数据均已缺省构造产生
vector c(n, elem)      // 创建一个含有n个elem拷贝的vector
vector c(beg,end)      // 创建一个含有n个elem拷贝的vector

析构函数

c.~vector ()           // 销毁所有数据,释放内存

成员函数

c.begin()          // 传回迭代器中的第一个数据地址。
c.end()            // 指向迭代器中末端元素的下一个,指向一个不存在元素。
c.push_back(elem)  // 在尾部加入一个数据。
c.clear()          // 移除容器中所有数据。
c.empty()          // 判断容器是否为空。
c.size()           // 返回容器中实际数据的个数。
c1.swap(c2)        // 将c1和c2元素互换。
swap(c1,c2)        // 将c1和c2元素互换。同上操作。
c.capacity()       // 返回容器中数据个数。
operator[]         // 返回容器中指定位置的一个引用。
c.max_size()       // 返回容器中最大数据的数量。
----------------------------------------------------------------------------------------
c.front()             // 传回第一个数据。
c.back()              // 传回最后一个数据,不检查这个数据是否存在。
c.assign(beg,end)c.assign(n,elem)//将[beg; end)区间中的数据赋值给c。将n个elem的拷贝赋值给c。
c.at(idx)             //传回索引idx所指的数据,如果idx越界,抛出out_of_range。
c.erase(pos)          // 删除pos位置的数据,传回下一个数据的位置。
c.erase(beg,end)      //删除[beg,end)区间的数据,传回下一个数据的位置。
get_allocator         // 使用构造函数返回一个拷贝。
c.insert(pos,elem)    // 在pos位置插入一个elem拷贝,传回新数据位置。
c.insert(pos,n,elem)  // 在pos位置插入n个elem数据。无返回值。
c.insert(pos,beg,end) // 在pos位置插入在[beg,end)区间的数据。无返回值。 
c.pop_back()          // 删除最后一个数据。
c.rbegin()            // 传回一个逆向队列的第一个数据。
c.rend()              // 传回一个逆向队列的最后一个数据的下一个位置。
c.resize(num)         // 重新指定队列的长度。
c.reserve()           // 保留适当的容量。

list

List定义

List是stl实现的双向链表,与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢。使用时需要添加头文件

#include <list>

List初始化

list<int>lst1;                           //创建空list
list<int> lst2(5);                       //创建含有5个元素的list
list<int>lst3(3,2);                      //创建含有3个元素的list
list<int>lst4(lst2);                     //使用lst2初始化lst4
list<int>lst5(lst2.begin(),lst2.end());  //同lst4

List常用操作函数

Lst1.push_back()      //在list的末尾添加一个元素 
Lst1.push_front()     //在list的头部添加一个元素 
Lst1.clear()          //删除所有元素 
----------------------------------------------------
Lst1.assign()         //给list赋值 
Lst1.back()           //返回最后一个元素 
Lst1.begin()          //返回指向第一个元素的迭代器 
Lst1.empty()          //如果list是空的则返回true 
Lst1.end()            //返回末尾的迭代器 
Lst1.erase()          //删除一个元素 
Lst1.front()          //返回第一个元素 
Lst1.get_allocator()  //返回list的配置器 
Lst1.insert()         //插入一个元素到list中 
Lst1.max_size()       //返回list能容纳的最大元素数量 
Lst1.merge()          //合并两个list 
Lst1.pop_back()       //删除最后一个元素 
Lst1.pop_front()      //删除第一个元素 
Lst1.rbegin()         //返回指向第一个元素的逆向迭代器 
Lst1.remove()         //从list删除元素 
Lst1.remove_if()      //按指定条件删除元素 
Lst1.rend()           //指向list末尾的逆向迭代器 
Lst1.resize()         //改变list的大小 
Lst1.reverse()        //把list的元素倒转 
Lst1.size()           //返回list中的元素个数 
Lst1.sort()           //给list排序 
Lst1.splice()         //合并两个list 
Lst1.swap()           //交换两个list 
Lst1.unique()         //删除list中重复的元素

deque

#include <deque>

deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是,deque还支持从开始端插入数据:push_front()。其余类似vector操作方法的使用。

顺序容器通用方法

添加元素

c.push_back(t)  	//在容器c的尾部添加值为t的元素。返回void 类型
c.push_front(t) 	//在容器c的前端添加值为t的元素。返回void 类型只适用于list和deque容器类型。
c.insert(p,t)   	//在迭代器p所指向的元素前面插入值为t的新元素。返回指向新添加元素的迭代器。
c.insert(p,n,t) 	//在迭代器p所指向的元素前面插入n个值为t的新元素。返回void 类型
c.insert(p,b,e) 	//在迭代器p所指向的元素前面插入由迭代器b和e标记的范围内的元素。返回 void 类型

容器大小操作

c.size()       //返回容器c中元素个数。返回类型为 c::size_type
c.max_size()   //返回容器c可容纳的最多元素个数,返回类型为c::size_type
c.empty()      //返回标记容器大小是否为0的布尔值
c.resize(n)    //调整容器c的长度大小,使其能容纳n个元素,如果n<c.size(),则删除多出来的元素。
c.resize(n,t)  //调整容器c的长度大小,使其能容纳n个元素。所有新添加的元素值都为t

访问元素

c.back()        //返回容器 c 的最后一个元素的引用。如果 c 为空,则该操作未定义
c.front()       //返回容器 c 的第一个元素的引用。如果 c 为空,则该操作未定义
c[n]            //返回下标为 n 的元素的引用。如果下标越界,则该操作未定义只适用于 vector 和 deque 容器
c.at(n)         //返回下标为 n 的元素的引用。如果下标越界,则该操作未定义只适用于 vector 和 deque 容器

删除元素

c.erase(p)    //删除迭代器p所指向的元素。返回一个迭代器,它指向被删除元素后面的元素。
c.erase(b,e)  //删除迭代器b和e所标记的范围内所有的元素。返回一个迭代器,它指向被删除元素段后面的元素。
c.clear()     //删除容器c内的所有元素。返回void。
c.pop_back()  //删除容器c的最后一个元素。返回void。如果c为空容器,则该函数未定义。
c.pop_front() //删除容器c的第一个元素。返回void。如果c为空容器,则该函数未定义只适用于list或deque容器。

赋值和交换

c1 = c2   //删除容器c1的所有元素,然后将c2的元素复制给c1。c1和c2的类型(包括容器类型和元素类型)必须相同
c1.swap   //(c2)交换c1和c2的内容,比赋值操作速度快。
c.assign  //(b,e)将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器
c.assign  //(n,t)将容器c重新设置为存储n个值为t的元素

关联式容器是非线性的树结构,更准确的说是二叉树结构。各元素之间没有严格的物理上的顺序关系,也就是说元素在容器中并没有保存元素置入容器时的逻辑顺序。但是关联式容器提供了另一种根据元素特点排序的功能,这样迭代器就能根据元素的特点“顺序地”获取元素。元素是有序的集合,默认在插入的时候按升序排列。

关联容器包括:map(集合)、set(映射)、multimap(多重集合)、multiset(多重映射)。

map

map容器提供一个键值对(key/value)容器,map与multimap差别仅仅在于multiple允许一个键对应多个值。对于迭代器来说,可以修改实值,而不能修改key。Map会根据key自动排序。
map 是键-值对的集合。map 类型通常可理解为关联数组:可使用键作为下标来获取一个值,正如内置数组类型一样。而关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在数组中的位置来获取。

初始化

#include <map>
map<k, v>m        //创建一个名为m的空map对象,其键和值的类型分别为k和v
map<k, v>m(m2)    //创建m2的副本m,m与m2必须有相同的键类型和值类型
map<k, v>m(b, e)  //创建map类型的对象m,存储迭代器b和e标记的范围内所有元素的副本,
                  //元素的类型必须能转换为pair<const k, v>。

在使用关联容器时,它的键不但有一个类型,而且还有一个相关的比较函数。所用的比较函数必须在键类型上定义严格弱排序(strict weak ordering):可理解为键类型数据上的“小于”关系,虽然实际上可以选择将比较函数设计得更复杂。对于键类型,唯一的约束就是必须支持 < 操作符,至于是否支持其他的关系或相等运算,则不作要求。

方法

添加元素有两种方法:1、先用下标操作符获取元素,然后给获取的元素赋值 2、使用insert成员函数实现
下标操作添加元素:如果该键已在容器中,则 map 的下标运算与 vector 的下标运算行为相同:返回该键所关联的值。只有在所查找的键不存在时,map 容器才为该键创建一个新的元素,并将它插入到此 map 对象中。此时,所关联的值采用值初始化:类类型的元素用默认构造函数初始化,而内置类型的元素初始化为 0。

m insert(e)    //e是一个用在m上的value_type 类型的值。如果键(e first不在m中,则插入一个值为e second 
               //的新元素;如果该键在m中已存在,则保持m不变。该函数返回一个pair类型对象,包含指向键为
               //e first的元素的map迭代器,以及一个 bool 类型的对象,表示是否插入了该元素
-------------------------------------------------------------------------------------------
m insert(beg,end)//beg和end是标记元素范围的迭代器,其中的元素必须为m value_type 类型的键-值对。对于
                 //该范围内的所有元素,如果它的键在m中不存在,则将该键及其关联的值插入到m。返回void类型
-------------------------------------------------------------------------------------------
m insert(iter,e)//e是一个用在m上的 value_type 类型的值。如果键(e first)不在m中,则创建新元素,并以
                //迭代器iter为起点搜索新元素存储的位置。返回一个迭代器,指向m中具有给定键的元素

遍历

map中使用下标存在一个很危险的副作用:如果该键不在 map 容器中,那么下标操作会插入一个具有该键的新元素。所以map 容器提供了两个操作:count 和 find,用于检查某个键是否存在而不会插入该键。

m count(k)   //返回 m 中 k 的出现次数
m find(k)    //如果m容器中存在按k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器。

删除

m erase(k)      //删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数
m erase(p)      //删除p所指向的元素。p必须指向m中确实存在的元素,而且不能等于m end()。返回void
m erase(b,e)    //从m中删除一段范围内的元素,该范围由迭代器对b和e标记。b和e必须标记m中的一段有效范围:即b和e都必须指向m中的元素或最后一个元素的下一个位置。而且,b和e要么相等(此时删除的范围为空),要么b所指向的元素必须出在e所指向的元素之前。返回 void 类型

set

set的含义是集合,它是一个有序的容器,里面的元素都是排序好的,支持插入,删除,查找等操作,就像一个集合一样。所有的操作的都是严格在logn时间之内完成,效率非常高。set和multiset的区别是:set插入的元素不能相同,但是multiset可以相同。Set默认自动排序。使用方法类似list。

begin()              //返回指向第一个元素的迭代器
clear()              //清除所有元素
count()              //返回某个值元素的个数
empty()              //如果集合为空,返回true
end()                //返回指向最后一个元素的迭代器
equal_range()        //返回集合中与给定值相等的上下限的两个迭代器
erase()              //删除集合中的元素
find()               //返回一个指向被查找到元素的迭代器
get_allocator()      //返回集合的分配器
insert()             //在集合中插入元素
lower_bound()        //返回指向大于(或等于)某值的第一个元素的迭代器
key_comp()           //返回一个用于元素间值比较的函数
max_size()           //返回集合能容纳的元素的最大限值
rbegin()             //返回指向集合中最后一个元素的反向迭代器
rend()               //返回指向集合中第一个元素的反向迭代器
size()               //集合中元素的数目
swap()               //交换两个集合变量
upper_bound()        //返回大于某个值元素的迭代器
value_comp()         //返回一个用于比较元素间的值的函数

举个栗子:

#include<set>
#include<iostream>
using namespace std;
int main()
{
    int i;
    int arr[5] = {0,1,2,3,4};
    set<int> iset(arr,arr+5);

    iset insert(5);
    cout<<"size:"<<iset size()<<endl;
    cout<<"3 count = "<<iset count(3)<<endl;
    iset erase(1);

    set<int>::iterator ite1 = iset begin();
    set<int>::iterator ite2 = iset end();
    for(;ite1!=ite2;ite1++)
    {
        cout<<*ite1;
    }
    cout<<endl;

    ite1 = iset find(3);
    if(ite1!=iset end())
        cout<<"3 found"<<endl;

    ite1 = iset find(1);
    if(ite1!=iset end())
        cout<<"1 not found"<<endl;
}

参考链接:
https://www.jianshu.com/p/fe909c102c08
https://www.jb51.net/article/115201.htm
https://blog.csdn.net/u014465639/article/details/70241850

推荐阅读