您的位置:首页 > 编程语言 > C语言/C++

[C++]标准库类型容器

2016-11-05 20:15 288 查看
update:2016/11/16

1.标准库类型
vector

vector
能够容纳绝大多数类型的对象作为其元素,但是由于引用并不是对象,因此不存在包含引用的
vector
。除此之外,其他大多数(非引用)内置类型和类类型都可以作为
vector
的元素,这也包含
vector


1.定义和初始化
vector

vector
作为一个类模板,本身不会指定类型,而必须要为其指定类型。例如:

vector<int> ivec;  //保存int类型的对象
vector<Sales_item> Sales_vec; //保存Sales_item类型的对象
vector<vector<string>> file; //保存vector对象的vector


初始化一个
vector
对象的常用方法如下:

初始化
vector
语句
含义解释
vector<T> v1
v1
是一个空
vector
,执行默认初始化
vector<T> v2(v1)
v2
使用
v1
的值初始化,包含了
v1
的所有元素
vector<T> v2=v1
v2
v1
的拷贝,包含了
v1
的所有元素
vector<T> v3(n)
v3
包含了
n
个元素,执行了值初始化
vector<T> v4(n,val)
v4
包含了
n
个重复的元素,每个元素的值都是
val
vector<T> v5{a,b,c...}
v5
的元素按顺序赋予初始值,执行列表初始化
vector<T> v5={a,b,c...}
v5
使用列表的拷贝进行初始化。

1. 默认初始化

vector
默认初始化可以提供一个空的容器,方便之后对其进行任何允许的操作。

vector<int> vector1;


2. 拷贝初始化

vector
执行拷贝初始化可以在初始化时将一个已存在的
vector
元素的值拷贝给新的
vector
对象。此时新的
vector
中的元素就是原
vector
对象对应元素的副本。

//assume that an int vector {1,2,3,4,5} called vector1 has been defined.
//then the following codes are equivalent to each other.
vector<int> vector2=vector1;
vector<int> vector3(vector1);
vector<int> vector4{vector1};


拷贝初始化时,两个
vector
对象的类型必须相同。

3. 列表初始化

vector
执行列表初始化时,可以用花括号
{}
将0个或多个初始元素值括起来,使用其在为新的
vector
对象初始化的同时为其元素赋予初值。

vector<int> vector5{1,2,5,8,0};


4. 值初始化

vector
执行值初始化,可以用圆括号
()
vector
容纳的元素数量和所有元素的统一值括起来,使用其在为新的
vector
对象初始化的同时,创建指定数量的元素。

在为
vector
进行值初始化时,首先由编译器创建一个经过初始化的元素初值,并将其赋给容器中的所有元素。

可以将元素值省略,即用括号
()
vector
对象容纳的元素数量括起来。在缺省元素初值的情况下,元素初值由
vector
对象中的元素类型决定:如果
vector
对象的元素是内置类型,则元素初始值设为
0
;如果元素是某种类类型,则元素由类的默认构造函数进行初始化。总之,在缺省元素初值的情况下,创建一个经过默认初始化的元素初值,并将其赋给容器中的所有元素。

vector<int> vector6(10);
vector<int> vector7(10,12);


5.构造还是初始值列表?

初始化的真实含义依赖于传递初始值时使用的是花括号
{}
亦或是圆括号
()
:

()
表示使用参数来构造一个
vector
对象。

{}
表示参数是一个初始值列表

//the deference between () and {}
vector<int> myVector1(10,3); //10 elements:3,3,3,3,3,3,3,3,3,3
vector<int> myVector2{10,3}; //2 elements:10,3


2.
vector
的迭代器

迭代器(iterator)是一种能够检查容器内元素并遍历元素的数据类型。

如同我们使用过的指针[/b],迭代器可以提供对对象的间接访问。事实上,从面向对象的角度而言,迭代器是一个基类,而指针则是这个基类的一个派生类。通过使用迭代器,我们可以在不知道对象内部表示的情况下(间接)按照一定的顺序访问一个容器的所有元素(遍历)。

2.1
vector
迭代器的使用

和指针不一样的是,我们可以不必关注元素的地址。
vector
在拥有迭代器的同时,还提供了返回迭代器的成员函数(运算符)。

1.
begin
和end

begin
成员返回指向头元素的迭代器。

end
成员返回指向尾元素的下一位置的迭代器(尾后迭代器)。

vector<T> myVec = {1, 2, 3, 4, 5}
auto begin = myVec.begin(), end = myVec.end();


如果调用
begin()
end()
的是空容器,则二者都返回尾后迭代器。

2.
vector
迭代器支持的运算

我们提到了
vector
的迭代器事实上是一种数据类型,于是对于这样的一个数据类型一定支持一定的运算(操作),下面列出
vector
的迭代器所有支持的运算(以下
iter
代表某个迭代器类型变量):

运算符操作
*iter
对迭代器
iter
解引用
iter->mem
解引用
iter
名为
mem
的成员,相当于
(*iter).mem
iter++
iter
指示容器中的下一个元素
iter--
iter
指示容器中的上一个元素
iter + n
iter
指示原位置向下移动了
n
个元素
iter - n
iter
指示原位置向上移动了
n
个元素
iter += n
iter + n
的结果赋给
iter
iter -= n
iter - n
的结果赋给
iter
iter1 - iter2
两个指示同一容器的迭代器相减得到所指示元素之间的距离
iter1 == iter2
判断两个迭代器是否指示同一个元素或相同容器的尾后迭代器
iter1 != iter2
判断两个迭代器是否指示同一个元素或相同容器的尾后迭代器
>,>=,<,<=
两个指示同一容器的迭代器,
iter1
指示的元素在
iter2
指示元素 之后,就说
iter1 > iter2

2.2 迭代器类型

一般来说,我们无需知道
vector
的迭代器的精确类型。想要获得一个指示
int
向量的通常做法会是这样:

// to get an iterator of iVec;
vector<int> iVec{1, 2, 3, 4, 5};
// use type auto to declare the iterator;
auto bg = ivec.begin();
int n = 2;
bg += n;


而实际上,在
vector
中(所有拥有迭代器的标准库类型都如此)使用
iterator
const_iterator
表示迭代器的类型。
const_iterator
类似于我们熟悉的常量指针(顶层
const
),能读取但不能修改它所指示的元素值。

如果容器是一个常对象,则只能使用
const_iterator
;如果容器不是常对象,则既可以使用
iterator
也可以使用
const_iterator
,唯一的区别在于前者指示的对象可读可写,而后者指示的对象只可读不可写

begin()
end()
运算符返回的具体类型由容器对象是否为常对象决定:如果是常对象,
begin()
end()
返回
const_iterator
;否则返回
iterator


3.迭代器的失效

任何一个可能改变
vector
对象容量的操作都会使该
vector
对象的迭代器失效。

3.
vector
上的一些操作

操作说明
vector.empty()
如果
vector
为空容器,返回
true
,否则返回
false
vector.size()
返回
vector
中的元素个数
vector.push_back(t)
vector
的尾端(拷贝地)添加一个值为
t
的元素,返回指向新添加元素的迭代器
vector.emplace_back(args)
vector
的尾端(构造地)添加一个由
arg
创建的元素,返回指向新添加元素的迭代器
vector
返回
vector
中第
n
个位置上元素的引用

2.标准库类型容器概述

容器(container)是包含对象的数据结构类模板。把数组(array)、队列(queue)、链表(list)、堆栈(stack)、树(tree)、图(tree)等数据结构中的每个节点(都是对象)组织起来,称为一个新的对象。如果抽象了这些数据元素的具体类型,只关心结构的组织,就成为一个类模板。标准模板库[/b](standard template library,STL)提供的标准库类型容器就是这样一个常用数据结构的类模板。

分类

标准库容器分为三大类:

顺序容器(sequential_container)

向量(vector)

双向队列(double_ended queue)

双向链表(doubly_linked list)

单向链表(linked list)

数组(array)

字符串(string)

关联容器[/b](associative container)

映射 (map)

映射 (multimap)

集合 (set)

集合 (multiset)

容器适配器[/b](container adaptor)

堆栈 (stack)

队列 (queue)

优先队列 (priority queue)

3.顺序容器

1.顺序容器概述

顺序容器[/b]是一种元素之间有顺序关系的线性表,是一种线性结构的可序群集。顺序容器为程序员提供了控制元素存储顺序访问顺序的能力,这种顺序不依赖于元素的值,而是与元素加入容器时的位置相对应。

标准容器库中的所有顺序容器都提供了快速顺序访问元素的能力,但是不同的容器在向容器中增删元素或是非顺序访问元素方面略有差异。

要使用不同的顺序容器,只需要包含不同的头文件即可。

容器头文件含义特性
vector
<vector>
可变大小数组支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。
deque
<deque>
双端队列支持快速随机访问。在头尾位置插入或删除元素很快。
list
<list>
双向链表只支持双向顺序访问。 在任何位置进行插入/删除操作速度都很快。
forward_list
<forward_list>
单向链表只支持单向顺序访问。在任何位置进行插入/删除操作速度都很快。
array
<array>
固定大小数组支持快速随机访问。不能添加或删除元素。

2.顺序容器的选择

除非有很好的理由选择其他容器,否则应当使用
vector


以下是一些选择顺序容器的基本原则:

除非你有很好的理由选择其他容器,否则应使用
vector


如果你的程序有很多小的元素,且空间的额外开销很重要,则不要使用
list
forward_list


如果程序要求随机访问元素,应使用
vector
deque


如果程序只有在读取输入时才需要在容器中间位置插入元素,则

首先,确定是否真的需要在容器中间位置添加元素。当处理输入数据时,通常可以很容易地向
vector
追加数据,然后再调用标准库的
sort
函数来重排容器中的元素,从而避免在中间位置添加元素。

如果必须在中间位置插入元素,考虑在输入截断使用
list
,一旦输入完成,将
list
中的内容拷贝到一个
vector
中。

3.顺序容器的使用(一)

4.顺序容器的操作

把所有顺序容器支持的操作列表如下:

vector
deque
list
forward_list
array
构造函数
Container con
Container con1(con2)
Container con(beg,end)
×
Container con{a,b,c...}
赋值与
swap
con1 = con2
con = {a,b,c...}
×
con1.swap(con2)
swap(con1,con2)
con.assign(beg,end)
×
con.assign(initial_list)
×
con.assign(n,t)
×
大小`
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐