http://blog.csdn.net/amin2001/article/details/8063
STL容器在被添加时(通过insert、push_front、push_back等)自动扩展它们自己来容纳新对象。这工作的很好,有些程序员因为这个信仰而被麻痹,认为他们不必担心要为容器中的对象腾出空间,因为容器自己可以照顾好这些。如果是那样就好了!当程序员想向容器中插入对象但并没有告诉STL他们所想的时,问题出现了。这是一个常见的可以自我表现的方法:
int transmogrify(int x); // 这个函数从x // 产生一些新值 vector<int> values; ... // 把数据放入values vector<int> results; // 把transmogrify应用于 transform(values.begin(), values.end(), // values中的每个对象 results.end(), // 把这个返回的values transmogrify); // 附加到results // 这段代码有bug!
在本例中,transform被告知它的目的区间是从results.end()开始的,所以那就是开始写在values的每个元素上调用transmogrify的结果的地方。就像所有使用目标区间的算法,transform通过对目标区间的元素赋值的方法写入结果,transform会把transmogrify应用于values[0]并把结果赋给*results.end()。然后它会把transmogrify应用于value[1]并把结果赋给*(results.end()+1)。那只能带来灾难,因为在*results.end()没有对象,*(results.end()+1)也没有!调用transform是错误的,因为它会给不存在的对象赋值。(条款50解释了STL的一个调试实现怎么在运行期检测这个问题。)犯了这种错误的程序员几乎总是以为他们调用算法的结果能插入目标容器。如果那是你想要发生的,你就必须说出来。STL是一个库,不是一个精神。在本例中,说“请把transform的结果放入叫做results容器的结尾”的方式是调用back_inserter来产生指定目标区间起点的迭代器:
vector<int> results; // 把transmogrify应用于 transform(values.begin(), values.end(), // values中的每个对象, back_inserter(results), // 在results的结尾 transmogrify); // 插入返回的values
在内部,back_inserter返回的迭代器会调用push_back,所以你可以在任何提供push_back的容器上使用back_inserter(也就是任何标准序列容器:vector、string、deque和list)。如果你想让一个算法在容器的前端插入东西,你可以使用front_inserter。在内部,front_inserter利用了push_front,所以front_insert只和提供那个成员函数的容器配合(也就是deque和list):
... // 同上 list<int> results; // results现在是list transform(values.begin(), values.end(), // 在results前端 front_inserter(results), // 以反序 transmogrify); // 插入transform的结果
因为front_inserter用push_front把每个对象添加到results,results中的对象顺序会和values中对应的对象顺序相反。这也是为什么front_inserter没有back_inserter那么常用的原因之一。另一个原因是vector不提供push_front,所以front_inserter不能用于vector。
如果你要transform把输出结果放在results前端,但你也要输出和values中对应的对象顺序相同,只要以相反的顺序迭代values:
list<int> results; // 同上 transform(values.rbegin(), values.rend(), // 在results前端 front_inserter(results), // 插入transform的结果 transmogrify); // 保持相对的对象顺序
front_inserter让你强制算法在容器前端插入它们的结果,back_inserter让你告诉它们把结果放在容器后端,有点惊人的是inserter允许你强制算法把它们的结果插入容器中的任意位置:
vector<int> values; // 同上 ... vector<int> results; // 同上,除了现在 ... // 在调用transform前 // results已经有一些数据 transform(values.begin(), values.end(), // 把transmogrify的 inserter(results, results.begin() + results.size()/2), // 结果插入 transmogrify); // results的中间
不管你是否使用了back_inserter、front_inserter或inserter,每次对目的区间的插入只完成一个对象。条款5解释了对于连续内存容器(vector、string和deque)来说这可能很昂贵,但条款5的建议解决方法(使用区间成员函数)不能应用于使用算法来完成插入的情况。在本例中,transform会对目的区间每次写入一个值,你无法改变。
当你要插入的容器是vector或string时,你可以通过按照条款14的建议最小化这个代价,预先调用reserve。你仍然要承受每次发生插入时移动元素的开销,但至少你避免了重新分配容器的内在内存:
vector<int> values; // 同上 vector<int> results; ... results.reserve(results.size() + values.size()); // 确定results至少 // 还能装得下 // values.size()个元素 transform(values.begin(), values.end(), // 同上, inserter(results, results.begin() + results.size() / 2),// 但results transmogrify); // 没有任何重新分配操作
当使用reserve来提高一连串插入的效率时,总是应该记住reserve只增加容器的容量:容器的大小仍然没有改变。即使调用完reserve,当你想要让容器把新元素加入到vector或string时,你也必须对算法使用插入迭代器(比如,从back_inserter、front_inserter或inserter返回的迭代器之一)。
要把这些完全弄清楚,这里有一个提高本条款开始时的那个例子的效率的错误方法(就是我们把transmogrify作用于values里的数据的结果附加到results的那个例子):
vector<int> values; // 同上 vector<int> results; ... results.reserve(results.size() + values.size()); // 同上 transform(values.begin(), values.end(), // 写入transmogrify的结果 results.end(), // 到未初始化的内存 transmogrify); // 行为未定义!
在这段代码中,transform愉快地试图对results尾部的原始的、未初始化的内存赋值。通常,这会造成运行期错误,因为赋值只在两个对象之间操作时有意义,而不是在一个对象和一块原始的比特之间。即使这段代码碰巧作了你想要它做的事情,results也不会知道transform在它的未使用容量上“创造”的新“对象”。直到results知道之前,它的大小在调用transform后仍然和原来一样。同样的,它的end迭代器仍和调用transform前指向同样的位置。结论呢?使用reserve而没有用插入迭代器会在算法内部导致未定义行为,也会弄乱容器。
正确地写这个例子的代码的方法是使用reserve和插入迭代器:
vector<int> values; // 同上 vector<int> results; results.reserve(results.size() + values.size()); // 同上 transform(values.begin(), values.end(), // 把transmogrify的结果 back_inserter(results), // 写入results的结尾, transmogrify); // 处理时避免了重新分配
到目前为止,我都在假设你让像transform那样的算法把它们的结果作为新元素插入容器。这是通常的期望,但有时候你要覆盖现有容器的元素而不是插入新的。当这种情况时,你不需要插入迭代器,但你仍然需要按照本条款的建议来确保你的目的区间足够大。
比如,假设你让transform覆盖results的元素。如果results至少有和values一样多的元素,那很简单。如果没有,你也必须使用resize来确保它有。
vector<int> values; vector<int> results; ... if (results.size() < values.size()){ // 确保results至少 results.resize(values.size()); // 和values一样大 } transform(values.begin(), values.end(), // 覆盖values.size()个 results.begin(), // results的元素 transmogrify);
或者你可以清空results然后用通常的方式使用插入迭代器:
... results.clear(); // 销毁results中 // 的所有元素 results.reserve(values.size()); // 保留足够空间 transform(values.begin(), values.end(), // 把transform地返回值 pack_inserter(results), // 放入results transmogrify);
本条款论证了这个主题的很多变化,但我希望你能牢牢记住本质。无论何时你使用一个要求指定目的区间的算法,确保目的区间已经足够大或者在算法执行时可以增加大小。如果你选择增加大小,就使用插入迭代器,比如ostream_iterators或从back_inserter、front_inserter或inserter返回的迭代器。这是所有你需要记住的东西。
注意:
copy(ve.begin(),ve.end(),back_inserter(v1));是将ve的数据插入到v1的后面
一:函数模板类
1、一元函数原型
template<class _A,class _R>
struct unary_function
{
typedef _A argument_type;
typedef _R result_type;
};
2、二元函数原型
template<class Arg1,class Arg2,class Result>
struct unary_function
{
typedef Arg1 first_argument_type;
typedef Arg2 Second_argument_type;
typedef Result result_type;
};
3、系统函数对象
plus 返回两个数的和:a+b
minus 返回两个数的差:a-b
multiplies 返回两个数的乘积:a*b
divides 返回两个数的商:a/b
mudulus 返回两个数的模:a%b
negate 返回某个数的相反数:-a
equal_to 判断两个数是否相等:a==b
not_equal_to 判断两个数是否不等:a!=b
greater 判断第一个数是否大于第二个数:a>b
less 判断第一个数是否小于第二个数:a<b
greate_equal 判断第一个数是否大于等于第二个数:a>=b
less_equal 判断第一个数是否小于等于第二个数:a<=b
logical_and 返回两个数的逻辑与结果:a&&b
logical_or 返回两个数的逻辑或结果:a||b
logical_not 返回某个数的逻辑非结果:!a
二:通用容器
1、vector
vector/vector(int nSize) 创建向量容器
assign 对Vector中的元素赋值
at 返回指定位置的元素
back 返回最末一个元素
begin 返回第一个元素的迭代器
capacity 返回vector所能容纳的元素数量(在不重新分配内存的情况下)
clear 清空所有元素
empty 判断Vector是否为空(返回true时为空)
end 返回最末元素的迭代器(译注:实指向最末元素的下一个位置)
erase 删除指定元素
front 返回第一个元素
get_allocator 返回vector的内存分配器
insert 插入元素到Vector中
max_size 返回Vector所能容纳元素的最大数量(上限)
pop_back 移除最后一个元素
push_back 在Vector最后添加一个元素
rbegin 返回Vector尾部的逆迭代器
rend 返回Vector起始的逆迭代器
reserve 设置Vector最小的元素容纳数量
resize 改变Vector元素数量的大小
size 返回Vector元素数量的大小
swap 交换两个Vector
2、list
assign 给list赋值
back 返回最后一个元素
begin 返回指向第一个元素的迭代器
clear 删除所有元素
empty 如果list是空的则返回true
end 返回末尾的迭代器
erase 删除一个元素
front 返回第一个元素
get_allocator 返回list的配置器
insert 插入一个元素到list中
max_size 返回list能容纳的最大元素数量
merge 合并两个list
pop_back 删除最后一个元素
pop_front 删除第一个元素
push_back 在list的末尾添加一个元素
push_front 在list的头部添加一个元素
rbegin 返回指向第一个元素的逆向迭代器
remove 从list删除元素
remove_if 按指定条件删除元素
rend 指向list末尾的逆向迭代器
resize 改变list的大小
reverse 把list的元素倒转
size 返回list中的元素个数
sort 给list排序
splice 合并两个list
swap 交换两个list
unique 删除list中重复的元素
3、deque
push_front 头部添加一个元素
push_back 尾部添加一个元素
insert 插入一个元素
erase 删除一个元素
pop_front 删除最前一个元素
pop_back 删除最后一个元素
clear 清楚所有元素
at 返回指定位置的元素
4、stack
stack<class T,class Container = deque/vector/list<T>> 构造栈
empty 堆栈为空则返回真
pop 移除栈顶元素
push 在栈顶增加元素
size 返回栈中元素数目
top 返回栈顶元素
5、queue
queue<class T,class Container = deque/list<T>> 构造队列
back 返回最后一个元素
empty 如果队列空则返回真
front 返回第一个元素
pop 删除第一个元素
push 在末尾加入一个元素
size 返回队列中元素的个数
6、set
begin 指向set的头指针
clear 删除所有元素
count 返回某键值元素的个数
empty 返回是否为空
end 指向set的尾指针
erase 删除某位置元素
pair<iterator, iterator>equal_range(const key_type& x) 返回一个迭代器对(指向键不小于x的第一个元素的迭代器,指向键大于x的第一个元素的迭代器)
find 返回某索引元素指针
get_allocator 返回构造函数的一个拷贝
pair<iterator,bool>insert(const value_type& x)返回<指向元素x的迭代器,是否插入成功>
lower_bound 返回键值不小于某值的第一个元素的迭代器
max_size 返回该set可以控制的最大长度
rbegin 返回反向set的反向头指针
rend 返回反响set的反向尾指针
resize(size_type Sz, T C=T()) 插入或删除使元素的个数为n,插入的元素为C
7、map
map(const Pred& comp=Pred(),const A& al=A()) 构造函数
pair<const_iterator,const_iterator>equal_range(const Key& key)const: 返回迭代器中键值等于key的迭代指针[fitst,last)
8、迭代器函数
back_inserter 返回容器的后插迭代器
front_inserter 返回容器的前插迭代器
三:非变异算法
1、循环
for_each 对每个元素执行相同的函数操作
2、查询
find 某值第一次出现位置
find_if 符合某谓词的第一个元素
find_first_of 子序列某元素第一次出现位置
adjacent_find 第一次相邻元素相等的位置
find_end 子序列最后出现位置
search 子序列第一次出现位置
search_n 一个值连续出现n次的位置
3、计数
count 某值出现的此时
count_if 与某谓词匹配的次数
4、比较
equal 两个序列对应元素都相同为真
mismatch 两个序列相异的第一个元素
四:变异算法
1、变换
transform 将某操作应用于指定范围的元素
2、填充
fill 用给定值填充所有元素
3、生成
generate 用一操作的结果填充所有元素
4、唯一
unique/unique_copy 删除相邻位置重复的元素
5、反转
reverse/reverse_copy 循环移动元素
6、随机
random_shuffle 随机移动元素
7、划分
partition/stable_paritition 满足谓词的元素都放在前面
五:排序及相关操作
1、排序
sort 以很好的平均效率排序
stable_sort 稳定排序
partial_sort 局部排序
partial_sort_copy 复制时进行局部排序
2、二分检索
lower_bound 大于等于某值第一次出现的迭代器位置
upper_bound 大于某值第一次出现位置
equal_range 等于某值迭代器范围
binary_search 是否存在某值
3、归并
merge 归并两个迭代器有序序列
inplace_merge 归并单个迭代器有序序列
4、有序结构上的集合操作
includes 一个序列为另一个序列子集为真
set_union 构造两集合有序并集
set_intersection 构造有序交集
set_difference 构造有序差集
set_symmetric_difference 构造有序对称差
5、堆操作
make_heap 从序列构造堆
pop_heap 从堆中弹出元素
push_heap 加入元素
sort_heap 排序
6、最大最小
max
min
min_element
max_element
7、词典比较
lexicographical_compare 两个序列按字典序排序
8、排列生成器
next_permutation 按字典序的下一个排序
prev_permutation 按字典序的上一个排序
9、数值算法
accumulate 累积求和
inner_product 内积求和
partial_sum 创建新序列,每个元素值代表指定范围内该位置前所有元素之和
adjacent_difference 相邻元素差集
http://www.crackerban.com/?p=1158