您的位置:首页 > 其它

Primer STL笔记第二部分容器与算法

2016-08-13 18:18 239 查看
9.1顺序容器的定义

要定义一个容器类型的对象笔下那个先包含相关的容器头文件。

所有容器类型都定义了默认构造函数,用于创建指定类型的空容器对象。默认构造函数不带参数。为了使程序更清晰、简短,容器类型最常用的构造函数是默认构造函数。在大多数的程序中,使用默认构造函数能达到最佳运行时性能,并且使容器更容易使用。

下面一些例子 将一个容器复制给另一个容器时,类型必须匹配:容器类型和元素类型都必须相同。

vector<int> ivec;

vector<int> ivec2(ivec); // ok: ivec is vector<int>

list<int> ilist(ivec); // error: ivec is not list<int>

vector<double> dvec(ivec); // error: ivec holds int not double

初始化为一段元素的副本
尽管不能直接将一种容器内的元素复制给另一种容器,但系统允许通过传递一对迭代器(第 3.4 节)间接实现该实现该功能。使用迭代器时,不要求容器类型相同。容器内的元素类型也可以不相同,只要它们相互兼容,能够将要复制的元素转换为所构建的新容器的元素类型,即可实现复制

// initialize slist with copy of each element of svec

list<string> slist(svec.begin(), svec.end());

// find midpoint in the vector

vector<string>::iterator mid = svec.begin() + svec.size()/2;

// initialize front with first half of svec: The elements up to but

not including *mid

deque<string> front(svec.begin(), mid);

// initialize back with second half of svec: The elements *mid

through end of svec

deque<string> back(mid, svec.end());

回顾一下指针,我们知道指针就是迭代器,因此允许通过使用内置数组中的
一对指针初始化容器也就不奇怪了:
char *words[] = {"stately", "plump", "buck", "mulligan"};
// calculate how many elements in words
size_t words_size = sizeof(words)/sizeof(char *);
// use entire array to initialize words2
list<string> words2(words, words + words_size);//还是begin 到end

创建容器时,除了指定元素个数,还可选择是否提供元素初始化式。我们也可以只指
4000
定容器大小

不提供元素初始化式时,标准库将为该容器实现值初始化(3.3.1&nbps;节)。采用这种类型的初始化,元素类型必须是内置或复合类型,或者是提供了默认构造函数的类类型。如果元素类型没有默认构造函数,则必须显式指定其元素初始化式。接受容器大小做形参的构造函数只适用于顺序容器,而关联容器不支持这种初始化。

因为容器受容器元素类型的约束,所以可定义元素是容器类型的容器

vector< vector<string> > lines; // vector of vectors

迭代器与迭代器范围

每种容器类型都提供若干共同工作的迭代器类型。与容器类型一样,所有迭代器具有相同的接口

常用迭代器运算:

*iter 返回迭代器 iter 所指向的元素的引用

iter->mem 对 iter 进行解引用,获取指定元素中名为 mem 的成员。等效于(*iter).mem

++iter

iter++ 给 iter 加 1,使其指向容器里的下一个元素

--iter
iter--
给 iter 减 1,使其指向容器里的前一个元素

iter1 ==
比较两个迭代器是否相等(或不等)。当两个迭代器指向同一个

iter2 容器中的同一个元素,或者当它们都指向同一个容器的超出末端的下一位置时,两个迭代器相等
iter1 !=
iter2

vector 和 deque 容器的迭代器提供额外的运算

iter + n iter-n 、iter1 +=iter2 、iter1 -=iter2 、iter1 -iter2(only)、关系操作符:>, >=,<, <=(only)、

迭代器 first 和 last 如果满足以下条件,则可形成一个迭代器范围:

• 它们指向同一个容器中的元素或超出末端的下一位置。

• 如果这两个迭代器不相等,则对 first 反复做自增运算必须能够到达 last。换句话说,在容器中,last 绝对不能位于 first 之前。

使用左闭合区间的编程意义因为左闭合区间有两个方便使用的性质,所以标准库使用此烦区间。假设first 和 last 标记了一个有效的迭代器范围,于是:1. 当 first 与 last 相等时,迭代器范围为空;2. 当 first 与不相等时,迭代器范围内至少有一个元素,而且
first 指向该区间中的第一元素。此外,通过若干次自增运算可以使 first 的值不断增大,直到 first == last 为止。





例子:slist.insert(slist.end(), sarray, sarray+4);
list<string>::iterator slist_iter = slist.begin();
// insert last two elements of sarray before slist_iter
slist.insert(slist_iter, sarray+2, sarray+4);

容器关系操作符

所有的容器类型都支持用关系操作符(第 5.2 节)来实现两个容器的比较。显比较的容器必须具有相同的容器类型,而且其元素类型也必须相同





capacity 和reserve

弄清楚容器的 capacity(容量)与 size(长度)的区别非常重要。size 指容器当前拥有的元素个数;而 capacity 则指容器在必须分配新存储空间之前可以存储的元素总数。空
vector 容器的 size 是 0,而标准库显然将其 capacity 也设置为 0。当程序员在 vector 中插入元素时,容器的 size 就是所添加的元素个数,而其 capacity 则必须至少等于 size,但通常比 size 值更大。

ivec.reserve(50); // sets capacity to at least
50; might be more

插入操作如何影响容器的选择

list容器是不连续的内存区域,向前向后历遍元素都可以,任何位置insert或erase都高效,除去容器尾部,其他位置上的插入删除操作都要求移动被插入元素的右边的所有元素。(就是右边的移动)


与 vector 容器一样,在 deque 容器的中间 insert 或 erase 元素效率比较低。

• 不同于 vector 容器,deque 容器提供高效地在其首部实现 insert 和erase 的操作,就像在容器尾部的一样。

• 与 vector 容器一样而不同于 list 容器的是, deque 容器支持对所有元素的随机访问。

• 在 deque 容器首部或尾部插入元素不会使任何迭代器失效,而首部或尾部删除元素则只会使指向被删除元素的迭代器失效。在 deque 容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器都失效

容器的选择提示:

1. 如果程序要求随机访问元素,则应使用 vector 或 deque 容器。
2. 如果程序必须在容器的中间位置插入或删除元素,则应采用 list 容器。
3. 如果程序不是在容器的中间位置,而是在容器首部或尾部插入或删除元
素,则应采用 deque 容器。
4. 如果只需在读取输入时在容器的中间位置插入元素,然后需要随机访问元
素,则可考虑在输入时将元素读入到一个 list 容器,接着对此容器重新
排序,使其适合顺序访问,然后将排序后的 list 容器复制到一个 vector
容器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: