Standard Template Library ~ vector + list + deque

STL中的线性表有3种实现:顺序实现vector,双链表的实现list和优化实现deque。这些类都可以用迭代器来访问。由于每个类的实现方式是不同的,因此这些类对应的迭代器类的实现也是不同的。为了便于用户使用,STL将迭代器类定义为相应容器内的公有的内嵌类,并且对于所有的迭代器,他们的类名都是相同的。因此,用户不需要分别记忆某个类的迭代器的类名是什么。每个容器提供两个迭代器类:iterator和const_iterator,前者可以通过迭代器修改它指向的数据元素,而后者只能读取它指向的元素而不能修改。

 

vector 类是可动态增长的数组存储线性表的数据元素。list是采用双链表实现的线性表类,他们都支持线性表的常规操作并根据实现的特点适当增加操作。他们共同支持的操作如下图:

函数 作用
int size() const返回容器中的元素个数
void clear()删除容器中的所有元素
bool empty()判断容器是否为空,是空返回true,否则返回false

void push_back(const object &x)

将x添加到表尾
void pop_back()删除表尾元素
const object &back() const返回表尾元素值
const object &front() const返回表头元素值

除了这些操作,每个类还根据自己的特点增加了一些特有的操作。list是用双链表实现的,在表头插入或者删除十分方便,因此增加了在表头和删除元素的操作 void push_front(const object &x) 和 void pop_front()。 vector是用数组实现的,很容易实现下标运算符重载以及一些数组特有的操作。相比于链表而言,顺序表还有容量的概念,所以还有一些针对容量的操作。vector类增加的操作如下表:

函数作用
object &operator[](int idx)返回vector中下标为idx的对象,该操作无边界检查
object &at(int idx)返回vector中下标为idx的对象,但有边界检查
int capacity()返回vector中数组的容量
void reserve(int newCapacity)设置数组容量

 

vector和list都有两个迭代器类:iterator和const_iterator,对于iterator指向的对象可以做任何操作,对const_iterator指向的对象不能做修改操作。这两个迭代器类都被定义成相同容器的内嵌类,因为迭代器是要给用户使用的,因此被设计为公有的内嵌类。vector和list类中的迭代器相关操作如表1,迭代器类的本身的操作如表2

表1- vector和list类中与迭代器相关的操作
函数作用
iterator begin()返回表头的位置
const_iterator begin()返回表头的位置
iterator end()返回表尾的位置
const_iterator end()返回表尾的位置
iterator insert(iterator pos,const object&x)在迭代器pos给出的位置前插入x
iterator erase(iterator pos)删除迭代器pos给出的位置的元素
iterator erase(iterator start,iterator end)删除从start到end之间的元素,但不包括end
表2- 迭代器类的常见操作
函数作用
itr++,  ++itr迭代器指向下一个元素
*itr取迭代器指向的元素
itr1==itr2判断两个迭代器是否指向同一元素,是返回true,否则返回false
itr!==itr2判断两个迭代器是否指向不同元素,是返回true,否则返回false

vector类定义在头文件vector中,list类定义在头文件list中,这两个头文件都定义在名字空间std中。代码清单1给出了vector类的一个使用实例:

//代码清单1
#include<iostream>
#include<vector>
using namespace std;

int main(){
   vector<int>  v;  //定义一个整型的顺序容器 v
   cout<<"the initial size of v is: "<<v.size()
   <<"\n the initial capacity of v is: "<<v.capacity()<<endl;
   v.push_back(2);
   cout<<"\n after push 2, capacity of v is:" <<v.capacity()<<endl;
   
   v.push_back(2);
   cout<<"\n after push 3, capacity of v is :"<<v.capacity()<<endl;
   v.push_back(4);
   cout<<"\n after push 4,capacity of v  is :"<<v.capacity()<<endl;

   //用下标访问v的元素
   cout<<"\n contents of v using iterator notation:";
   vector<int>::const_iterator p;
   for(p=v.begin();p!=v.end();p++)
   cout<<*p<<"  ";
   cout<<endl;
   return 0;
}

代码清单1用到vector类,因此必须包括头文件vector。程序定义了一个整型的vector类对象v,然后分别输出表中元素个数和存储元素的数组规模,由于此时表尾空表,因此输出:

the initial size of v is: 0
the initial capacity of v is: 0

表示表中元素个数和数组规模都为0. 然后分别再表尾中插入2、3、4,并且输出插入2、3、4以后数组的规模。此时产生三行输出:

After push 2,capacity of v is: 1
After push 3,capacity of v is: 2
After push 4,capacity of v is: 4

从表中可以看出来,随着容器中元素的增加,数组的容量也在增加。在插入了3个元素之后再次输出表长和容量,得到两行输出:

the size of v is: 3
the capacity of v is: 4

接下来利用下标重载输出容器中的所有元素,该过程与输出一个普通数组完全一样,只是数组中的元素个数可以通过函数size或得。输出的结果是

contents of v using []: 2 3 4

最后利用迭代器输出容器中的所有元素。首先定义一个vector类的迭代器p,由于该迭代器是用来访问容器中的对象,而不是修改容器中的对象,因此采用 const_iterator. 然后通过一个for循环输出容器中的对象,输出的结果与采用下标变量的输出完全一样。输出的结果是:

contents of v using iterator notation : 2  3  4 

 

代码清单2 给出list类的一个使用实例:

//代码清单2
#include<iostream>
#include<list>
using namespace std;


template<class T>
void printall(const list<T> &v)

int main(){
 
   list<int>  v1;
   
   v1.push_front(1);
   v1.push_front(2)
   v1.push_back(4);
   v1.push_back(3);
   printall(v1);

   list<int>::iterator itr=v1.begin(),itre=v1.end();
   for(int i=5; itr!=itre; ++itr,++i)
   v1.insert(itr,i);
   printall(v1)
   return 0;
}

template<class T>
void printall(const list<T> &v){
   if(v.empty())
      cout<<"\n the list is empty";
   else{
      typename list<T>::const_iterator itr,itre;
      itr=v.begin();
      itre=v.end();
      do(cout<<*itr<<"  ";
      ++itr;
      }while (itr!=itre);
    }
    cout<<endl;
}

代码清单2需要用到list库,因此需要包含list头文件。 main函数定义了一个整型的list对象v1,然后执行了两次表头插入,分别插入1、2,又执行两次表尾插入,分别插入4、3,调用printall输出v1中的所有对象。 此时输出为2 1 4 3. 然后演示了通过迭代器的定位插入。先定义两个迭代器类的对象:itr指向起始节点,itre指向尾结点。从起始节点开始,一个间隔一个,依次插入了5、6、7、8.最后再次调用printall输出v1 的所有对象,此时输出为 5 2 6 1 7 4 8 3.

list对象中的元素只能通过迭代器访问。由于main函数中有两个地方需要输出v1 中所有对象,为此定义了函数模板printall。该函数定义了两个迭代器对象:itr指向起始节点,itre指向尾结点。由于这两个迭代器对象是用来输出容器中的元素,不会改变容器中的元素,因此这两个迭代器采用的是const_iterator迭代器。函数首先调用empty函数判断容器是否为空,如果是非空,那么就输出容器中的所有的对象

vector类和list类都内嵌了两个迭代器,而且两个类的迭代器类的名字是相同的。这种实现方法可以简化类的设计和使用。再设计类的时候,设计者不必为选择迭代器的类名而烦恼,不必担心会和其他容器的迭代器重名。用户使用时也非常的方便,不管使用哪一容器,只需记住迭代器的类名是iterator和const_iterator。要使用vector类的迭代器,可定义vector::iterator类的对象,要使用list类的迭代器,可定义list::iterator的对象。

deque 也是C++用于表示线性结构的标准的容器,是一种经过了优化的容器。它既可以通过下标访问,也可以通过迭代器访问。它的两端操作(表头和表尾的插入或者删除)的效率类似于list,下标操作的效率接近于vector。但在中间插入和删除的效率与vector一样低。它常被用为实现栈和队列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值