《STL Tutorial Reference》 Chapt 6 Containers
Chapt 6 STL Containers
Content included:
How to use, internal data structures, operations, and the performance: general abilities, advantages, and disadvantages of all container types.
Sepecial classes: container adapters(: stack, queue, priority queue), bitmaps, and valarrays.
6.1 通用容器能力与操作
每个容器都具备的能力:
- 所有容器提供值而非引用语义。当插入时,容器内部拷贝元素而非管理它们的引用。因此,STL容器存储和的元素必须能拷贝,即需要public copy constructor
- 通常,所有的元素都有其次序。
- 通常,操作并非安全。调用者必须确保操作的参数满足要求。使用STL不会抛出异常。
通用操作:
- 初始化:每个容器类提供一个default constructor, copy constructor, destructor, 以及用另一个容器元素、数组、标准输入来初始化的constructor.
ConType c ConType c1(c2) ConType c(beg, end) c.~ConType() c.size() c.empty() c.max_size() c1 == c2 c1 != c2 c1 < c2 c1 > c2 c1 <= c2 c1 >= c2 c1 = c2 assign operator c1.swap(c2) member function swap(c1, c2) global function c.begin() c.end() c.rbegin return reverse iterator for 1st element c.rend() c.insert(pos, elem) c.erase(beg, end) remove elements in range [beg, end) c.clear() remove all c.get_allocator()
说下几种特殊的初始化方法:
数组初始化:
int array[] = { 2, 3, 17} ..//std:set<int> c(array, array+sizeof(array)/sizeof(array[0]);
标准输入初始化:
std:deque<int> c((std::istream_iterator<int>(std::cin)), std::istream_iterator<int>());
6.2 Vector
模型:动态数组
提供随机访问。
容量:
capacity() 返回不重新分配内存的情况下最大可能的元素个数
max_size() 返回可以容纳的最大大小
这两个函数都是依赖于STL实现的
保留一定容量的以避免重新分配内存带来的耗时:
方式一:
std::vector<int> v;
v.reverve(80); //reverve memory for 80 elements
方式二:
std::vector<int> v(5);
//creates a vector and initializes it with five values, call 5 times the default constructor of type T
推荐第一种方式
元素访问:
c.at(idx) | return element in idx with range checking |
c[idx] | return element in idx with no range checking |
c.front() | return 1st element(no check 1st element exists) |
c.back() | return last element(no check last element exists) |
c.at(idx)可以进行越界检查,超出范围会抛出错误异常。
下面代码:
std::vector<Elem> coll; //empty vector
coll[5] = elem;//RUNTIME ERROR? undefine behavior
std::cout << coll.front();RUNTIME ERROR? undefine behavior
迭代器函数:
c.begin() |
c.end() |
c.rbegin() |
c.rend() |
插入和删除元素:
c.insert(pos, elem) | |
c.insert(pos, n, elem) | |
c.insert(pos, beg, end) | |
c.push_back(elem) | |
c.pop_back() | |
c.erase(pos) | |
c.erase(beg,end) | |
c.resize(num) | |
c.resize(num, elem) | |
c.clear() |
class vector<bool>
比通常是实现更节省空间,每个元素至少保留1bit
这样导致模板操作可能不适合vector<bool>
6.3 Deques
也是使用动态数组管理元素
deque典型的实现是用一束单个的block,第一block以一个方向增长,最后一个block以相反方向增长
和vector比较,操作只有2个不同:
- deque没有提供capacity()和reverve()函数
- deque提供了push_front()和pop_front()函数
6.4 List
插入和移除元素:
c.insert(pos, elem) | |
c.insert(pos, n, elem) | |
c.insert(pos, beg, end) | |
c.push_back(elem) | |
c.pop_back() | |
c.push_front(elem) | |
c.pop_back() | |
c.remove(val) | |
c.remove_if(op) | |
c.erase(pos) | |
c.erase(beg, end) | |
c.resize(num) | |
c.resize(num, elem) | |
c.clear() |
但是,上述函数没有提供移除某个值的第一次出现
移接函数 (Splice Functions)
c.unique() | 移除重复元素 |
c.unique(op) | |
c1.splice(pos,c2) | c2的所有元素移到c1的pos前 |
c1.splice(pos, c2, c2beg, c2end) | c2的[c2beg, c2end)范围内的元素移到c1的pos前 |
c.sort() | 按升序排序 |
c1.sort(op) | |
c1.merge(c2) | 合并2个有序list c1和c2 |
c1.merge(c2, op) | |
c.reverse() | 反转 |
6.5 Sets 和 Multisets
set通常实现为平衡二叉树(Balanced Binary Trees)
实际上,set和multiset典型的实现为红黑树(Red-black Trees)
自动排序的最大优点是搜索某个值时有很好的表现。
但是也有很大的限制,你不能直接改变元素的值,因为这可能会破坏正确的次序。因此要修改一个元素的值,你必须先移除拥有旧值的元素,然后插入一个拥有新值的元素。
- set和multiset不提供直接元素访问的操作
- 通过iterator的间接访问有限制:从iterator的观点看,元素的值是constant
set<Type> c | set<Type, op> c |
set<Type> c(op) | set<Type, op> c(op) |
set<Type> c1(c2) | set<Type, op> c1(c2) |
set<Type> c(beg, end) | set<Type, op> c(beg, end) |
set<Type> c(beg, end, op) | set<Type, op> c(beg, end, op) |
c.~set<Type>() | c.~set<Type, op>() |
特殊的搜索操作:
count(elem) | |
find(elem) | |
lower_bound(elem) | 返回>=elem的位置 |
upper_bound(elem) | 返回>elem的位置 |
equal_range(elem) | |
要理解lower_bound(elem), upper_bound(elem), equal_range(elem),看下面代码就清楚了:
#include <iostream>
#include <set>
using namespace std;
int main ()
{
set<int> c;
c.insert(1);
c.insert(2);
c.insert(4);
c.insert(5);
c.insert(6);
cout << "lower_bound(3): " << *c.lower_bound(3) << endl;
cout << "upper_bound(3): " << *c.upper_bound(3) << endl;
cout << "equal_range(3): " << *c.equal_range(3).first << " "
<< *c.equal_range(3).second << endl;
cout << endl; cout << "lower_bound(5): " << *c.lower_bound(5) << endl;
cout << "upper_bound(5): " << *c.upper_bound(5) << endl;
cout << "equal_range(5): " << *c.equal_range(5).first << " "
<< *c.equal_range(5).second << endl; system("PAUSE");
return 0;
}
插入和移除操作:
c.insert(elem) | |
c.insert(pos, elem) | |
c.insert(beg, end) | |
c.erase(elem) | |
c.erase(elem) | |
c.erase(pos) | |
c.erase(beg, end) | |
c.clear() |
注意,insert函数的返回类型不同:
- set
- pair<iterator, bool> insert(const value_type &elem);
- iterator insert(iterator pos_hint, const value_type& elem);
- multiset
- iterator insert(const value_type& elem);
- iterator insert(iteratir pos_hint, const value_type& elem);
set不提供remove()函数,而提供erase函数。
- 序列容器提供的erase()函数
- iterator erase(iterator pos);
- iterator erase(iterator beg, iterator end);
- 关联容器提供的erase()函数
- void erase(iterator pos)
- void erase(iterator beg, iterator end)
6.6 Map和Multimap
和set一样,通常map也是以平衡二叉树作为实现。
可以将set看作特殊的map:其key和value是相同的。
一点差别是:1)map的元素是key/value对 2)map可以作为关联数组
std::map<std::string,float> coll; // empty collection
/*insert "otto"/7.7 as key/value pair
*-first it inserts "otto"/float()
*-then it assigns 7.7
*/
coll["otto"] = 7.7;
总结:何时该使用何种容器?参考下表
- 默认情况下,你应该使用vector.它有最简单的内部数据结构并提供了随机访问。这样,数据访问是方便且灵活,并且数据处理也是足够快
- 如果你经常在序列开始和结尾插入/删除元素,你应该使用deque.另外,如果这是重要的:当元素移除时,由容器使用的内部存储量减少时,你也应使用deque。再者,因为vector通常使用一个block,而deque可能包含更多的元素,因为它使用多个block
- 如果你插入、移除或移动元素经常发生在容器中间,考虑使用list。list提供特殊的成员函数以常数时间来从一个容器移动元素到另一个。但是注意,因为List没有提供随机访问,当你只拥有list的起始,在访问元素时你可能遇到困难
- 像所有的node-based容器,list没有使指向元素的iterator无效,只要这些元素是容器的一部分。vector使得所有超出容量的iterator、指针、引用无效。deque当改变它们的size,也使相应的iterator、指针、引用无效。
- 如果你需要一个能handle exception的容器:每个操作或者成功或者无效,你应使用list或者关联容器。
- 如果你通常需要依据搜索准则搜索元素,使用set或multiset.
- 在搜索1000个元素时,O(Logn)理论上比O(n)快10倍,hash表通常比二叉树快5~10倍。如果hash容器可取得,你可以考虑使用
- 如果为了处理key/value对,使用map或multimap(或hash)
- 如果你需要一个字典,使用multimap
6.10 容器类内部定义细节:
6.10.1 Type Definitions
container::value_type
- 元素类型
- vector: typedef _Tp value_type;
- set/multiset:(记住这个value_type是const)
- typedef _Key key_type;
- typedef _Key value_type;
- map/multimap:
- typedef _Key key_type;
- typedef _Tp mapped_type;
- typedef pair<const _Key,_Tp> value_type;
- vector,deque,list,set/multiset,map/multimap,string提供
- container::reference
- 容器元素的引用
- 典型情况下为: container::value_type&
- vector,deque,list,set/multiset,map/multimap,string提供
- container::const_reference
- 容器const元素的引用
- 典型情况下为: cosnt container::value_type&
- vector,deque,list,set/multiset,map/multimap,string提供
- container::iterator
- iterator类型
- vector,deque,list,set/multiset,map/multimap,string提供
- container::const_iterator
- constant iterators类型.
- vector,deque,list,set/multiset,map/multimap,string提供
- container::reverse_iterator
- reverse iterators类型.
- vector,deque,list,set/multiset,map/multimap提供
- container::const_reverse_iterator
- constant reverse iterators类型.
- vector,deque,list,set/multiset,map/multimap,string提供
- container::size_type
- unsigned int类型 for size values.
- vector,deque,list,set/multiset,map/multimap,string提供
- container::difference_type
- signed int类型 for difference values.
- vector,deque,list,set/multiset,map/multimap,string提供
- container::key_type
- For sets and multisets, it is equivalent to value_type.
- set/multisets, map/multimap提供.
- container::mapped_type
- The type of the value of the elements of associative containers.
- map/multimap提供.
- container::key_compare
- The type of the comparison criterion of associative containers.
- set/multiset, map/multimap提供.
- container::value_compare
- The type of the comparison criterion for the whole element type. For sets and multisets, it is equivalent to key_compare. For maps and multimaps, it is an auxiliary class for a comparison criterion that compares
only the key part of two elements. Provided by sets, multisets, maps, and multimaps.
- The type of the comparison criterion for the whole element type. For sets and multisets, it is equivalent to key_compare. For maps and multimaps, it is an auxiliary class for a comparison criterion that compares
- container::allocator_type
- The type of the allocator.
- vector,deque,list,set/multiset,map/multimap,string提供
6.10.2 Construct, Copy, Destruct 操作
- container::container()
- explicit container::container(const CompFunc& op)
- explicit container::container(const container& c)
- explicit container::container(size_type num)
- container::container(size_type num, const T& value)
- container::container(InputIterator beg, InputIterator end)
- container::container(InputIterator beg, InputIterator end, const ComFunc& op)
- container::~container()
6.10.3 非修改操作
- size操作
- size_type container::size() const
- bool container::empty() const
- size_type container::max_size() const
- 以上vector,deque,list,set/multiset,map/multimap,string都提供
- capacity操作
- container::capacity() const
- vector,string提供
- container::reserve() const
- vector,sting提供
- container::capacity() const
- 比较操作
- bool operator ==(const container& c1, const container& c2)
- bool operator !=(const container& c1, const container& c2)
- bool operator > (const container& c1, const container& c2)
- bool operator < (const container& c1, const container& c2)
- bool operator >=(const container& c1, const container& c2)
- bool operator <=(const container& c1, const container& c2)
- 两个容器有相同数目的元素,并且按次序相等,返回true
- 关联容器的特殊非修改操作
- size_type container::count(const T& value) const
- 线性复杂度
- iterator container::find(const T& value)
- const_iterator container::find(const T& value) const
- find()算法的特殊版本
- log复杂度
- iterator container::lower_bound(const T& value)
- const_iterator container::lower_bound(const T& value)
- iterator container::upper_bound(const T& value)
- const_iterator container::upper_bound(const T& value)
- log复杂度
- pair<iterator, iterator>container::equal_range(const T& value)
- pair<const_iterator, const_iterator>container::equal_range(const T& value) const
- size_type container::count(const T& value) const
6.10.4 assignment操作
- container& container::operator=(const container& c)
- void container::assign(size_type num, const T& value)
- 将容器所有元素清空,并指派num个元素,值都为value
- void container::assign(InputIterator beg, InputIterator end)
- 以上两个assign函数只有vector,deque,list,string提供
- void container::swap(container& c)
- void swap(container& c1, container& c2)
6.10.5 直接访问操作
- reference container::at(size_type idx)
- const_reference container::at(size_type idx) const
- reference container::operator [](size_type idx)
- const_reference container::operator [](size_type idx) const
- T& map::operator[](const key_type& key)
- 此即关联数组,只有map提供
- reference container::front()
- const_reference container::front()
- vector, deque, list提供
- reference container::back()
- const_reference container::back()
- vector, deque, list提供
6.10.6 生成iterator的操作
- iterator container::begin()
- const_iterator container:: begin () const
- iterator container::end()
- const_iterator container::end() const
- reverse_iterator container::rbegin()
- const_reverse_iterator container::rbegin() const
- reverse_iterator container::rend()
- const_reverse_iterator container::rend() const
- 以上所有容器都提供
6.10.7 Insert / Remove 操作
insert:
- iterator container::insert(const T& value)
- set, map提供
- pair<iterator,bool> container::insert(const T& value)
- multiset, multimap提供
- iterator container::insert(iterator pos, const T& value)
- 所有容器都提供
- void container::insert(iterator pos, size_type num, const T& value)
- 仅顺序容器提供
- void container::insert(InputIterator beg, InputIterator end)
- 仅关联容器提供
- void container::insert(iterator pos, InputIterator beg, InputIterator end)
- 仅顺序容器提供
- void container::push_front(const T& value)
- void container::pop_front()
- 仅deque,list提供
- void container::push_back(const T& value)
- void container::pop_back()
- vector, deque, list,string提供
remove:
- void list::remove(const T& value)
- void list::remove_if(UnaryPredicate op)
- 仅list提供
- 删除所有list中值等于value的元素
- 顺序容器中唯一提供以值的方式删除的容器,其他顺序容器要以值方式删除,必须使用find()算法得到iterator
erase:
- size_type container::erase (const T& value)
- 关联容器提供
- void container::erase(iterator pos)
- void container::erase(iterator beg, iterator end)
- 关联容器提供
- iterator container::erase(iterator pos)
- iterator container::erase(iterator beg, iterator end)
- 顺序容器提供
resize:
- void container::resize(size_type num)
- void container::resize(size_type num, T value)
- 顺序容器提供..这个比较特别,可能引起iterator无效
clear:
- void container::clear()
- 所有容器都提供
6.10.8 List的特殊成员函数
- void list::unique()
- void list::unique(BinaryPredicate op)
- void list::splice(iterator pos, list& source)
- void list::splice(iterator pos, list& source, iterator sourcePos)
- void list::splice(iterator pos, list& source, iterator sourceBeg, iterator sourceEnd)
- void list::sort()
- void list::sort(CompFunc op)
- void list::merge(list& source)
- void list::merge(list& source, CompFunc op)
- 标准要求两list是已排序的,但是你也可以使用2未排序的list
- 未测试过有何区别(((!!!
- void list::reverse ()
6.10.9 Allocator支持
待续..