您的位置:首页 > 其它

STL复习

2015-07-01 17:42 246 查看
STL将数据结构和算法分离,通过迭代器粘合起来。

每个容器的组成都有:成员类型 , 成员函数 和 成员变量。容器的存储要么是连续内存, 要么是基于节点的容器。连续内存的容器中常用的string 和 vector,其实现不考虑引用计数,只需要三个成员就行:记录元素个数的size, 记录当前容量的 capacity 和 管理动态内存的 指针 p.

C98中的函数适配器 bind1st, bind2nd, not1, not2, mem_fun_ref, mem_fun, ptr_fun ; ptr_fun用来将函数指针转化为函数对象,其实就是增加成员类型,因为bind1st, bind2nd, not1, not2的参数都只能是函数对象。men_fun_ref() 用来绑定成员函数,此时容器的元素是类对象。 men_fun() 也是用来绑定成员函数的,只是此时的容器的元素是类对象指针。想想还是C++11的bind好用,一个bind()
的重载还有lambda表达式,解决所有这些问题。

对于string,需要关注的是string:: npos 成员,用来标志字符串的结尾。 string 的大多数函数的参数都是 位置 + 长度的形式。find 是全部匹配,find_first_of 和 find_first_not_of 是只要有一个字符匹配就行,返回匹配的位置, 返回的位置是size_t 类型值,也就是string::value_type 类型。注意<algorithm>中,还有一个全局的find 函数。

remove() 函数并不是真正意义上的删除,因为容器的size 并没有发生变化。 其实只是将要remove的元素用其后边的不要remove的元素覆盖掉,这就导致容易的后边有一些多余的元素,remove() 的返回值是迭代器,用于指向这些多余的元素的起始。所以需要删除的话,需要remove() 和 .erase() 成员函数搭配使用。

container.erase(remove(...), container.end());


同样的还有remove_if(), unique().

注意,unique() 函数只是remove 掉了相邻的相同元素,所以如果需要将整个容易中重复出现的元素remove 掉, 需要先排序,调用sort()函数,让相同的元素聚集。

container.erase(unique(...), container.end());
unique() 函数的返回值也是迭代器,指向多余元素的起始。

上边这些只是针对连续内存的容易,对于基于节点的容易,比如list , list 的remove() 就是直接删除。而且,list 拥有自己的sort() 函数和unique() 函数。

详细信息可以查询http://www.cplusplus.com

STL的算法<algorithm>中需要注意的是返回值为迭代器的情况和算法中可缺省的谓词及一元和二元函数对象。

通过迭代器往容器中写入新的元素,迭代器一定要是可用的。.end() 返回的迭代器就是不可用的,对于一个size为0, 当然capacity 不为0 的容器, .begin() 返回的迭代器一样是不可用的。否则会发生 iterator not incrementable 的运行时错误。这时需要用到插入迭代器,front_inserter(), back_inserter(), inserter()
;返回的迭代器总是有效的。

back_inserter() 内部调用了push_back, inserter() 内部调用了 insert(). 需要注意的是front_insert() 内部调用了push_front() ,只有deque 和 list 可以用。

STL中的排序函数:

sort() , stable_sort() 前者使用的主要是快速排序,后者使用的是归并排序。

sort(container.begin(), container.end(), [](int x, int y){return x > y; });
可以设置的是最后的谓词可调用对象,或者最简单的,直接使用库中的 greater<int>() , 缺省的是升序排列,也就是less<int>()。

partial_sort(), partial_sort_copy() 堆排序,升序时,排出最小的指定数目的数;降序时,排出最大的指定数目的数。

partial_sort(container.begin(), container.begin() + 3, container.end(),greater<int>());
//排序之后,container的前三个元素就是最大的三个数。

partial_sort_copy(container.begin(), container.end(), outCon.begin(), outCon.end(), less<int>());

//如果outCon的size 为 3, 那么排序之后,outCon 中的元素就是container中三个最小的数的升序排列。

nth_element() 使第n大小的(假如全排序的话,可以有相同的元素,排序之后位于第n个位置上的数)刚好位于位置n上。其他位置上的元素的顺序不能保证。

nth_element(container.begin(), container.begin() + 3, container.end(), greater<int>());
is_sorted() 用来判断容器中的元素是否已经排好序

if(is_sorted(container.begin(), container.end(), greater<int>()))
patiton() , stable_partition() 用于将容器分为两部分,满足条件的在前,返回值是迭代器,用来指示第二部分的起始位置

vector<int>::iterator iter = partition(container.begin(), container.end(), bind1st(greater<int>(), 5));
copy(iter, container.end(), ostream_iterator<int>(cout, "  "));
//输出容器中大于5的元素

注意这里使用的流迭代器,可以将输入输出流当作容器来看待了。

istream_iterator<int> input(cin);
istream_iterator<int> endinput;
//未赋值的,表示指向流的末尾。

需要排序的算法

之所以需要已经排序的容器,是因为排好序了才能提供最好的性能。

binary_search() , lower_bound() , upper_bound() 二分查找,前者用来查找是否存在,后两个用来查找已经排好序的元素的上界和下界的迭代器,lower_bound()返回指向查找值的迭代器,值不不存在时,指向一个适合插入该值位置的迭代器。upper_bound() 返回一个与查找值相等值的下一个位置。也就是说,如果查找值不存在, lower_bound()
, upper_bound()

返回值会指向同一个位置。

equal_range() 以pair的形式返回lower_bound() , upper_bound()的结果。lower_bound() , upper_bound()刚好形成一个左闭右开的区间,在区间内刚好都是要查找的值,当然也可能是个空区间,此时equal_range()返回的pair的first
和 second 指向同一个位置。

set_union(), set_intersection(), set_difference() , set_symmetric_difference() 分别用来求两个容器的并集, 交集, 差集 和 并集 - 交集。由于参数是迭代器,也就是指示位置的,所以也可以对数组进行操作,包括其他STL 的算法。

merge() 用来合并两个容器的元素。

inplace_merge() 用来将一个前后部分已经排好序的容器重新排序。

includes() 用来判断一个容器是否包含另外一个容器的全部元素。

next_permutation() 和 prev_permutation() 用来获得一个容器的全排列,不过默认的是字典的升序,也就是对于sting str= “bca”, next_permutation 只能得到字典序比其大的 string(“cab”) 和 string(“cba”),而prev_permutation 可以得到字典序比起小的string("abc"), string("acb"), string("bac") 。
所以要得到全部的全排列, 需要先对str 排一下序,然后使用next_permutation() 函数或者是 prev_permutation() 函数朝着一个字典序方向,获取全部的全排列。

sort(container.begin(), container.end(), greater<int>());
copy(container.begin(), container.end(), ostream_iterator<int>(cout, "  "));
cout << endl;
while (next_permutation(container.begin(), container.end(), greater<int>()))
{
copy(container.begin(), container.end(), ostream_iterator<int>(cout, "  "));
cout << endl;    //输出container元素的全排列
}


进行区间统计的accumulate()

accumulate() 有两个重载版本,

sum (1)

template <class InputIterator, class T>
T accumulate (InputIterator first, InputIterator last, T init);

custom (2)

template <class InputIterator, class T, class BinaryOperation>
T accumulate (InputIterator first, InputIterator last, T init,
BinaryOperation binary_op);
一个用来求和,一个给用户定制。其中二元函数对象的一个参数用来保存前边累计的值,起初被初始化为 init,一个参数用来保存迭代器指向的元素的值,于此进行往前迭代。

for_each()也能实现相同的功能,

template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function fn)
{
while (first!=last) {
fn (*first);
++first;
}
return fn;      // or, since C++11: return move(fn);
}
这里如果fn 是仿函数,允许fn 持有自己的状态。注意,for_each() 最终的返回值是这个可调用对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: