STL(Standard Template Library)是C++标准庫的一部分(80%),是用C++ Template机制来表达泛型的庫。
STL,成功的将算法与数据结构分离,在没有效率损失的前提下,得到了及大的弹性。
六大组件
容器(Container)
算法(Algorithm)
迭代器(Iterator)
仿函数(Function object)
适配器(Adaptor)
空间配制器(allocator)
Set,Map都不能用push_back,push_front,因为它是自动排序的。
Sets/Multisets
内部的元素依据其值自动排序
Set内的相同数值的元素只能出现一次,Multisets内可包含多个数值相同的元素。
内部由二叉树实现,便于查找。
Maps/Multimaps
Map的元素是成对的键值/实值,内部的元素依据其值自动排序。
Map内的相同数值的元素只能出现一次,Multimaps内可包含多个数值相同的元素。
内部由二叉树实现,便于查找。
所有容器的共同操作
一。所有容器都提供了一个默认的构造函数,一个拷贝构造函数。
例:
list
....
vector
int array[]={1,2,3,4};
....
set
二。与大小相关的函数
size(),empty(),max_size()
三。返回迭代器的函数
begin(),end(),rbegin(),rend()
四。比较操作
==,!=,<,>,>=....
Vector详解:
capacity(),返回vector能够容纳的元素个数。
size(),返回vector内现有元素的个数。
赋值操作:
c1=c2; 把c2的全部元素指派给c1
c.assign(n,elem);复制n个elem,指派给c
c.assign(beg,end);将区间beg,end内的元素指派给c
c1.swap(c2);将c1,c2元素互换
swap(c1,c2);同上
元素存取
c.at(index);
c[index];
c.front();返回第一个元素
c.back();
插入和删除:
c.insert(pos.elem);
c.insert(pos,n.elem); 插入n个elem
c.insert(pos,beg,end); 在pos出插入beg,end区间内的所有元素。
c.push_back(elem);
c.pop_back();
c.erase(pos); 删除pos上的元素,返回下一个元素
c.erase(beg,end);
c.resize(num);将元素数量改为num,如果size变大了,多出来的新元素都要一default方式构建。
c.resize(num,elem);将元素数量改为num,如果size变大了,多出来的新元素是elem的副本。
c.clear();删除所有。
vector的reserve和resize
reserve只分配空间,而不创建对象,size()不变。而resize分配空间而且用空对象填充.
reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。
再者,两个函数的形式是有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。
vector有而deque无的:capacity(), reserve();
deque有而vector无的:push_front(elem), pop_front(); push_back(elem), pop_back();
STL提供的另两种容器queue、stack,其实都只不过是一种adaptor,它们简单地修饰deque的界面而成为另外的容器类型
List详解:
for_each (.begin(), .end(), “函数”);
count (.begin(), .end(), 100, jishuqi);
返回对象等于100的个数jishuqi值。
count_if() 带一个函数对象的参数(上面“100”的这个参数)。函数对象是一个至少带有一个operator()方法的类。这个类可以更复杂。
find(*.begin().*end(),“要找的东西”);
如果没有找到指出的对象,就会返回*.end()的值,要是找到了就返回一个指着找到的对象的iterator
fine_if();与count_if()类似,是find的更强大版本。
STL通用算法search()用来搜索一个容器,但是是搜索一个元素串,不象find()和find_if() 只搜索单个的元素。
search算法在一个序列中找另一个序列的第一次出现的位置。
search(A.begin(), A.end(), B.begin(), B.end());
在A中找B这个序列的第一次出现。
要排序一个list,我们要用list的成员函数sort(),而不是通用算法sort()。
list容器有它自己的sort算法,这是因为通用算法仅能为那些提供随机存取里面元素 的容器排序。
list的成员函数push_front()和push_back()分别把元素加入到list的前面和后面。你可以使用insert() 把对象插入到list中的任何地方。
insert()可以加入一个对象,一个对象的若干份拷贝,或者一个范围以内的对象。
list成员函数pop_front()删掉list中的第一个元素,pop_back()删掉最后一个元素。 函数erase()删掉由一个iterator指出的元素。还有另一个erase()函数可以删掉一个范围的元素。
list的成员函数remove()用来从list中删除元素。
*.remove("要删除的对象");
通用算法remove()使用和list的成员函数不同的方式工作。一般情况下不改变容器的大小。
remove(*.begin(),*.end(),"要删除的对象");
使用STL通用算法stable_partition()和list成员函数splice()来划分一个list。
stable_partition()是一个有趣的函数。它重新排列元素,使得满足指定条件的元素排在 不满足条件的元素前面。它维持着两组元素的顺序关系。
splice 把另一个list中的元素结合到一个list中。它从源list中删除元素。
Set Map详解:
STL map和set的使用虽不复杂,但也有一些不易理解的地方,如:
为何map和set的插入删除效率比用其他序列容器高?
为何每次insert之后,以前保存的iterator不会失效?
为何map和set不能像vector一样有个reserve函数来预分配数据?
当数据元素增多时(10000到20000个比较),map和set的插入和搜索速度变化如何?
C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般的平衡二叉树(AVL-树).
为何map和set的插入删除效率比用其他序列容器高?
大部分人说,很简单,因为对于关联容器来说,不需要做内存拷贝和内存移动。说对了,确实如此。map和set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。这里的一切操作就是指针换来换去,和内存移动没有关系。
为何每次insert之后,以前保存的iterator不会失效?(同解)
为何map和set不能像vector一样有个reserve函数来预分配数据?
究其原理来说时,引起它的原因在于在map和set内部存储的已经不是元素本身了,而是包含元素的节点。
其实你就记住一点,在map和set内面的分配器已经发生了变化,reserve方法你就不要奢望了。
详细的实现参看STL中的Allocator
当数据元素增多时(10000和20000个比较),map和set的插入和搜索速度变化如何?
如果你知道log2的关系你应该就彻底了解这个答案。在map和set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。
泛型算法:
所有算法的前两个参数都是一对iterators:[first,last),用来指出容器内一个范围内的元素。
每个算法的声明中,都表现出它所需要的最低层次的iterator类型。
70个算法:
accumulate() 元素累加
adjacent_difference() 相邻元素的差额
adjacent_find() 搜寻相邻的重复元素
binary_search() 二元搜寻
copy() 复制
copy_backward() 逆向复制
count() 计数
count_if() 在特定条件下计数
equal() 判断相等与否
equal_range() 判断相等与否(传回一个上下限区间范围)
fill() 改填元素值
fill_n() 改填元素值,n 次
find() 搜寻
find_if() 在特定条件下搜寻
find_end() 搜寻某个子序列的最后一次出现地点
find_first_of() 搜寻某些元素的首次出现地点
for_each() 对范围内的每一个元素施行某动作
generate() 以指定动作的运算结果充填特定范围内的元素
generate_n() 以指定动作的运算结果充填 n 个元素内容
includes() 涵盖於
inner_product() 内积
inplace_merge() 合并并取代(覆写)
iter_swap() 元素互换
lexicographical_compare() 以字典排列方式做比较
lower_bound() 下限
max() 最大值
max_element() 最大值所在位置
min() 最小值
min_element() 最小值所在位置
merge() 合并两个序列
mismatch() 找出不吻合点
next_permutation() 获得下一个排列组合
泛型演算法(Generic Algorithms)与 Function Obje4 cts
nth_element() 重新安排序列中第n个元素的左右两端
partial_sort() 局部排序
partial_sort_copy() 局部排序并复制到它处
partial_sum() 局部总和
partition() 切割
prev_permutation() 获得前一个排列组合
random_shuffle() 随机重排
remove() 移除某种元素(但不删除)
remove_copy() 移除某种元素并将结果复制到另一个 container
remove_if() 有条件地移除某种元素
remove_copy_if() 有条件地移除某种元素并将结果复制到另一个 container
replace() 取代某种元素
replace_copy() 取代某种元素,并将结果复制到另一个 container
replace_if() 有条件地取代
replace_copy_if() 有条件地取代,并将结果复制到另一个 container
reverse() 颠倒元素次序
reverse_copy() 颠倒元素次序并将结果复制到另一个 container
rotate() 旋转
rotate_copy() 旋转,并将结果复制到另一个 container
search() 搜寻某个子序列
search_n() 搜寻「连续发生 n 次」的子序列
set_difference() 差集
set_intersection() 交集
set_symmetric_difference() 对称差集
set_union() 联集
sort() 排序
stable_partition() 切割并保持元素相对次序
stable_sort() 排序并保持等值元素的相对次序
swap() 置换(对调)
swap_range() 置换(指定范围)
transform() 以两个序列为基础,交互作用产生第三个序列
unique() 将重复的元素摺叠缩编,使成唯一
unique_copy() 将重复的元素摺叠缩编,使成唯一,并复制到他处
upper_bound() 上限
-- 以下是 heap 相关演算法 --
make_heap() 制造一个 heap
pop_heap() 从 heap 内取出一个元素
push_heap() 将一个元素推进 heap 内
sort_heap() 对 heap 排序
以下内容来自 《More Effctive STL》:
● 标准STL序列容器:vector、string、deque和list。
● 标准STL关联容器:set、multiset、map和multimap。
● 非标准序列容器slist和rope。slist是一个单向链表,rope本质上是一个重型字符串。(“绳子
(rope)”是重型的“线(string)”。明白了吗?)
● 非标准关联容器hash_set、hash_multiset、hash_map和hash_multimap。
● vector
● vector作为标准关联容器的替代品。,有时候vector可以在时间和空间上都表现得比
标准关联容器好。
● 几种标准非STL容器,包括数组、bitset、valarray、stack、queue和priority_queue。
vector、list和deque提供给程序员不同的复杂度,因此应该这么用:vector是一种可以默认使用
的序列类型,当很频繁地对序列中部进行插入和删除时应该用list,当大部分插入和删除发生
在序列的头或尾时可以选择deque这种数据结构。
● 标准的连续内存容器是vector、string和deque。非标准的rope也是连续内存容器。
●表现为链表的容器——比如list和slist——是基于节点的,所有的标准关联容器也是(它们的典型实现是平衡树)。非标准的散列容器使用不同的基于节点的实现.
●用empty来代替检查size()是否为0
●避免使用vector