目录:
1.STL的组成
2.指针的算术运算
3.泛型find()的实现&泛型指针iterator的作用
4.常用泛型算法汇总
5.所有容器的通用操作
6.顺序容器vector,list,deque的插入和删除
vector iterators incompatible错误避免与原因分析
1.STL的组成
(1)容器container:vector\list\set\map\pair……
(2)泛型算法generic algorithm:find()\sort()\replace()\merge()……
2.指针的算术运算
array[2] == *(array+2)
若array的第一个元素的地址1000,那么array+2 != 1002,因为必须把“指针所指的类型”考虑进去
例:int为4byte(32bit,1个机器字长),那么array+2 == 1008
3.泛型find()的实现&泛型指针iterator的作用
要求:1.自适应类型int,string等。2.自适应array,vector
<span style="font-size:14px;">template<typename elemType>
inline elemType* begin(const vector<elemType>& vec)
{ return vec.empty() ? 0 : &vec[0]; }
template<typename elemType>
const elemType* find(const elemType* first, //返回的是地址,不加const可能会被修改
const elemType *last,const elemType& value)
{
if(!first || !last)
return 0;
for(;first != last; ++first)
if(*first == value)
return first;
return 0;
}
//调用
int ia[8] = {1,1,2,3,5,8,13,21};
const int* pi=find(ia,ia+8,ia[3]);
//vector
find(begin(svec),end(svec),search_value)</span>
附注:使用iterator,可以find()能够自适应到vector和list两种不同容器
iterator作为一种泛型指针,用于隐藏不同容器间的差异,是
实现泛型算法的基础
要求3:自适应不同容器的泛型find()
template<typename IteratorType,typename elemType>
IteratorType find(IteratorType first,IteratorType last,
const elemType& value)
{
for(;first != last;++first)
if(*first == value)
return first;
return last;
}
int main()
{
int ia[8] = {1,1,2,3,5,8,13,21};
int *pi=find(ia,ia+8,5);
if(pi != pi+8)
cout<<"找到了"<<endl;
vector<int> vec(ia,ia+8);
vector<int>::iterator iter =find(vec.begin(),vec.end(),22);
if(iter != vec.end())
cout<<"找到了"<<endl;
return 0;
}
4.常用泛型算法(Essential附录B)
int ia[8] = {1,1,2,3,5,8,13,21};
int ia2[9] = {1,1,2,3,5,8,13,21,24};
list<int> ilist(ia,ia+8)
以下,ia相当于ilist.begin(),ia+8相当于ilist.end()
加“*”表示可重构运算类型,重构方式如下:
class Even
{
public:
bool operator()(int val)
{ return !(val%2); }
};
ires = count_if(ia,ia+8,Even())
|
class Twiceover
{
public:
bool operator()(int val1,int val2)
{ return val1==val2/2 ? true : false; }
}
iter=adjacent_find(ia,ia+8,Twiceover())
|
搜索:<algorithm>iter
find(ia,ia+8,value) 若找到,返回其迭代器;否则,返回end(), 附find_end()
find_if(ia,ia+8,LessThanVal(val)) 一找到,就返回迭代器
*adjacent_find(ia,ia+8) 返回第一组相邻重复元素中第一个元素的迭代器
count(ilist.begin(),ilist.end,value) 返回容器中与value相等的元素个数
*count_if(ia,ia+8,bind2nd(less<int>(),10)) 返回"<10"的元素个数
*binary_search(ia,ia+8,value) 在"<"排列的容器中找value,返回bool
find_first_of() 搜索某些元素首次出现的地点
search()在序列1中搜索序列2,返回序列2起始处的迭代器
|
排序&次序整理:<algorithm> merge(ia,ia+8,ia2,ia2+9,result.begin()) 合并已排序序列,放置与result partial_sort() 局部排序 partition() 局部总和 random_shuffle(vec.begin(),vec.end()) 随机重排 reverse(ilist.begin(),ilist.end())颠倒元素次序 rotate(ia,ia+3,ia+8)旋转结果:{3,5,8,13,21,1,1,2} sort(ia,ia+8) 从小到大排序 |
复制、删除、替换:<algorithm> copy(ilist.begin(),ilist.end,listCopy.begin())复制 copy_backward逆向复制 remove(vec.begin(),vec.end(),0) 移除元素但不删除 *remove_if(vec.begin(),vec.end(),Even()) 返回删除后的有效迭代器end() replace(vec.begin(),vec.end(),oldval,newval) 取代某个元素 repace_if(vec.begin(),vec.end(),bind2nd(less<int>(),10),new)有条件取代 swap() 交换 unique(vec.begin,vec.end()) 将重复元素折叠所编使其唯一,与remove类似 fill(ia,ia+8,value)改填元素为value,fill_n(ia,n,value)只设n个元素值为value |
关系:<algorithm> *equal(ia,ia+7,ia2),若等长部分元素相等,返回true,ia2多的元素不管 includes(ia2,ia2+9,ia,ia+8) 若ia的元素都在ia2中,返回true,ia和ia2已排序 mismatch() max(ia[0],ia[1]) 返回两元素中最大值 max_element(ia,ia+8) 返回最大值的迭代器 distance(ia,iter) 返回两个迭代器的距离,例如iter和和ia的距离 |
数值:<numeric> *accmulate(ia,ia+8,0) 返回元素累加结果,“0”为指定初值 adjacent_difference(ia,ia+8,iresult.begin()) 相邻元素差额 {0,1,1,2,3,5,8} -> {0,1,0,1,1,2,3} 保留第0位,其他:该位-前一位 partial_sum() *inner_product(ia,ia+8,ia2,0) 内积,对应相乘再相加 |
集合:<algorithm>
set_union(ia,ia+8,ia2,ia2+9,ia3) 并集 {0,1,2,3}+{0,2,4,6}={0,1,2,3,4,6}
set_difference(ia,ia+8,ia2,ia2+9,ia3) 差集,集合1有,但集合2木有的元素,抽出来排序放入集合3
。集合1和2都排好序
|
较重要的泛型
5.所有容器的通用操作
int ia[] = {0,1,0,2,0,3,0,4,0,5};
vector<int> vec(ia,ia+10);
vec_iter = remove(vec.begin(),vec.end(),0) //0是要删除的元素
//remove()操作之后、erase()操作之前的vector内容:{1,2,3,4,5,3,0,4,0,5}
//要保留的元素都被向前复制。
|
vec.erase(vec_iter,vec.end());//erase()操作后的vector内容:1,2,3,4,5
//数组不易改变大小,所以不适用remove,而要用remove_copy()
int ia2[5]
remove_copy(ia,ia+10,ia2,0) //得到ia2:1,2,3,4,5
|
5.所有容器的通用操作
|
|
6.顺序容器vector,list,deque的插入和删除
定义:
- vector<int> ivec(32) //大小32,默认每个值为0, 适用于随机访问
- listM<string> slist(16,"unassigned") //大小16,每个字符赋值“unassigned” 适用于插入删除操作频繁
插入删除:
- 通用:push_back(),pop_back()
- list和deque还有:push_front(),pop_front()
- 通用:front() back() 返回最前端或最后端值
vector的删除erase和插入insert,注意避免vector iterators incompatible错误,插入删除后要赋值
#include<iterator>
#include<algorithm>
#include<vector>
template <typename T>
void DeleteVector(vector<T> &data, T key)
{
//vector<T>::iterator itr = data.begin();
//while(itr != data.end())
//{
// if(*itr == key){
// itr=data.erase(itr); //注意要赋值itr
// return;
// }
// else
// ++itr;
//}
vector<T>::iterator iter = find(data.begin(),data.end(),key);
if(iter != data.end())
iter=data.erase(iter);
}
template <typename T>
void InsertVector(vector<T> &data, T key)
{
vector<T>::iterator itr = data.begin();
while (itr != data.end())
{
if(*itr < key)
itr=itr+1;
else{
itr=data.insert(itr,key); //注意赋值itr
break;
}
}
if(itr == data.end())
data.push_back(key);
return;
}
如果itr在插入或删除后没有赋值,可能出现vector iterators incompatible的错误
分析原因:
- 如果插入后没有修改 itr,就在下方比较 itr 和 data.end() ,那么就出现错误;
- 问题出现在insert之后,vector的链表改变,新插入的元素不在iterator所引用的地址;
- 正确的做法是将insert()返回的插入元素的iterator赋给itr;
- 同理erase()也存在同样的问题,erase一个元素后,后续元素不一定移动到iterator所引用的位置。
其他引发该错误的原因有:
- 空Vector问题。不允许引用空vector的begin迭代器,因为vector是空的,自然不会有第一个项目,使用也会引发vector iterators incompatible。vector.clear()后,不能用vector.begin()
- vc2005 对于迭代器的匹配是非常严格的,通常这种错误是因为两个不同的迭代器操作同一个 vector,或者是因为迭代器在遍历vector时,vector的链表改变了,就会引发这种错误,比如vector在遍历的途中,别的位置push_back()一个元素,这时迭代器就失效了,导致错误。可以使用临界区互斥访问。