第12章 理解容器与迭代器
------------------------------------------------------------------------------------------------------------------------------------------------------
1、迭代器(五大类):
(1)五大类:
读迭代器(输入迭代器)
写迭代器(输出迭代器)
前向迭代器
双向迭代器
随机访问迭代器
(2)公共迭代器typedef和方法
iterator、const_iterator
reverse_iterator、const_reverse_iterator
方法: begin()、end() (半开区间)
cbegin()、cend() (const)
注:end()返回的迭代器越过了vector容器的尾部,而不是引用容器中的最后一个元素
注:只有顺序容器、关联容器和无序关联容器提供了迭代器。容器适配器和bitset类都不支持迭代元素
------------------------------------------------------------------------------------------------------------------------------------------------------
2、C++11的变化
(1)引入无序关联容器(散列表)
(2)STL容器都包含了移动构造函数和移动赋值运算符,提高了性能。例如:
原: Element myElement(12, "Twelve");
vec.push_back(myElement);
C++11: vec.push_back({12, "Twelve"}); //等价于 vec.push_back(Element(12, "Twelve"));
// Or
vec.emplace_back(12, "Twelve");
------------------------------------------------------------------------------------------------------------------------------------------------------
3、顺序容器(一):vector 容器
(1)格式: template <class T, class Allocator = allocator<T> > class vector;
----------------------------------------------------------------------------------------------------------------------------------------------
(2)创建: 1)基本创建: vector<double> doubleVector(10); // Create a vector of 10 doubles.
2)指定初始值: vector<double> doubleVector(10, 0.0); // 10 doubles of value 0.0
----------------------------------------------------------------------------------------------------------------------------------------------
(3)访问元素: operator[]运算符: 类似于数组索引,不执行边界检查
at(): 等同于operator[]运算符,但是会执行边界检查
front(): 返回第一个元素
back(): 返回最后一个元素
----------------------------------------------------------------------------------------------------------------------------------------------
(4)动态长度: vector<double> doubleVector; // Create a vector with zero elements.
1)push_back(); doubleVector.push_back(temp);
2)size(); for (size_t i = 0; i < doubleVector.size(); i++)
----------------------------------------------------------------------------------------------------------------------------------------------
(5)构造函数: 1)默认: 默认的构造函数创建一个带有0个元素的vector
如果没有提供默认值,那么新对象通过0初始化
3)初始化 initializer_list参数(C++11): vector<int> intVector({1,2,3,4,5,6});
统一初始化: vector<int> intVector = {1,2,3,4,5,6};
4)堆分配: vector<Element>* elementVector = new vector<Element>(10);
delete elementVector; //通过delete(而不是delete[])释放vector,因为vector是一个基本类型,而非数组类型
5)堆分配(使用智能指针) shared_ptr<vector<Element> > elementVector(new vector<Element>(10));
----------------------------------------------------------------------------------------------------------------------------------------------
(6)复制和赋值:1)assign(); 删除所有现有的元素,添加任意数目的新元素
2)swap(); 交换两个vector的内容
----------------------------------------------------------------------------------------------------------------------------------------------
(7)迭代器:iterator: for (vector<double>::iterator iter = doubleVector.begin();
iter != doubleVector.end(); ++iter)
{
*iter /= max;
cout << *iter << " ";
}
注:1)尽量使用前递增而不要使用后递增,更为高效。因为iter++必须返回一个新的迭代器对象,而++iter只是返回对iter的引用
2)vector迭代器是随机访问的,可以向前向后移动,而且还可以随意跳跃:--iter;
------------------------------------------------------------------------------------------------------
1)使用auto关键字 for (auto iter = doubleVector.begin();
iter != doubleVector.end(); ++iter)
{
*iter /= max;
cout << *iter << " ";
}
------------------------------------------------------------------------------------------------------
2)基于区间的for循环 for (auto& d : doubleVector)
{
d /= max;
cout << d << " ";
}
------------------------------------------------------------------------------------------------------
3)访问对象元素中的字段 vector<string> stringVector(10, "hello");
for (auto it = stringVector.begin(); it != stringVector.end(); ++it)
{
it->append(" there");
}
// 或
vector<string> stringVector(10, "hello");
for (auto& str : stringVector)
{
str.append(" there");
}
----------------------------------------------------------------------------------------------------------------------------------------------
(8)迭代器:const_iterator 注:不能通过const_iterator修改元素
cbegin()、cend() vector<string> stringVector(10, "hello");
for (auto iter = stringVector.cbegin();
iter != stringVector.cend(); ++iter)
{
cout << *iter << endl;
}
----------------------------------------------------------------------------------------------------------------------------------------------
(9)添加和删除元素
push_back()、pop_back() 追加、删除
insert() (5种形式)从任意位置插入元素
insert(const_iterator pos, const T& x); //将值x插入位置pos
insert(const_iterator pos, size_type n, const T& x); //将值x在位置pos插入n次
insert(const_iterator pos, InputIterator first, InputIterator last); //将范围first,last内的元素插入位置pos
erase() (2种形式)从任意位置删除元素
clear() 删除所有元素
----------------------------------------------------------------------------------------------------------------------------------------------
(10)大小和容量
size() 返回元素的个数
capacity() 返回在重分配之前可以保存的元素个数。因此在重分配之前还能插入的元素个数为 capacity()-size()
empty() 查询是否为空
reserve() 分配保存指定数目元素的足够空间(不会创建真正的元素,因此不要越过vector大小访问元素)
resize() 指定vector要保存的元素数目
----------------------------------------------------------------------------------------------------------------------------------------------
(11)vector<bool>特化
flip() 取反
注:除非真的需要使用动态大小的位字段,否则应该避免使用vector<bool>,而是使用bitset
------------------------------------------------------------------------------------------------------------------------------------------------------
3、顺序容器(二):list
(1)描述: 双向链表 不提供operator[]的随机访问操作,只有通过迭代器才能访问单个元素
(2)访问元素 front() 返回list的第一个元素的引用
back() 返回list的最后一个元素的引用
begin() 返回第一个元素的迭代器
end() 返回最后一个元素之后一个元素的迭代器
(3)迭代器 不能进行加减操作和其他指针运算:可以通过++iter或--iter的方式遍历,而不能使用 iter+n或iter-n等
(4)添加和删除 push_front 在首端追加
pop_front 在首端移除
注:list支持和vector一样的添加和删除元素的方法
list适用于在数据结构上执行很多插入和删除操作,但不需要基于索引快睡访问元素的应用程序
(5)大小和容量 注:支持size()、empty()、resize()
不支持reserve()、capacity()
(6)特殊list操作
splice() 插入
remove()、remove_if() 从list中删除特定元素
unique() 从list删除连续重复元素
merge() 合并灵感list
sort() 对list中的元素执行稳定排序操作
reverse() 翻转list中元素的顺序
------------------------------------------------------------------------------------------------------------------------------------------------------
4、顺序容器(三)
(1)deque 双头序列 几乎和vector是等同的,使用得少。不要求元素连续保存在内存中
(2)array(C++11) 数组 和vector类似,区别在于大小固定的,这个类的目的是让array能分配在栈上,而不是像vector总是需要访问堆
(3)forward_list(C++11) 单链表 和list类似,区别在于只支持前向迭代
------------------------------------------------------------------------------------------------------------------------------------------------------
5、容器适配器
(1)queue 队列 template <class T, class Container = deque<T> > class queue;
(2)priority_queue 优先级队列 template <class T, class Container = vector<T>,class Compare = less<T> >;
(3)stack 栈 template <class T, class Container = deque<T> > class stack;
------------------------------------------------------------------------------------------------------------------------------------------------------
5、关联容器(一)
(1)pair工具类 <utility> template <class T1, class T2> struct pair;
注:将两个可能属于不同类型的值组合起来,通过first和second公共数据成员访问这两个值
pair<string, int> myPair("hello", 5);
myOtherPair.first = "hello";
myOtherPair.second = 6;
------------------------------------------------------------------------------------------------------------------------------------------------------
6、关联容器(二):map
(1)插入元素 1)insert()
2)operator[]
(2)访问元素 1)operator[]
2)find()
3)count() 查找是否存在具有给定键的元素
(3)删除元素 1)erace()
------------------------------------------------------------------------------------------------------------------------------------------------------
7、关联容器(三):set
------------------------------------------------------------------------------------------------------------------------------------------------------
8、(C++11)无序关联容器/哈希表/散列表
------------------------------------------------------------------------------------------------------------------------------------------------------
9、其他容器:bitset
------------------------------------------------------------------------------------------------------------------------------------------------------
(done)