【C++ Primer 学习笔记】: 容器和算法之【顺序容器】
2015-11-17 15:59
531 查看
本系列博客主要是在学习 C++ Primer 时的一些总结和笔记。
【C++ Primer 学习笔记】: 容器和算法之【顺序容器】
本文地址:http://blog.csdn.net/shanglianlm/article/details/49888699
顺序容器
接受容器大小做形参的构造函数只适用于顺序容器,而关联容器不支持这种初始化。
• 元素类型必须支持赋值运算。
• 元素类型的对象必须可以复制。
引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。
除输入输出(IO)标准库类型之外,所有其他标准库类型都是有效的容器元素类型。
容器的容
vector 和 deque 容器的迭代器提供额外的运算
避免存储 end 操作返回的迭代器
不要存储 end 操作返回的迭代器。添加或删除 deque 或 vector 容器内的元素都会导致存储的迭代器失效。
导致死循环的错误示例
例如,考虑一个读取容器中每个元素的循环,对读出元素做完处理后,在原始元素后面插入一个新元素。
为了避免存储 end 迭代器,可以在每次做完插入运算后重新计算 end 迭代器值:
所有容器都通过比较其元素对来实现关系运算: ivec1 < ivec2
假设 ivec1 和 ivec2 都是 vector 类型的容器,则上述比较使用了内置 int 型定义的小于操作符。如果这两个 vector 容器存储的是 strings 对象,则使用 string 类型的小于操作符。
如果上述 vector 容器存储 Sales_item 类型的对象,则该比较运算不合法。因为 Sales_item 类型没有定义关系运算,所以不能比较存放 Sales_items 对象的容器:
赋值和 assign 操作使左操作数容器的所有迭代器失效。swap 操作则不会使迭代器失效。完成 swap 操作后,尽管被交换的元素已经存放在另一容器中,但迭代器仍然指向相同的元素。
由于 assign 操作首先删除容器中原来存储的所有元素,因此,传递给 assign 函数的迭代器不能指向调用该函数的容器内的元素。
带有一对迭代器参数的 assign 操作允许我们将一个容器的元素赋给另一个不同类型的容器。
关于 swap 的一个重要问题在于:该操作不会删除或插入任何
元素,而且保证在常量时间内实现交换。由于容器内没有移动
任何元素,因此迭代器不会失效。
size 和 capacity 的区别:
size 指容器当前拥有的元素个数;
capacity 则指容器在必须分配新存储空间之前可以存储的元素总数。
头文件
默认的 stack 和 queue 都基于 deque 容器实现,而 priority_queue 则在 vector 容器上实现。在创建适配器时,通过将一个顺序容器指定为适配器的第二个类型实参,可覆盖其关联的基础容器类型:
对于给定的适配器,其关联的容器必须满足一定的约束条件。stack 适配器所关联的基础容器可以是任意一种顺序容器类型。
因此,stack 栈可以建立在 vector、list 或者 deque 容器之上。
而 queue 适配器要求其关联的基础容器必须提供 push_front 运算,因此只能建立在 list 容器上,而不能建立在 vector 容器上。
priority_queue 适配器要求提供随机访问功能,因此可建立在 vector 或 deque 容器上,但不能建立在 list 容器上。
实例
声明语句:
【C++ Primer 学习笔记】: 容器和算法之【顺序容器】
本文地址:http://blog.csdn.net/shanglianlm/article/details/49888699
顺序容器
1 定义
头文件#include <vector> #include <list> #include <deque>
1-1 初始化
接受容器大小做形参的构造函数只适用于顺序容器,而关联容器不支持这种初始化。
1-2 容器内元素的类型约束
C++ 语言中,大多数类型都可用作容器的元素类型。容器元素类型必须满足以下两个约束:• 元素类型必须支持赋值运算。
• 元素类型的对象必须可以复制。
引用不支持一般意义的赋值运算,因此没有元素是引用类型的容器。
除输入输出(IO)标准库类型之外,所有其他标准库类型都是有效的容器元素类型。
容器的容
// note spacing: use ">>" not ">>" when specifying a container element type vector< vector<string> > lines; // vector of vectors
2 迭代器和迭代器范围
2-1 迭代器操作
vector 和 deque 容器的迭代器提供额外的运算
2-2 迭代器范围
左闭合区间3 顺序容器的操作
3-1 容器定义的类型别名
3-2 begin 和 end 成员
3-3 顺序容器中添加元素
避免存储 end 操作返回的迭代器
不要存储 end 操作返回的迭代器。添加或删除 deque 或 vector 容器内的元素都会导致存储的迭代器失效。
导致死循环的错误示例
例如,考虑一个读取容器中每个元素的循环,对读出元素做完处理后,在原始元素后面插入一个新元素。
vector<int>::iterator first = v.begin(), last = v.end(); // cache end iterator // diaster: behavior of this loop is undefined while (first != last) { // do some processing // insert new value and reassign first, which otherwise would be invalid first = v.insert(first, 42); ++first; // advance first just past the element we added }
为了避免存储 end 迭代器,可以在每次做完插入运算后重新计算 end 迭代器值:
// safer: recalculate end on each trip whenever the loop adds/erases elements while (first != v.end()) { // do some processing first = v.insert(first, 42); // insert new value ++first; // advance first just past the element we added }
3-4 关系操作符
C++ 语言只允许两个容器做其元素类型定义的关系运算。所有容器都通过比较其元素对来实现关系运算: ivec1 < ivec2
假设 ivec1 和 ivec2 都是 vector 类型的容器,则上述比较使用了内置 int 型定义的小于操作符。如果这两个 vector 容器存储的是 strings 对象,则使用 string 类型的小于操作符。
如果上述 vector 容器存储 Sales_item 类型的对象,则该比较运算不合法。因为 Sales_item 类型没有定义关系运算,所以不能比较存放 Sales_items 对象的容器:
3-5 容器大小的操作
3-6 访问元素
// check that there are elements before dereferencing an iterator or calling front or back if (!ilist.empty()) { // val and val2 refer to the same element list<int>::reference val = *ilist.begin(); list<int>::reference val2 = ilist.front(); // last and last2 refer to the same element list<int>::reference last = *--ilist.end(); list<int>::reference last2 = ilist.back(); }
3-7 删除元素
3-8 赋值与 swap
赋值和 assign 操作使左操作数容器的所有迭代器失效。swap 操作则不会使迭代器失效。完成 swap 操作后,尽管被交换的元素已经存放在另一容器中,但迭代器仍然指向相同的元素。
由于 assign 操作首先删除容器中原来存储的所有元素,因此,传递给 assign 函数的迭代器不能指向调用该函数的容器内的元素。
带有一对迭代器参数的 assign 操作允许我们将一个容器的元素赋给另一个不同类型的容器。
关于 swap 的一个重要问题在于:该操作不会删除或插入任何
元素,而且保证在常量时间内实现交换。由于容器内没有移动
任何元素,因此迭代器不会失效。
4 vector容器的自增长
4-1 capacity 和 reserve 成员
vector 类提供了两个成员函数:capacity 和 reserve 使程序员可与 vector 容器内存分配的实现部分交互工作。capacity 操作获取在容器需要分配更多的存储空间之前能够存储的元素总数,而 reserve 操作则告诉 vector 容器应该预留多少个元素的存储空间。size 和 capacity 的区别:
size 指容器当前拥有的元素个数;
capacity 则指容器在必须分配新存储空间之前可以存储的元素总数。
5 容器的选用
通常来说,除非找到选择使用其他容器的更好理由,否则 vector 容器都是最佳选择。6 容器适配器
头文件
#include <stack> #include <queue>
默认的 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 容器上。
6-1 栈适配器
实例
// number of elements we'll put in our stack const stack<int>::size_type stk_size = 10; stack<int> intStack; // empty stack // fill up the stack int ix = 0; while (intStack.size() != stk_size) // use postfix increment; want to push old value onto intStack intStack.push(ix++); // intStack holds 0...9 inclusive int error_cnt = 0; // look at each value and pop it off the stack while (intStack.empty() == false) { int value = intStack.top(); // read the top element of the stack if (value != --ix) { cerr << "oops! expected " << ix << " received " << value << endl; ++error_cnt; } intStack.pop(); // pop the top element, and repeat } cout << "Our program ran with " << error_cnt << " errors!" << endl;
声明语句:
stack<int> intStack; // empty stack
6-2 队列和优先级队列
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性
- C++ Custom Control控件向父窗体发送对应的消息