C++各个容器比较(vector,deque,list,set,map,queue,stack)

在容器中添加或删除元素可能会使已存在的迭代器失效。当混合使用迭代器操作和容器操作时,必须时刻留意给定的容器操作是否会使迭代器失效。许多使一个迭代器失效的操作,例如 insert 或 erase,将返回一个新的迭代器,让程序员保留容器中的一个位置。使用改变容器长度的容器操作的循环必须非常小心其迭代器的使用。

一:

标准库定义了三种顺序容器类型:vector、list 和 deque(是双端队列“double-ended queue”的简写,发音为“deck”)。
顺序容器适配器包括 stack、queue 和 priority_queue 类型,见表。

顺序容器
vector 支持快速随机访问
list 支持快速插入/删除
deque 双端队列
顺序容器适配器
stack 后进先出(LIFO)堆栈
queue 先进先出(FIFO)队列
priority_queue 有优先级管理的队列

二:

C++ 定义的容器类型中,只有 vector 和 deque 容器提供下面两种重要的运算集合:迭代器算术运算(第 3.4.1 节),以及使用除了 == 和 != 之外的关系操作符来比较两个迭代器(== 和 != 这两种关系运算适用于所有容器)。表 9.4 总结了这些相关的操作符。

*iter      返回迭代器 iter 所指向的元素的引用
iter->mem  对 iter 进行解引用,获取指定元素中名为 mem 的成员。等效于(*iter).mem
++iter
iter++      给 iter 加 1,使其指向容器里的下一个元素
--iter
iter--      给 iter 减 1,使其指向容器里的前一个元素
iter1 == iter2
iter1 != iter2   比较两个迭代器是否相等(或不等)。当两个迭代器指向同一个容器中的同一个元素,或者当它们都指向同一个容器的超出末端的下一位置时,两个迭代器相等

vector 和 deque 类型迭代器支持的操作,只适用于 vector 和 deque 容器:
iter + n
iter - n  
在迭代器上加(减)整数值 n,将产生指向容器中前面(后面)第 n个元素的迭代器。新计算出来的迭代器必须指向容器中的元素或超出容器末端的下一位置
iter1 += iter2
iter1 -= iter2
这里迭代器加减法的复合赋值运算:将 iter1 加上或减去 iter2 的运算结果赋给 iter1
iter1 -iter2
两个迭代器的减法,其运算结果加上右边的迭代器即得左边的迭代器。这两个迭代器必须指向同一个容器中的元素或超出容器末端的下一位置。
>, >=, <, <=
迭代器的关系操作符。当一个迭代器指向的元素在容器中位于另一个迭代器指向的元素之前,则前一个迭代器小于后一个迭代器。关系操作符的两个迭代器必须指向同一个容器中的元素或超出容器末端的下一位置.

例如,下面的语句用于计算 vector 对象的中点位置:
vector<int>::iterator iter = vec.begin() + vec.size()/2;
另一方面,代码:
// copy elements from vec into ilist
list<int> ilist(vec.begin(), vec.end());
ilist.begin() + ilist.size()/2; // error: no addition on list iterators
是错误的。list 容器的迭代器既不支持算术运算(加法或减法),也不支持关系运算(<=, <, >=, >),它只提供前置和后置的自增、自减运算以及相等(不等)运算。

9.2.1. 迭代器范围
c.begin() 返回一个迭代器,它指向容器 c 的第一个元素
c.end() 返回一个迭代器,它指向容器 c 的最后一个元素的下一位置
c.rbegin() 返回一个逆序迭代器,它指向容器 c 的最后一个元素
c.rend() 返回一个逆序迭代器,它指向容器 c 的第一个元素前面的位置

C++ 语言使用一对迭代器标记迭代器范围(iterator range),这两个迭代器分别指向同一个容器中的两个元素或超出末端的下一位置,通常将它们命名为first 和 last,或 beg 和 end,用于标记容器中的一段元素范围。
尽管 last 和 end 这两个名字很常见,但是它们却容易引起误解。其实第二个迭代器从来都不是指向元素范围的最后一个元素,而是指向最后一个元素的下一位置。该范围内的元素包括迭代器 first 指向的元素,以及从 first 开始一直到迭代器 last 指向的位置之前的所有元素。如果两个迭代器相等,则迭代器范围为空  
[ first, last )
while (first != last)
{
// safe to use *first because we know there is at least one element
++first;
}


三:

9.3.3. 在顺序容器中添加元素
调用 push_back 函数会在容器 container 尾部创建一个新元素,并使容器的长度加 1。新元素的值为 text_word 对象的副本,而 container 的类型则可能是 list、vector 或 deque。    除了 push_back 运算,list 和 deque 容器类型还提供了类似的操作:push_front。这个操作实现在容器首部插入新元素的功能。

list<int> ilist;
for (size_t ix = 0; ix != 4; ++ix)
ilist.push_back(ix);
for (size_t ix = 0; ix != 4; ++ix)
ilist.push_front(ix);
循环结束后,ilist内的元素序列为:3、2、1、0、0、1、2、3。

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 类型

任何 insert 或 push 操作都可能导致迭代器失效。当编写循环将元素插入到 vector 或 deque 容器中时,程序必须确保迭代器在每次循环后都得到更新。

表 9.8. 顺序容器的大小操作

c.size() 返回容器 c 中的元素个数。返回类型为 c::size_type
c.max_size() 返回容器 c 可容纳的最多元素个数,返回类型为c::size_type

c.empty() 返回标记容器大小是否为 0 的布尔值


四:

9.3.6. 访问元素

如果容器非空,那么容器类型的 front 和 back 成员(表 9.9)将返回容器内第一个或最后一个元素的引用:

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


五:

9.3.7. 删除元素

回顾前面的章节,我们知道容器类型提供了通用的 insert 操作在容器的任何位置插入元素,并支持特定的 push_front 和 push_back 操作在容器首部或尾部插入新元素。类似地,容器类型提供了通用的 erase 操作和特定的pop_front 和 pop_back 操作来删除容器内的元素(表 9.10)。

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 容器)


pop_front 和 pop_back 函数用于删除容器内的第一个和最后一个元素。但vector 容器类型不支持 pop_front 操作。这些操作删除指定的元素并返回void。
pop_front 操作通常与 front 操作配套使用,实现以栈的方式处理容器:
while (!ilist.empty()) {
process(ilist.front()); // do something with the current top of ilist
ilist.pop_front(); // done; remove first element
}
这个循环非常简单:使用 front 操作获取要处理的元素,然后调用pop_front 函数从容器 list 中删除该元素。


六:

适配器

默认的 stack 和 queue 都基于 deque 容器实现,而 priority_queue 则在 vector 容器上实现。在创建适配器时,通过将一个顺序容器指定为适配器的第二个类型实参,可覆盖其关联的基础容器类型:
// empty stack implemented on top of vector
stack< string, vector<string> > str_stk;
// str_stk2 is implemented on top of vector and holds a copy of svec
stack<string, vector<string> > str_stk2(svec);

对于给定的适配器,其关联的容器必须满足一定的约束条件。stack 适配器所关联的基础容器可以是任意一种顺序容器类型。因此,stack 栈可以建立在vector、list 或者 deque 容器之上。而 queue 适配器要求其关联的基础容器必须提供 push_front 运算,因此只能建立在 list 容器上,而不能建立在vector 容器上。priority_queue 适配器要求提供随机访问功能,因此可建立在vector 或 deque 容器上,但不能建立在 list 容器上。


9.7.1. 栈适配器
表 9.23 列出了栈提供的所有操作。

s.empty() 如果栈为空,则返回 true,否则返回 stack
s.size() 返回栈中元素的个数
s.pop() 删除栈顶元素的值,但不返回其值
s.top() 返回栈顶元素的值,但不删除该元素

s.push(item) 在栈顶压入新元素

(尽管栈是以 deque 容器为基础实现的,但是程序员不能直接访问deque 所提供的操作。例如,不能在栈上调用 push_back 函数,而是必须使用栈所提供的名为 push 的操作。)

9.7.2. 队列和优先级队列  先进先出(FIFO)的存储和检索策略

表 9.24. 队列和优先级队列支持的操作
q.empty() 如果队列为空,则返回 true,否则返回 false
q.size() 返回队列中元素的个数
q.pop() 删除队首元素,但不返回其值
q.front() 返回队首元素的值,但不删除该元素该操作只适用于队列
q.back() 返回队尾元素的值,但不删除该元素该操作只适用于队列

q.top() 返回具有最高优先级的元素值,但不删除该元素该操作只适用于优先级队列
q.push(item) 对于 queue,在队尾压入一个新元素,对于 priority_quue,在基于优先级的适当位置插入新元素




1、vector(连续的空间存储,可以使用[ ]操作符)可以快速的访问随机的元素,快速的在末尾插入元素,但是在序列中间随机的插入、删除元素要慢。而且,如果一开始分配的空间不够时,有一个重新分配更大空间的过程
2、deque(小片的连续,小片间用链表相连,实际上内部有一个map的指针,因为知道类型,所以还是可以使用[ ],只是速度没有vector快)快速的访问随机的元素,快速的在开始和末尾插入元素。随机的插入删除元素要慢,空间的从新分配空间后,原有的元素不需要备份。对deque的排序操作,可将deque先复制到vector,排序后再复制回deque
 
3、list(每个元素间用链表相连)访问随机元素没有vector快,随机地插入元素要比vector快,对每个元素分配空间,不存在空间不够,重新分配的情况。
 
4、set内部元素唯一,用一棵平衡树结构来存储,因此遍历的时候就排序了,查找也比较快
 
5、map一对一地映射结合,key没有重复
 
6、queue的声明queue<int,deque<int> > s是受限的队列,存储的空间由第二个参数的容器确定,第一个参数在没有第二个参数的情况下,决定存储空间类型,第二个参数存在的情况下,第一个类型参数无效。默认情况下是deque类型的,因此可以如此声明queue<int> s1,这样,声明的队列存储空间就是默认的deque。另外,queue第二个参数可以选择的容器类型包括deque、list,其余的如果声明,操作受限。
 
7、stack的默认存储空间也是deque,其他的声明和queue差不多,可以使用的容器类型包括deque、vector、list,stack是先进后出栈。
 

 

1、stack
stack 模板类的定义在<stack>头文件中。
stack 模板类需要两个模板参数,一个是元素类型,一个容器类型,但只有元素类型是必要
的,在不指定容器类型时,默认的容器类型为deque。
定义stack 对象的示例代码如下:
stack<int> s1;
stack<string> s2;
stack 的基本操作有:
入栈,如例:s.push(x);
出栈,如例:s.pop();注意,出栈操作只是删除栈顶元素,并不返回该元素。
访问栈顶,如例:s.top()
判断栈空,如例:s.empty(),当栈空时,返回true。
访问栈中的元素个数,如例:s.size()。

 

2、queue
queue 模板类的定义在<queue>头文件中。
与stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类
型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
定义queue 对象的示例代码如下:
queue<int> q1;
queue<double> q2;

queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,如例:q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:q.size()

#include <cstdlib>
#include <iostream>
#include <queue>

using namespace std;

int main()
{
    int e,n,m;
    queue<int> q1;
    for(int i=0;i<10;i++)
       q1.push(i);
    if(!q1.empty())
    cout<<"dui lie  bu kong\n";
    n=q1.size();
    cout<<n<<endl;
    m=q1.back();
    cout<<m<<endl;
    for(int j=0;j<n;j++)
    {
       e=q1.front();
       cout<<e<<" ";
       q1.pop();
    }
    cout<<endl;
    if(q1.empty())
    cout<<"dui lie  bu kong\n";
    system("PAUSE");
    return 0;


3 deque

3-1)deque<int>::iterator myItor

    #include "stdafx.h"  
    #include <iostream>  
    #include <deque>  
    using namespace std;  
      
      
    int _tmain(int argc, _TCHAR* argv[])  
    {  
        deque<int> myDeque;  
        myDeque.push_front(1);  
        myDeque.push_front(2);  
        myDeque.push_back(3);  
        myDeque.push_back(4);  
        myDeque.push_back(5);  
        myDeque.push_front(6);  
        myDeque.pop_back();  
        deque<int>::iterator myItor;  
        for(myItor=myDeque.begin(); myItor!=myDeque.end(); myItor++)  
            cout<<*myItor<<endl;  
              
        return 0;  
    }
//输出为  6 1 2 3 4 5




注意事项!

C++中string erase函数的使用

erase函数的原型如下:
(1)string& erase ( size_t pos = 0, size_t n = npos );
(2)iterator erase ( iterator position );
(3)iterator erase ( iterator first, iterator last );
也就是说有三种用法:
(1)erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符(vector就只有迭代器的方法,没有size_t的方法!!!!)
(2)erase(position);删除position处的一个字符(position是个string类型的迭代器)
(3)erase(first,last);删除从first到last之间的字符(first和last都是迭代器)
下面给你一个例子:
// string::erase
#include <iostream>
#include <string>
using namespace std;

int main ()
{
  string str ("This is an example phrase.");
  string::iterator it;

  // 第(1)种用法
  str.erase (10,8);
  cout << str << endl;        // "This is an phrase."

  // 第(2)种用法
  it=str.begin()+9;
  str.erase (it);
  cout << str << endl;        // "This is a phrase."

  // 第(3)种用法
  str.erase (str.begin()+5, str.end()-7);
  cout << str << endl;        // "This phrase."
  return 0;
}

你的假如是删除数组中的一项,并不能说明erase的用法。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值