一、STL分类
容器类(container)
(1)顺序容器:
vector:内存成倍增长的动态数组
deque:动态开辟的二维数组
list:双向链表
(2)关联容器:
set:单重集合 红黑树
mutiset:多重集合 红黑树
map:单重映射 红黑树
mutimap:多重映射 红黑树
(3)容器适配器:
stack
queue
prioriy_queue
迭代子(iterator):
正向迭代器:iterator / const_iterator
反向迭代器:reverse_iterator / const_reverse_iterator
插入行迭代器:back_insert_iterator / front_insert_iterator/insert_iterator
流式迭代器:istream_iterator / ostream_iterator
算法(algorithm)
泛型算法(generic algorithm)和函数对象(function object)的使用。
二、容器的实现
(1)vector
插入
a.用push_back(value)//在尾部快速插入元素
b.用insert(it,value);//在迭代器指向的位置进行插入元素
删除
a.用clear();//清除元素中的所有元素;
b.用erase(it_fist,it_second);//删除迭代器区间的元素;
c.用erase(it);//删除迭代器指向的元素;
修改
a.使用迭代器进行修改;
b.用下标进行修改,因为vector提供了[]运算符的重载;
查找
a.使用迭代器遍历整个容器查找;
b.使用find(it_fist,it_second,num);查找;找到返回当前元素的迭代器,未找到返回末尾位置迭代器;
c.使用find_if()进行查找;
代码练习:
int main()
{
srand(time(0));
vector<int> vec;
/*
第一部分:增加元素:
*/
cout<<"--------------------------------------------"<<endl;
vec.push_back(13);
vec.push_back(44);
vec.push_back(4);
vec.push_back(8);
sort(vec.begin(),vec.end());//默认升序排序
vector<int>::iterator it1=vec.begin();
for(;it1!=vec.end();++it1)
{
cout<<*it1<<" ";//打印出4 8 13 44
}
cout<<endl;
vector<int>::iterator it2=vec.begin();
vec.insert(it2,85);//插入完之后迭代器将失效;不能使用迭代器遍历打印
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));//输出85 4 8 13 44
cout<<endl;
/*
第二部分:删除元素:
*/
cout<<"--------------------------------------------"<<endl;
vector<int>::iterator it3=vec.begin();
vec.erase(it3);//删除完之后将会使迭代器失效,不能使用迭代器遍历打印
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//vec.clear();
cout<<vec.size()<<endl;//容器内元素的个数
cout<<vec.capacity()<<endl;//返回当前vector最大能够存储的元素个数
/*
第三部分:修改:
*/
cout<<"--------------------------------------------"<<endl;
vector<int>::iterator it4=vec.begin();
*it4=55;//迭代器解引用修改
vec[1]=100;//[]运算符重载函数修改
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
/*
第四部分:查找元素:
*/
cout<<"--------------------------------------------"<<endl;
vector<int>::iterator it5=find(vec.begin(),vec.end(),55);
if(it5==vec.end())
{
cout<<"55 not find"<<endl;
return -1;
}
cout<<"55 finded"<<endl;
/*
第五部分:练习:
1、从大到小进行排序(前提)
2、把74插到合适的位置。如果序列中有74,则不需要插入。
3、找到74,如果有则删除
*/
cout<<"--------------------------------------------"<<endl;
vec.clear();//清空
for(int i=0;i<20;++i)
{
vec.push_back(rand()%100+1);
}
vector<int>::iterator it6=vec.begin();
for(;it6!=vec.end();++it6)
{
cout<<*it6<<" ";
}
cout<<endl;
sort(vec.begin(),vec.end(),greater<int>());//从大到小排序
vector<int>::iterator it7=find_if(vec.begin(),vec.end(),bind1st(greater_equal<int>(),74));
if(*it7!=74)//先找74
{
vec.insert(it7,74);
}
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
vector<int>::iterator it8=find(vec.begin(),vec.end(),74);//找74
/*if(*it8==74)//不可这样判断,因为当未找到时,在打印时出现迭代器失效
vec.erase(it8);*/
if(it8==vec.end())//find()找到返回当前元素的迭代器;未找到返回end()
{
cout<<"74 not find"<<endl;
return -1;
}
cout<<"74 finded"<<endl;
vec.erase(it8);
copy(vec.begin(),vec.end(),ostream_iterator<int>(cout," "));
cout<<endl;
cout<<"--------------------------------------------"<<endl;
return 0;
}
(2)deque
int main()
{
deque<int> deq;
cout<<deq.size()<<endl;
//cout<<deq.capacity()<<endl;
/*增加*/
deq.insert(deq.begin(),10);//在迭代器位置插入
deq.push_back(12);//后插
deq.push_front(15);//前插
copy(deq.begin(),deq.end(),ostream_iterator<int>(cout," "));
cout<<endl;
/*删除*/
deq.erase(deq.begin());//把迭代器位置的元素删除
copy(deq.begin(),deq.end(),ostream_iterator<int>(cout," "));
cout<<endl;
/*deq.clear();
copy(deq.begin(),deq.end(),ostream_iterator<int>(cout," "));
cout<<endl;*/
/*修改*/
deq[0]=88;
copy(deq.begin(),deq.end(),ostream_iterator<int>(cout," "));
cout<<endl;
cout<<deq[1]<<endl;
/*查找*/
deque<int>::iterator it1=find(deq.begin(),deq.end(),88);
if(it1==deq.end())
cout<<"not find"<<endl;
deque<int>::iterator it=find_if(deq.begin(),deq.end(),bind1st(greater_equal<int>(),74));
if(*it!=74)
{
deq.insert(it,74);
}
copy(deq.begin(),deq.end(),ostream_iterator<int>(cout," "));
cout<<endl;
return 0;
}
(3)list
int main()
{
list<int> t;
/*增加*/
t.insert(t.begin(),96);
t.push_back(89);
t.push_front(3);
copy(t.begin(),t.end(),ostream_iterator<int>(cout," "));
cout<<endl;
/*删除*/
/*t.erase(t.begin());
t.clear();*/
/*修改*/
//t[0]=100;//不提供,因为list底层用链表实现,内存空间不连续;采取迭代器修改
/*查找*/
list<int>::iterator it1=find(t.begin(),t.end(),188);
if(it1==t.end())
cout<<"not find"<<endl;
list<int>::iterator it=find_if(t.begin(),t.end(),bind1st(greater_equal<int>(),74));
if(*it!=74)
{
t.insert(it,74);
}
copy(t.begin(),t.end(),ostream_iterator<int>(cout," "));
cout<<endl;
return 0;
}
(4)set & multiset
int main()
{
set<int> myset1;//用一个类型实例化set时,一定要保证该类型提供小于运算符的重载函数,因为set底层用红黑树实现,红黑树本身就是一个排序树
/*增加*/
myset1.insert(15);
myset1.insert(3);
myset1.insert(1);
myset1.insert(44);
myset1.insert(78);
copy(myset1.begin(),myset1.end(),ostream_iterator<int>(cout," "));
cout<<endl;
set<int,greater<int>> myset2;//按升序插入
myset2.insert(89);
myset2.insert(189);
myset2.insert(82);
myset2.insert(14);
myset2.insert(14);
copy(myset2.begin(),myset2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
/*删除*/
myset2.erase(myset2.begin());
copy(myset2.begin(),myset2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
multiset<int> myset3;//多重集合,允许键值重复
myset3.insert(14);
myset3.insert(15);
myset3.insert(14);
cout<<myset3.count(14)<<endl;//打印myset3中14出现的次数
copy(myset3.begin(),myset3.end(),ostream_iterator<int>(cout," "));
cout<<endl;
/*查找*/
multiset<int>::iterator it=myset3.find(14);//提供了自己的find()算法,效率高;不建议使用全局的find算法(O(n))
if(it==myset3.end())
{
cout<<"14 not find"<<endl;
return -1;
}
myset3.erase(it);
copy(myset3.begin(),myset3.end(),ostream_iterator<int>(cout," "));
return 0;
}
(5)map
int main()
{
map<string,vector<int>> mymap;
vector<int> vec1,vec2,vec3;
/*增加*/
//方法一:利用map中提供的[]运算符重载函数来进行插入
mymap["LiuBei"]=vec1;
mymap["ZhaoYun"]=vec2;
mymap["ZhuGeLiang"]=vec3;
//方法二:map中元素的类型是pair对象,把键值对打包起来用insert进行插入
typedef map<string,vector<int>>::value_type _VT;
mymap.insert(_VT("ZhangFei",vec1));
//方法二:typedef重命名
typedef pair<string,vector<int>> _PAIR;
mymap.insert(_PAIR("CaoCao",vec1));
map<string,vector<int>>::iterator it=mymap.find("LiuBei");
if(it==mymap.end())
{
cout<<"not find"<<endl;
return -1;
}
for(int i=0;i<20;i++)
{
it->second.push_back(rand()%100);
}
copy(it->second.begin(),it->second.end(),ostream_iterator<int>(cout," "));//打印
cout<<endl;
map<string,vector<int>>::iterator it1=mymap.begin();
for(;it1!=mymap.end();++it1)
{
cout<<it1->first<<" ";
copy(it->second.begin(),it->second.end(),ostream_iterator<int>(cout," "));
cout<<endl;
}
return 0;
}
(6)容器适配器
容器适配器就是对已有容器的一个再封装。底层并没有自己独立的数据结构。
stack:栈;底层是deque.
queue:队列;底层是deque.
priority_queue:优先级队列;底层一vector为基础;插入的元素按优先级插,取元素的时候优先级最高的先取出。
三、算法
函数对象:每个对象都是一个类模板,以操作数类型为模板参数。包含头文件:#include<functional>
(1)函数对象的来源
1. 标准库预定义的一组算术,关系和逻辑函数对象;
1.1算术:
加法:plus<Type>
减法:minus<Type>//同加法
乘法:multiplies<Type>//不能用串,可用于复数和浮点数等
除法:divides<Type>//同乘法
求余:modulus<Type>//不能用于复数,浮点数,只能用于整数
取反:negate<Type>//同取余,但为单参数
1.2关系:返回值为布尔量,两个参数,第一参数和第二参数相比:
等于:equal_to<Type>
不等于:not_equal_to<Type>
大于:greater<Type>
大于等于:greater_equal<Type>
小于:less<Type>
小于等于:less_equal<Type>
1.3逻辑操作(逻辑函数对象,Type必须支持逻辑运算,有两个参数。)
逻辑与:logical_and<Type> //对应&&
逻辑或:logical_or<Type> //对应||
逻辑非:logical_not<Type> //对应!
2. 预定义的一组函数适配器,允许对预定义的函数对象进行特殊化或扩展;
2.1绑定器(binder);
把二元函数对象中的一个参数固定(绑定),使之转为一元函数;
C++标准库提供两种预定义的binder适配器:bind1st和bind2nd,分别绑定了第一或第二个参数。
2.2取反器(negator):
把函数对象的值翻转的适配器;如原来为小于,用了它后就变成了大于。
C++标准库也提供了两种negator适配器:not1和not2。not1用于一元预定义函数对象;not2用于二元预定义函数对象。
3. 自定义函数对象。
泛型算法:
泛型算法函数名都加有后缀
_if 表示函数采用的操作是在元素上,而不是对元素的值本身进行操作。如find_if算法表示查找一些值满足函数指定条件的元素,而find查找特定的值。
_copy 表示算法不仅操作元素的值,而且还把修改的值复制到一个目标范围中。reverser算法颠倒范围中元素的排列顺序,而reverse_copy算法同时把结果复制到目标范围中。
联系:函数对象主要是作为泛型算法的实参使用,通常用来改变缺省的操作
比如:sort(vec.begin(),vec.end(),greater<int>());这就是把整数的大于关系函数对象作为实参,得降序排列。