[转]C++容器亲自总结

C++容器亲自总结


原文链接:C++容器亲自总结

容器的定义#

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

容器的种类#

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

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

容器适配器:本质上,适配器是使一种不同的行为类似于另一事物的行为的一种机制。容器适配器让一种已存在的容器类型采用另一种不同的抽象类型的工作方式实现。适配器是容器的接口,它本身不能直接保存元素,它保存元素的机制是调用另一种顺序容器去实现,即可以把适配器看作“它保存一个容器,这个容器再保存所有元素”。STL 中包含三种适配器:栈stack 、队列queue和优先级队列priority_queue

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

不同容器的使用方法#

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

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;

deque#

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

顺序容器使用方法小结#

添加元素#

函数名 意义
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个元素。

map#

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

定义与初始化(需要导入头文件#include )#

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):可理解为键类型数据上的“小于”关系,虽然实际上可以选择将比较函数设计得更复杂。
对于键类型,唯一的约束就是必须支持 < 操作符,至于是否支持其他的关系或相等运算,则不作要求。

常用的操作方法#

添加元素有两种方法:

  • 先用下标操作符获取元素,然后给获取的元素赋值
  • 使用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";

set#

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

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)

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

  • vector(向量):相当于数组,但其大小可以不预先指定,并且自动扩展。它可以像数组一样被操作,由于它的特性我们完全可以将vector 看作动态数组。在创建一个vector 后,它会自动在内存中分配一块连续的内存空间进行数据存储,初始的空间大小可以预先指定也可以由vector 默认指定,这个大小即capacity ()函数的返回值。当存储的数据超过分配的空间时vector 会重新分配一块内存块,但这样的分配是很耗时的,效率非常低。

  • deque(队列):它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小,它不需要重新分配空间。

  • list(列表):是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。

  • set、multiset、 map、multimap: 是一种非线性的树结构,具体的说采用的是一种比较高效的特殊的平衡检索二叉树—— 红黑树结构。

各种容器优劣分析#

Vector#

优点:

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

List:#

优点:

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

Deque:#

优点:

  • 支持随机访问,方便,即支持[ ] 操作符和vector.at() ,但性能没有vector 好;
  • 可以在两端进行push 、pop 。
    缺点:
  • 在内部进行插入、删除操作效率低。

综合#

vector 的查询性能最好,并且在末端增加数据也很好,除非它重新申请内存段;适合高效地随机存储

list 是一个链表,任何一个元素都可以是不连续的,但它都有两个指向上一元素和下一元素的指针。所以它对插入、删除元素性能是最好的,而查询性能非常差;适合大量地插入和删除操作而不关心随机存取的需求

deque 是介于两者之间,它兼顾了数组和链表的优点,它是分块的链表和多个数组的联合。所以它有比 list 好的查询性能,有比 vector 好的插入、删除性能。 如果你需要随即存取又关心两端数据的插入和删除,那么deque 是最佳之选

关联容器的特点是明显的,相对于顺序容器,有以下几个主要特点:

  • 其内部实现是采用非线性的二叉树结构,具体的说是红黑树的结构原理实现的;
  • set 和map 保证了元素的唯一性,mulset 和mulmap 扩展了这一属性,可以允许元素不唯一;
  • 元素是有序的集合,默认在插入的时候按升序排列

基于以上分析:

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

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

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

  • 在使用上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

扩展:栈stack 、队列queue和优先级队列priority_queue#

原文链接:容器适配器stack,queue和priority_queue

栈stack#

stack是一种后进先出特点的容器适配器,其删除和插入操作只能在容器的一端进行,即只能在栈顶插入和弹出
stack的底层容器可以是任何标准的容器类模板或者其它特定的类容器(你设计的容器),但是这些容器必须支持以下操作:empty(判空),back(获取尾部元素),push_back(尾插),pop_back(尾删),size(获取元素大小)
vector,list,deque皆可作为stack的底层容器,默认情况下,如果没有为stack指定容器,默认使用deque作为默认容器

使用stack需要包含头文件#include<stack>stack不存在迭代器

函数名称 功能
stack() 构造一个空栈
empty() 判断栈是否为空,空返回true,非空返回false
size() 返回栈元素个数
top() 返回栈顶元素的引用
push() 在栈顶插入元素
pop() 将stack栈顶元素弹出

队列queue#

队列是一种先进先出的容器适配器,其中从容器的一段插入,另一端提取元素。在队尾插入,在队头弹出元素
底层容器是标准容器类模板之一,也可以只用你专门设计的容器类,该容器必须支持empty(判空),front(获取队头元素的引用),back(获取队尾元素引用),push_back(尾插),pop_front(头删),size(获取元素大小)
vector,list和deque满足这些要求。默认情况下,没显示给出queue指定容器,默认使用deque

使用queue需要包含头文件#include<queue>queue容器适配器没有迭代器

函数声明 功能介绍
queue() 构造空队列
size() 返回队列中的元素个数
empty() 判断队列是否为空
back() 返回队尾元素引用
front() 返回队头元素引用
push() 在对尾插入元素
pop() 将队头元素弹出

优先级队列priority_queue#

优先队列是容器适配器,根据若排序标准,它的第一个元素总是它所包含的元素中优先级最高的。(或许值是最大的,或许是最小的),就像数据结构里的堆。
优先队列默认形成大堆(根结点最小),优先队列的元素从顶部弹出,顶部是优先级最高的。
底层容器可以是任何容器的类模板,也可以是其他特定设计的容器类(自己设计的),容器支持的功能:随机访问operator[],empty,size,front,push_back,pop_front
标准容器vector和deque都可以满足这些需求,没显示定义容器模板时,优先队列默认使用vector
优先队列使用仿函数来控制生成大根堆还是生成小根堆

优先队列就是一个堆,在使用堆的地方都可以使用优先队列,头文件也是#include<queue>:

函数 功能
priority_queue() 建立一个空优先队列
priority_queue(first,last) 将迭代器first到last之间的元素建堆
top 返回优先级队列中优先级最高元素,即堆顶元素
size 返回优先队列里的元素个数
empty 判断优先队列是否为空
push 往优先队列中插入元素
pop 删除优先级队列中优先级最高元素,即堆顶元素

其它内容可参考文章priority_queue 的常见用法详解

posted @   二次元攻城狮  阅读(103)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
  1. 1 烟花易冷 小柔Channel
  2. 2 红颜如霜 江壹纯
  3. 3 不谓侠 小桃Channel
  4. 4 小小恋歌 新坦结衣
  5. 5 神预言 袁娅维TIARAY
红颜如霜 - 江壹纯
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.
点击右上角即可分享
微信分享提示
主题色彩