STL中容器的使用全面总结

STL- 常用容器 一、string容器1、string基本概念本质:string是C++风格的字符串,而string本质上是一个类string和char * 区别:char * 是一个指针string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器。特点:string 类内部封装了很多成员方法例如:查找find,拷贝copy,删除delete 替换replace,插入insertstring管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责。 阅读详情
一、容器的定义

       在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对像的指针,这种对象类型就叫做容器。很简单,容器就是保存其它对象的对象,当然这是一个朴素的理解,这种“对象”还包含了一系列处理“其它对象”的方法。

二、容器的种类

  1、顺序容器:是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集。顺序性容器中的每个元素均有固定的位置,除非用删除或插入的操作改变这个位置。顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定。顺序容器包括:vector(向量)、list(列表)、deque(队列)。
  2、关联容器:关联式容器是非线性的树结构,更准确的说是二叉树结构。各元素之间没有严格的物理上的顺序关系,也就是说元素在容器中并没有保存元素置入容器时的逻辑顺序。但是关联式容器提供了另一种根据元素特点排序的功能,这样迭代器就能根据元素的特点“顺序地”获取元素。元素是有序的集合,默认在插入的时候按升序排列。关联容器包括:map(集合)、set(映射)、multimap(多重集合)、multiset(多重映射)。
  3、容器适配器:本质上,适配器是使一种不同的行为类似于另一事物的行为的一种机制。容器适配器让一种已存在的容器类型采用另一种不同的抽象类型的工作方式实现。适配器是容器的接口,它本身不能直接保存元素,它保存元素的机制是调用另一种顺序容器去实现,即可以把适配器看作“它保存一个容器,这个容器再保存所有元素”。STL 中包含三种适配器:栈stack 、队列queue 和优先级队列priority_queue 。

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

三、不同容器的使用方法

  1、vector(需要导入头文件#include <vector>)

       ①定义与初始化

            如果没有指定元素的初始化式,那么标准库将自行提供一个元素初始值进行,具体值为何,取决于存储在vector 中元素的数据类型;如果为int型数据,那么标准库将用 0 值创建元素初始化式;如果 vector 保存的是含有构造函数的类类型(如 string)的元素,标准库将用该类型的默认构造函数创建元素初始化式;元素类型可能是没有定义任何构造函数的类类型。这种情况下,标准库仍产生一个带初始值的对象,这个对象的每个成员进行了值初始化。

         vector<int> vec1;    //默认初始化,vec1为空

         vector<int> vec2(vec1);  //使用vec1初始化vec2

         vector<int> vec3(vec1.begin(),vec1.end());//使用vec1初始化vec2

         vector<int> vec4(10);    //10个值为0的元素

         vector<int> vec5(10,4);  //10个值为4的元素

         vector<string> vec6(10,"null");    //10个值为null的元素

         vector<string> vec7(10,"hello");  //10个值为hello的元素


      ②常用的操作方法

           

    vec1.push_back(100);            //添加元素

    int size = vec1.size();         //元素个数

    bool isEmpty = vec1.empty();    //判断是否为空

    cout<<vec1[0]<<endl;        //取得第一个元素

    vec1.insert(vec1.end(),5,3);    //从vec1.back位置插入5个值为3的元素

    vec1.pop_back();              //删除末尾元素

    vec1.erase(vec1.begin(),vec1.end());//删除之间的元素,其他元素前移

    cout<<(vec1==vec2)?true:false;  //判断是否相等==、!=、>=、<=...

    vector<int>::iterator iter = vec1.begin();    //获取迭代器首地址

    vector<int>::const_iterator c_iter = vec1.begin();   //获取const类型迭代器

    vec1.clear();                 //清空元素


③遍历方法

// 下标法(vector的特有访问方法,一般容器只能通过迭代器访问)
     int  length = vec1.size();
     for ( int  i=0;i<length;i++)
    {
       cout<<vec1[i];
    }
    cout<<endl<<endl;
     // 迭代器法
    vector< int >::const_iterator iterator = vec1.begin();
     for (;iterator != vec1.end();iterator++)
    {

       cout<<*iterator;

    }

  2、list(需要导入头文件#include <list>)

       ①定义与初始化

 

    list<int> lst1;          //创建空list

    list<int> lst2(3);       //创建含有三个元素的list

    list<int> lst3(3,2); //创建含有三个元素的值为2的list

    list<int> lst4(lst2);    //使用lst2初始化lst4

    list<int> lst5(lst2.begin(),lst2.end());  //同lst4

       ②常用的操作方法

    lst1.assign(lst2.begin(),lst2.end());  //分配值

    lst1.push_back(10);                    //添加值

    lst1.pop_back();                   //删除末尾值

    lst1.begin();                      //返回首值的迭代器

    lst1.end();                            //返回尾值的迭代器

    lst1.clear();                      //清空值

    bool isEmpty1 = lst1.empty();          //判断为空

    lst1.erase(lst1.begin(),lst1.end());                        //删除元素

    lst1.front();                      //返回第一个元素的引用

    lst1.back();                       //返回最后一个元素的引用

    lst1.insert(lst1.begin(),3,2);         //从指定位置插入3个值为2的元素

    lst1.rbegin();                         //返回第一个元素的前向指针

    lst1.remove(2);                        //相同的元素全部删除

    lst1.reverse();                        //反转

    lst1.size();                       //含有元素个数

    lst1.sort();                       //排序

    lst1.unique();                         //删除相邻重复元素

       ③遍历方法

    //迭代器法

    for(list<int>::const_iterator iter = lst1.begin();iter != lst1.end();iter++)

    {

       cout<<*iter;

    }

    cout<<endl;

  3、deque(需要导入头文件#include <deque>)

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

 4、顺序容器使用方法小结(操作的共同点)

       ①添加元素

函数名意义
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 类型

//在容器首部或者尾部添加数据

list<int> ilist;

ilist.push_back(ix);//尾部添加

ilist.push_front(ix);//首部添加

//在容器中指定位置添加元素

list<string> lst;

list<string>::iterator iter = lst.begin();

while (cin >> word)

iter = lst.insert(iter, word); // 和push_front意义一样

//插入一段元素

list<string> slist;

string sarray[4] = {"quasi", "simba", "frollo", "scar"};

slist.insert(slist.end(), 10, "A");//尾部前添加十个元素都是A

list<string>::iterator slist_iter = slist.begin();

slist.insert(slist_iter, sarray+2, sarray+4);//指针范围添加

②容器大小的操作

函数名意义
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


list<int> ilist(10, 1);

ilist.resize(15); // 尾部添加五个元素,值都为0

ilist.resize(25, -1); // 再在尾部添加十个元素,元素为-1

ilist.resize(5); // 从尾部删除20个元素

③访问元素

函数名意义
c.back()

返回容器 c 的最后一个元素的引用。如果 c 为空,则该操作未定

义

c.front()返回容器 c 的第一个元素的引用。如果 c 为空,则该操作未定义
c[n]

返回下标为 n 的元素的引用。如果 n <0 或 n >= c.size(),则该操作未定义

只适用于 vector 和 deque 容器

c.at(n)

返回下标为 n 的元素的引用。如果下标越界,则该操作未定义

只适用于 vector 和 deque 容器


vector<int> vi;

for(int i=0;i<10;i++)vi.push_back(i);

cout<<vi[0]<<endl;

cout<<vi.at(0)<<endl;

cout<<vi[10]<<endl; //越界错误

cout<<vi.at(10)<<endl;//越界错误

④ 删除元素
函数名意义
c.erase(p)

删除迭代器p所指向的元素。返回一个迭代器,它指向被删除元素后面的元素。如果p指向容器内的最后一个元素,则返回的迭代器指向容器超出末端的下一位置。如果p本身就是指向超出末端的下一位置的迭代器,则该函数未定义

c.erase(b,e)

删除迭代器b和e所标记的范围内所有的元素。返回一个迭代器,它指向被删除元素段后面的元素。如果e本身就是指向超出末端的下一位置的迭代器,则返回的迭代器也指向容器的超出末端的下一位置

c.clear()删除容器c内的所有元素。返回void
c.pop_back()

删除容器c的最后一个元素。返回void。如果c为空容器,则该函数未定义

c.pop_front()

删除容器c的第一个元素。返回void。如果c为空容器,则该函数未定义

只适用于 list 或 deque 容器


//删除第一个或最后一个元素

list<int> li;

for(int i=0;i<10;i++)list.push_back(i);

li.pop_front();//删除第一个元素

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

//删除容器内的一个元素

list<int>::iterator iter =li.begin();

if(iter!= li.end())li.erase(iter);

//删除容器内所有元素

li.clear();


⑤赋值与swap

函数名

意义

c1 = c2

删除容器c1的所有元素,然后将c2的元素复制给c1。c1和c2的类型(包括容器类型和元素类型)必须相同

c1.swap(c2)

交换内容:调用完该函数后,c1中存放的是 c2 原来的元素,c2中存放的则是c1原来的元素。c1和c2的类型必须相同。该函数的执行速度通常要比将c2复制到c1的操作快

c.assign(b,e)

重新设置c的元素:将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器

c.assign(n,t)将容器c重新设置为存储n个值为t的元素

list<string> sl1,sl2;

for(int i=0;i<10;i++)sl2.push_back("a");

sl1.assign(sl2.begin(),sl2.end());//用sl2的指针范围赋值,sl1中十个元素都为a

sl1.assign(10, "A"); //s1被重新赋值,拥有十个元素,都为A


vector<string> vs1(3);  // vs1有3个元素
vector<string> vs(5);  // vs2有5个元素
vs1.swap(vs2);//执行后,vs1中5个元素,而vs2则存3个元素。


  5、map(需要导入头文件#include <map>)

       C++中map容器提供一个键值对(key/value)容器,map与multimap差别仅仅在于multiple允许一个键对应多个值。对于迭代器来说,可以修改实值,而不能修改key。Map会根据key自动排序。

        map 是键-值对的集合。map 类型通常可理解为关联数组:可使用键作为下标来获取一个值,正如内置数组类型一样。而关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在数组中的位置来获取。

       ①定义与初始化

          map<int,string> map1;                  //空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。

insert 操作:

函数名意义
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中具有给定键的元素


    例1:

word_count.insert(map<string,  int >::value_type( "Anna" , 1));
word_count.insert(make_pair( "Anna" , 2));//返回false,且键值仍为1.
word_count["Anna"] = 2;//键值变为2
   insert的返回值:包含一个迭代器和一个bool值的pair对象,其中迭代器指向map中具有相应键的元素,
而bool值则表示是否插入了该元素。 如果该键已在容器中,则其关联的值保持不变,返回的bool值为false。
在这两种情况下,迭代器都将指向具有给定键的元素。

例2:
pair<map<string,  int >::iterator,  bool > ret =
word_count.insert(make_pair(word, 1));

    ret存储insert函数返回的pair对象。该pair的first成员是一个map迭代器,指向插入的键。
ret.first从insert返回的pair对象中获取 map 迭代器;ret.second从insert返回是否插入了该元素。

例3:

    map1[3] = "Saniya";                    //添加元素

    map1.insert(map<int,string>::value_type(2,"Diyabi"));//插入元素

    map1.insert(pair<int,string>(1,"Siqinsini"));

    map1.insert(make_pair<int,string>(4,"V5"));

    string str = map1[3];                  //根据key取得value,key不能修改

    map<int,string>::iterator iter_map = map1.begin();//取得迭代器首地址

    int key = iter_map->first;             //取得key

    string value = iter_map->second;       //取得value

    map1.erase(iter_map);                  //删除迭代器数据

    map1.erase(3);                         //根据key删除value

    map1.size();                       //元素个数

    map1.empty();                       //判断空

    map1.clear();                      //清空所有元素

③遍历

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

函数名意义
m.count(k)

返回 m 中 k 的出现次数

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

        例1:

int occurs = 0;
if (word_count.count("foobar"))occurs = word_count["foobar"];
map<string,int>::iterator it = word_count.find("foobar");
if (it != word_count.end())occurs = it->second;

   例2:

for(map<int,string>::iterator iter = map1.begin();iter!=map1.end();iter++)

    {

       int keyk = iter->first;

       string valuev = iter->second;

    }

④从map对象中删除元素

函数名意义
m.erase(k)

删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数

m.erase(p)

从m中删除迭代器p所指向的元素。p必须指向m中确实存在的元素,而且不能等于m.end()。返回void

m.erase(b,

e)

从m中删除一段范围内的元素,该范围由迭代器对b和e标记。b和e必须标记m中的一段有效范围:即b和e都必须指向m中的元素或最后一个元素的下一个位置。而且,b和e要么相等(此时删除的范围为空),要么b所指向的元素必须出在e所

指向的元素之前。返回 void 类型

string removal_word = "a";
if (word_count.erase(removal_word))
cout << "ok: " << removal_word << " removed\n";
else cout << "oops: " << removal_word << " not found!\n";

  6、set(需要导入头文件#include <set>)

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

       ①set容器的定义和使用

           set 容器的每个键都只能对应一个元素。以一段范围的元素初始化set对象,或在set对象中插入一组元素时,对于每个键,事实上都只添加了一个元素。

vector< int > ivec;

for  (vector< int >::size_type i = 0; i != 10; ++i) {

ivec.push_back(i);

ivec.push_back(i);

}

set< int > iset(ivec.begin(), ivec.end());

cout << ivec.size() << endl;  //20个

cout << iset.size() << endl;  // 10个

       ②在set中添加元素

set<string> set1;

set1.insert( "the" );  //第一种方法:直接添加

set< int > iset2;

iset2.insert(ivec.begin(), ivec.end()); //第二中方法:通过指针迭代器

        ③从set中获取元素

 set 容器不提供下标操作符。为了通过键从 set 中获取元素,可使用 find运算。
如果只需简单地判断某个元素是否存在,同样可以使用 count 运算,返回 set 中该键对应的元素个数。
当然,对于 set 容器,count 的返回值只能是1(该元素存在)或 0(该元素不存在)。

set< int > iset;

for ( int  i = 0; i<10; i++)iset.insert(i);

iset.find(1)  // 返回指向元素内容为1的指针

iset.find(11)  // 返回指针iset.end()

iset.count(1)  // 存在,返回1

iset.count(11)  // 不存在,返回0

  •    set<int>::iterator it=iset.begin()

*it就是当前迭代器指向的值

  • set默认是从小到大排列值,定义时set<int,greater<int>> iset;则此时默认是从大到小排列值。

   ④迭代器的关联容器操作

函数名意义
m.lower_bound(k)

返回一个迭代器,指向键不小于 k 的第一个元素

m.upper_bound(k)返回一个迭代器,指向键大于 k 的第一个元素
m.equal_range(k)

返回一个迭代器的 pair 对象。它的 first 成员等价于 m.lower_bound(k)。而 second 成员则等价于 m.upper_bound(k)


四、各种容器的元素在内存中的储存方式

1、vector(向量):相当于数组,但其大小可以不预先指定,并且自动扩展。它可以像数组一样被操作,

由于它的特性我们完全可以将vector 看作动态数组。在创建一个vector 后,它会自动在内存中分配一块连续的

内存空间进行数据存储,初始的空间大小可以预先指定也可以由vector 默认指定,这个大小即capacity ()函数

的返回值。当存储的数据超过分配的空间时vector 会重新分配一块内存块,但这样的分配是很耗时的,效率非常低。

2、deque(队列):它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个

映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小,它不需要重新分配空间。
3、list(列表):是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、

一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,

并且由指针将有序的元素链接起来。
4、set, multiset, map, multimap 是一种非线性的树结构,具体的说采用的是一种比较高效的特殊的

平衡检索二叉树—— 红黑树结构。

五、各种容器优劣分析

1、Vector:
优点:
  A、支持随机访问,访问效率高和方便,它像数组一样被访问,即支持[ ] 操作符和vector.at()。
  B、节省空间,因为它是连续存储,在存储数据的区域都是没有被浪费的,但是要明确一点vector 大多情况下并不是满存的,在未存储的区域实际是浪费的。
缺点:
  A、在内部进行插入、删除操作效率非常低。
  B、只能在vector 的最后进行push 和pop ,不能在vector 的头进行push 和pop 。
  C、 当动态添加的数据超过vector 默认分配的大小时要进行内存的重新分配、拷贝与释放,这个操作非常消耗能。

2、List:
优点:
  不使用连续的内存空间这样可以随意地进行动态操作,插入、删除操作效率高;
缺点:
  A、不能进行内部的随机访问,即不支持[ ] 操作符和vector.at(),访问效率低。
  B、相对于verctor 占用更多的内存。

3、Deque:
优点:
  A、支持随机访问,方便,即支持[ ] 操作符和vector.at() ,但性能没有vector 好;
  B、可以在两端进行push 、pop 。
缺点:
  在内部进行插入、删除操作效率低。
综合:
    vector 的查询性能最好,并且在末端增加数据也很好,除非它重新申请内存段;适合高效地随机存储。 
list 是一个链表,任何一个元素都可以是不连续的,但它都有两个指向上一元素和下一元素的指针。所以它对插入、删除元素性能是最好的,而查询性能非常差;适合 大量地插入和删除操作而不关心随机存取的需求。
    deque 是介于两者之间,它兼顾了数组和链表的优点,它是分块的链表和多个数组的联合。所以它有被list 好的查询性能,有被vector 好的插入、删除性能。 如果你需要随即存取又关心两端数据的插入和删除,那么deque 是最佳之选。

3、关联容器的特点是明显的,相对于顺序容器,有以下几个主要特点:
A, 其内部实现是采用非线性的二叉树结构,具体的说是红黑树的结构原理实现的;
B, set 和map 保证了元素的唯一性,mulset 和mulmap 扩展了这一属性,可以允许元素不唯一;
C, 元素是有序的集合,默认在插入的时候按升序排列。

基于以上特点,
A, 关联容器对元素的插入和删除操作比vector 要快,因为vector 是顺序存储,而关联容器是链式存储;比list 要慢,是因为即使它们同是链式结构,但list 是线性的,而关联容器是二叉树结构,其改变一个元素涉及到其它元素的变动比list 要多,并且它是排序的,每次插入和删除都需要对元素重新排序;

B, 关联容器对元素的检索操作比vector 慢,但是比list 要快很多。vector 是顺序的连续存储,当然是比不上的,但相对链式的list 要快很多是因为list 是逐个搜索,它搜索的时间是跟容器的大小成正比,而关联容器 查找的复杂度基本是Log(N) ,比如如果有1000 个记录,最多查找10 次,1,000,000 个记录,最多查找20 次。容器越大,关联容器相对list 的优越性就越能体现;

C, 在使用上set 区别于vector,deque,list 的最大特点就是set 是内部排序的,这在查询上虽然逊色于vector ,但是却大大的强于list 。

D, 在使用上map 的功能是不可取代的,它保存了“键- 值”关系的数据,而这种键值关系采用了类数组的方式。数组是用数字类型的下标来索引元素的位置,而map 是用字符型关键字来索引元素的位置。在使用上map 也提供了一种类数组操作的方式,即它可以通过下标来检索数据,这是其他容器做不到的,当然也包括set 。(STL 中只有vector 和map 可以通过类数组的方式操作元素,即如同ele[1] 方式)。

六、关于容器的sizeof、size()、capacity问题

vector<int> ivec;

cout<<sizeof(ivec)<<endl; // 12

cout<<ivec.size()<<endl; // 0

cout<<ivec.capacity()<<endl; // 0

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

ivec.push_back(1);

cout<<sizeof(ivec)<<endl; // 12

Cout<<ivec.size()<<endl; // 10

cout<<ivec.capacity()<<endl; // 16


       这是container的实现问题,container肯定有些数据成员什么的,这可以是auto_ptr或者是普通的ptr指向一块内存区域,或者还有可能(应该)包括这个内存区域的长度,现在已经用的长度。sizeof操作符统计的只是数据成员的长度,不会与堆里面的数据长度有关,所以会出现你看到的结果。即作sizeof操作的大小是相同的。而vector::size()操作,才反映了具体数据长度。Capacity求的是容器(vector)的容量。

七、其它

1、STL中hashtable,hashset,hashmap,set,map,unordered_map、unordered_set的区别

       ①hashtable,hashset,hashmap,unordered_map、unordered_set与set,map的根本区别在于底层的实现不同,前者底层都是由hashtable来提供的,后者都是由红黑树来提供;前者查询时间虽然是O(1),但是并不是前者查询时间一定比后者短,因为实际情况中还要考虑到数据量,而且前者的hash函数的构造速度也没那么快,所以不能一概而论,应该具体情况具体分析。后者保证了一个稳定的动态操作时间,查询、插入、删除都是O(logN),最坏和平均都是。

    ②unordered_map、unordered_set在C++11的时候被引入标准库了,而hashset,hashmap没有,所以建议还是使用unordered_map比较好。

    ③hashset与set相比较,它里面的元素不一定是经过排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然跟hash函数有关)。(hashmap与map区别一样)

【C++基础】std::vector详解 是 C++ 标准库中的一个容器,提供了动态数组的功能。它的底层实现通常是使用连续的内存块来存储元素,因此可以通过指针算术来访问元素,并且支持常数时间的随机访问,并支持在容器末尾高效地添加和删除元素。 阅读详情

相关推荐

【STL】容器分类及用法(图文+代码详解)

STL学习笔记02

m0_52309496的博客 1889

STL中常用容器总结

1.vector(向量)(底层是数组) 向量没有确定数据类型所以向量可以是多种数据类型,但是注意一个向量对象只能有一种数据类型,可以构造二维向量(二维数组)比如二维整型向量vector ,但值得注意的是二维向量的大元素和小元素(行元素和最小元素)都是一个向量可以不分配大小而是通过数据的规模分配大小 这里介绍整型向量的常用方法函数(其他类型的可以自行通过转换类型达到相同的效果): vector a(...

Gardenia 3408

C++ STL容器在实际项目中的选择和使用策略

通过合理地选择和使用STL容器,我们可以提高代码的效率、可读性和可维护性,从而构建出更加健壮和高效的C++应用程序。在C++编程中,标准模板库(STL)提供了丰富的容器类,这些容器类为数据的存储和操作提供了高效且灵活的方式。在这个案例中,我们使用了map容器的插入、查找、删除和遍历等操作,实现了对学生信息的存储和管理。我们可以选择使用map作为存储学生信息的容器,因为map可以根据学生的ID快速查找、插入和删除学生信息。C++ STL中的容器大致可分为三类:序列容器、关联容器和容器适配器。

AntonioMargery的博客 1020

STL容器

STL容器底层知识

g498912529的博客 5228

STL 每种容器的使用场景

array array 容器的大小是固定的,无法动态的扩展或收缩,这就意味着,在使用该容器的过程无法借由增加或移除元素而改变其大小,它只允许访问或者替换存储的元素。 vector vector 常被称为向量容器,因为该容器擅长在尾部插入或删除元素,在常量时间内就可以完成,时间复杂度为O(1);而对于在容器头部或者中部插入或删除元素,则花费时间要长一些(移动元素需要耗费时间),时间复杂度为线性阶O(n)。 deque deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间

a15322910600的博客 751

【048】C++ STL容器的使用时机:何时使用哪个?

C++ STL 容器是高效编程的关键,但选择合适的容器至关重要。本文将深入探讨 STL 容器的三大类别:顺序容器、关联容器和无序关联容器,详细分析 `vector`、`list`、`deque`、`set`、`map` 等常用容器的特性、性能差异及适用场景。我们将比较不同容器在内存管理、随机访问、插入/删除操作等方面的优劣,并提供最佳实践和使用技巧,帮助开发者根据实际需求选择最合适的容器,从而编写出高效、可靠的 C++ 代码。 最后,还会推荐一些学习资源,帮助读者更深入地学习 STL 容器。

Lion_Long的博客 1876

C++ STL中容器的使用全面总结

一、容器的定义        在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对像的指针,这种对象类型就叫做容器。很简单,容器就是保存其它对象的对象,当然这是一个朴素的理解,这种“对象”还包含了一系列处理“其它对象”的方法。 二、容器的种类   1、顺序容器:是一种各元素之间有顺序关系的线性表,是一种线性结构的可序群集。顺序性容器中的每个元素均有固定的位置,除非用删除或插入的操

算法改变人生 6万+

如何在iPhone上本地运行SmolVLM?5亿参数模型实战指南(附Swift代码)

本文详细介绍了如何在iPhone上本地部署和运行轻量高效的SmolVLM多模态模型。通过实战指南,分享了使用Swift和MLX框架进行环境配置、模型加载、内存优化以及实现实时图像分析与文本生成的完整流程,帮助开发者在移动端高效运行AI视觉语言模型。

echo99的专栏 654

STL常用容器——map容器的使用

map容器是存储pair 类型键值对( pair 类模板创建的 pair 对象)的关联式容器。pair 键值对(pair):键值对中第一个元素为key(键),起查找作用,第二个元素为value(值)。使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改。在使用 map 容器存储多个键值对时,默认情况下会自动根据各键值对的键的大小,对所有键值对做升序排序。

万里顾一程的博客 3262

基于FPGA的UDP 通信(六)

本文基于FPGA和MATLAB对千兆以太网通信模块UDP数据发送(FPGA发送)进行联合调试。

记录所学,分享知识,结识挚友 4728

uniapp微信小程序 - 详解map地图markers图标不显示问题,自定义图标真机调试不显示变成默认marker标记点图标(解决微信小程序map组件markers自定义图标失效,兼容安卓苹果手机)

uniapp微信小程序 map地图markers图标不显示,markers图标真机调试不显示,uniapp map地图显示图标markers问题,自定义图标不显示,添加marker后不显示,uniapp 微信小程序 map marker图标不显示如何解决,uniapp小程序地图的marker图标不显示问题,微信小程序map组件markers自定义图标真机显示问题,uni-app, 微信小程序, map组件, markers图标不显示, 真机调试, 微信小程序map组件,地图加载后marker标记点ios设备

🏆 前端领域优质创作者 2911

C++ 如何高效的使用 STL 容器?

在使用C++标准模板库(STL)中的容器时,对象复制的常见情况和复制的实现方式是重要的考虑因素。对象的复制通常通过复制构造函数和复制赋值运算符来完成,这两个函数是类的成员函数,用于创建类的新对象或将一个对象的值赋给另一个对象。然而,对象的复制可能会导致性能问题,特别是当对象的复制成本很高时。此外,如果有一个对象,其中“复制”有一个非常规的含义,那么将这样的对象放入容器可能会导致问题。在存在继承的情况下,复制可能会导致切片问题。

红军不怕远征难,万水千山只等闲 1465

R语言中的summarise函数和mutate函数用于计算分组占比。下面是关于这两个函数的详细介绍以及相应的源代码示例:

R语言中的summarise函数和mutate函数用于计算分组占比。

CodeByte的博客 1180

【C++】STL 容器总结 ( STL 各容器特点 | STL 个容器使用场景 | 单端数组容器 | 双端队列容器 | 双向链表容器 | 集合容器 | 多重集合容器 | 映射容器 | 多重映射容器 )

一、STL 各容器特点 1、std::vector 单端数组容器 2、std::deque 双端队列容器 3、std::list 双向链表容器 4、std::set 集合容器 5、std::multiset 多重集合容器 6、std::map 映射容器 7、std::multimap 多重映射容器 二、STL 各容器特点总结 三、STL 各容器使用场景示例

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 6689

非结构化数据在大数据湖中的应用实践

想象一下,你正在整理一个杂乱的书房。有些书整整齐齐地放在书架上,每本书都有明确的标题、作者和出版日期——这些就是结构化数据,它们像数据库中的表格,有固定的格式和字段。但书房里还有更多东西:散落的照片、手写的笔记、录音带、视频光盘、甚至还有画作。这些物品没有固定的格式,每件都独一无二——这就是非结构化数据。在技术术语中,非结构化数据是指没有预定义数据模型或组织形式的信息。文本文档(Word、PDF、TXT)电子邮件和社交媒体内容图像和照片(JPG、PNG)音频文件(MP3、WAV)

软件工程实践的博客 360

OpenCV计算机视觉实战(3)——计算机图像处理基础

本文全面介绍了计算机视觉和数字图像处理的基础知识。从最基本的像素概念入手,详细讲解了图像在计算机中的表示方式,包括RGB、CMYK等色彩空间的工作原理及其应用场景。还系统分析了常见图像和视频文件格式的特点,梳理了计算机图像处理技术的发展历程,并重点介绍了OpenCV这一强大的开源计算机视觉库的功能与应用领域。

qq_30167691的博客 1738

【STL】STL各常用容器特点、STL各容器使用时机、STL容器共性机制、deque、stack、queue

对STL中deque、stack、queue、list、Set、Map各容器的特点对比,使用时机,共性机制的总结,以方便于日后个容器的使用。 自我感觉本博客STL分类中的各个博客能让你了解并会使用SLT中的几乎一切基础知识。

兰斯兰斯 505

Spring Boot入门(13):Mybatis-Plus之条件构造器使用手册:精通让你快速提高查询效率的技巧!

化繁为简,MP 中条件构造器的使用,极其详细.

**My Coding Family** 3万+

STL容器跨模块使用的风险

即使在PIMPL模式中,如果头文件的接口参数仍然包含STL容器(如std::string和std::vector),还是可能导致ABI兼容性问题。此例中就未解决问题!如果两个模块(如动态库和可执行文件)的ABI不兼容,即使它们的源代码兼容,编译后的二进制文件也可能无法正确协同工作。:减少头文件依赖,但接口参数仍需处理STL的ABI问题。在头文件中隐藏STL容器的使用,仅暴露实现类指针。例如一个日志库的头文件接口参数有 STL 容器。

lijian2017的博客 818

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

STL容器跨模块使用风险

在不同版本的 Visual Studio(VS)中调用该接口时,若为封闭项目,强制统一编译环境是最简单的方式。,尤其是当接口参数涉及STL容器(如。:若需跨不同VS版本调用接口,

lijian2017的博客 583

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C++ STL Queue容器使用详解

它基于其他底层容器实现队列数据结构,遵循先进先出(FIFO)原则。是标准模板库(STL)中的。

2301_80167761的博客 590

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

STL中list的容器使用介绍

STL中list的使用:   STL中的list就是一双向链表,可高效地进行插入删除元素。现总结一下它的操作。   文中所用到两个list对象c1,c2分别有元素c1(10,20,30)  c2(40,50,60)。还有一个list::iterator citer用来指向c1或c2元素。   list对象的声明构造():   A.      listc0;

rainbow693的博客 2464

【c++】STL容器-string的使用

一、STL 1. STL简要介绍 2. STL版本 3. STL六大组件 二、string 1. string的介绍 2. string的使用 1. 默认成员函数 1. 构造函数和拷贝构造函数 2. 析构函数 3. 赋值运算符重载 2. 迭代器的使用 范围for遍历和operator[]和operator<<或迭代器进行遍历 3. 容量有关的成员函数 4. 元素访问 5. 用于修改的成员函数 6. 字符串操作 7. 非成员函数的重载

重铸自身根基的博客 1621

stl容器使用

注意:count函数在set中返回值始终为1,因为set容器中不能存储重复的元素,但在multiset容器中可以,所以在multiset中返回值可以为其他的值。//若n大于原来的大小,则容器变长为n,增加的元素自动为0。注意:erase函数中删除的是()中前一个元素,如上的d1.erase(d1.end()-1),如果()中的是d1.erase(d1.end()整个代码解释: 在原有的数组,头部添加了一个100,尾部添加了一个0,输出,然后删除尾部的元素,再输出。2.栈没有迭代器,不能遍历。

2301_80029042的博客 1743

STL库和常用容器使用

STL(Standard Template Library,标准模板库)是C++标准库的一部分,提供了丰富的通用模板类和函数,用于实现常见的数据结构和算法。STL的设计目标是提供高效、通用、可复用的数据结构和算法,以及一致的接口和编程风格,使得C++程序员能够更加方便地编写高质量的代码。:容器是用于存储和组织数据的类模板,提供了多种数据结构,如向量、列表、映射、集合等。容器可以存储任意类型的数据,并提供了丰富的操作接口,如插入、删除、访问等。

zhangqiling 971
上一篇: 深入解析C++ STL中的常用容器
下一篇: STL基本容器使用
imJaron
博客等级 码龄11年 121粉丝 286原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值