C++ STL使用实例
一、概述
二、容器
1.vector
(1)概述
参考1
Vector是一个封装了动态大小数组的顺序容器(Sequence container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,Vector是一个能够存放任意类型的动态数组。
【1】.顺序序列
顺序容器中的元素按照严格的线性顺序排序。可以通过元素在序列中的位置访问对应的元素。
【2】.动态数组
支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作。操供了在序列末尾相对快速地添加/删除元素的操作。
【3】.能够感知内存分配器的(Allocator-aware)
容器使用一个内存分配器对象来动态地处理它的存储需求。
(2)函数介绍
【1】.push_back 在数组的最后添加一个数据
【2】.pop_back 去掉数组的最后一个数据
【3】.at 得到编号位置的数据
【4】.begin 得到数组头的指针
【5】.end 得到数组的最后一个单元+1的指针
【6】.front 得到数组头的引用
【7】.back 得到数组的最后一个单元的引用
【8】.max_size 得到vector最大可以是多大
【9】.capacity 当前vector分配的大小
【10】.size 当前使用数据的大小
【11】.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
【12】.reserve 改变当前vecotr所分配空间的大小
【13】.erase 删除指针指向的数据项
【14】.clear 清空当前的vector
【15】.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)
【16】.rend 将vector反转构的结束指针返回(其实就是原来的begin-1)
【17】.empty 判断vector是否为空
【18】.swap 与另一个vector交换数据
(3)代码实例
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void show(vector<int> v)
{
cout<<"------ iterator show------"<<endl;
vector<int>::iterator it;
for(it = v.begin(); it != v.end(); it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
void reverseShow(vector<int> v)
{
cout<<"----- reverse iterator show ------"<<endl;
vector<int>::reverse_iterator it;
for(it = v.rbegin();it != v.rend();it++)
{
cout<< *it<<" ";
}
cout<<endl;
}
int main()
{
cout<<"--- 1.create ---"<<endl;
vector<int> v;
v.push_back(1); v.push_back(2);
vector<int> v1(v);
vector<int>v2(3,1);
vector<int>v3(20);
cout<<"--- 2.add member ---"<<endl;
v.push_back(3); v.push_back(4);
v2.push_back(66); v2.push_back(45);
v.insert(v.begin()+1,88);// add 88 from site 1
v.insert(v.begin()+2,3,9);// add 3 9 from site 2
cout<<"--- 3.get member ---"<<endl;
cout<<"v: "<<v[0]<<","<<v[1]<<","<<v[2]<<","<<v[3]<<","<<v[4]<<","<<v[5]<<","<<v[6]<<","<<v[7]<<endl;
//cout<<v[7777777]<<endl; // fault
cout<<"v1: "<<v1[0]<<","<<v1[1]<<","<<v1[2]<<","<<v1[3]<<endl;
cout<<"v2: "<<v2[0]<<","<<v2[1]<<","<<v2[2]<<endl;
show(v);
cout<<"at(): "<<v.at(1)<<endl;
cout<<"front(): "<<v.front()<<endl;
cout<<"back(): "<<v.back()<<endl;
reverseShow(v);
cout<<"--- 4.len ---"<<endl;
cout<<"v.size(): "<<v.size()<<endl;
cout<<"v.capacity(): "<<v.capacity()<<endl;
cout<<"v3.capacity(): "<<v3.capacity()<<endl;
cout<<"v3.max_size(): "<<v3.max_size()<<endl;
cout<<"--- 5.sort ---"<<endl;
sort(v.begin(),v.end());
show(v);
reverse(v.begin(),v.end());
show(v);
cout<<"--- 6.other ---"<<endl;
v.swap(v2);
show(v);
cout<<"--- 6.delete ---"<<endl;
v.pop_back();//delete last one
show(v);
v.erase(v.begin()+1);
show(v);
v.erase(v.begin()+1,v.begin()+3);
show(v);
cout<<"empty(): "<<v.empty()<<endl;
v.clear();
cout<<"empty(): "<<v.empty()<<endl;
cout<<"--- 7.find ---"<<endl;
vector<int>::iterator itc = find(v2.begin(),v2.end(),2);
cout<<"find: "<<*itc<<endl;
if(itc == v2.end())
cout<<"not find"<<endl;
else
cout<<"found it"<<endl;
itc = find(v2.begin(),v2.end(),109);
cout<<"find: "<<*itc<<endl;
return 0;
}
2、map
(1)概述
map可以将任何基本类型(包括stl容器)映射到任何基本类型(包括stl容器)
map的键是唯一的, 如果有重复的键,新的value会覆盖旧的value
map会以键从小到大的顺序自动排序,这是由于map的内部是使用红黑树实现的(set也是)
(2)函数
insert()
erase()
clear()
find() // 在find之前要先判断key存不存在,用count(key)
(3)代码实例
#include <iostream>
#include <map>
#include <string>
using namespace std;
void show(map<int,string> m,string s)
{
cout<<s<<endl;
map<int,string>::iterator it;
for(it = m.begin(); it != m.end(); it++)
{
cout<< "["<< it->first <<"]"<<" = "<<it->second <<endl;
}
}
int main()
{
cout<<"--- 1.Create ---"<<endl;
map<int,string> m1;
cout<<"--- 2.add ---"<<endl;
m1.insert(pair<int,string>(1,"aaaa"));
m1.insert(pair<int,string>(2,"bbbb"));
m1.insert(pair<int,string>(3,"cc"));
m1.insert(pair<int,string>(88,"ttxs"));
m1.insert(pair<int,string>(10,"b100"));
m1.insert(pair<int,string>(11,"b100"));
m1.insert(pair<int,string>(31,"b100"));
m1.insert(pair<int,string>(21,"b100"));
m1.insert(pair<int,string>(12,"c200"));
m1.insert(pair<int,string>(11,"AK--"));
show(m1,"m1:");
cout<<"--- 3.get member ---"<<endl;
cout<<"m1[2]:"<<m1[2]<<endl;
cout<<"--- 4.find ---"<<endl;
// before find, should check key exist or not
cout<<"count 999:"<<m1.count(999)<<endl;
cout<<"count 88:"<<m1.count(88)<<endl;
if(m1.count(88) == 1)
{
map<int,string>::iterator ita = m1.find(88);
cout<<"ita:"<<ita->second<<endl;
if(ita != m1.end())
cout<<"found it"<<endl;
else
cout<<"no exist"<<endl;
}
map<int,string>::iterator itc = m1.lower_bound(10);
if(itc != m1.end())
cout<<"lower_bound found it"<<endl;
else
cout<<"lower_bound no exit"<<endl;
cout<<"--- 4.delete ---"<<endl;
map<int,string>::iterator itd = m1.find(88);
m1.erase(itd);
show(m1,"m1 erase one");
//map<int,string>::iterator itc = m1.find(3);
//m1.erase(ita,m1.end());
//show(m1,"m1 erase after 10");
map<int,string> m2(m1);
show(m2,"m2:");
m2.clear();
show(m2,"m2 clear");
cout<<"--- 5.other ---"<<endl;
cout<<"size: "<<m1.size()<<endl;
return 0;
}
3、list
(1)概述
Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢
list容器不提供 at() 和 操作符 operator[] ,对容器中元素的访问有些不便,但是我们可以使用迭代器进行元素的访问
(2)函数
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)代码实例
#g++ list.cc
#include <iostream>
#include <list>
#include <numeric>
#include <algorithm>
#include <string>
using namespace std;
void show(list<int> l,string s)
{
cout<<s<<endl;
list<int>::iterator it;
for(it = l.begin();it != l.end(); it++)
cout<< *it <<" ";
cout<<endl;
}
void show_reverse(list<int> l,string s)
{
cout<<s<<endl;
list<int>::reverse_iterator it;
for(it = l.rbegin(); it != l.rend(); it++)
cout<< *it <<" ";
cout<<endl;
}
int main()
{
cout<<endl<<"--- 1.Create ---"<<endl;
list<int> l1;
list<int> l2(10,6);
list<int> l3(l2);
list<int> l4(l2.begin(),--l2.end());
list<int> l5(l1);
cout<<endl<<"--- 2.add member ---"<<endl;
l1.push_front(1); l1.push_front(2);
l1.push_back(5); l1.push_back(6);
l1.insert(++l1.begin(),88);
list<int>::iterator ita = l1.begin();
ita++;ita++;ita++;
l1.insert(ita,3,55);
l5.assign(6,110);
list<int> l6(l1);
cout<<endl<<"--- 3.get member ---"<<endl;
show(l1,"l1:"); show(l2,"l2:"); show(l3,"l3:");
show(l4,"l4:"); show(l5,"l5:"); show(l6,"l6:");
show_reverse(l1,"l1 reverse:");
cout<<"back(): "<<l1.back()<<endl;//last one
cout<<"front(): "<<l1.front()<<endl;//first one
cout<<endl<<"--- 4.delete ----"<<endl;
l1.pop_front();
l1.pop_back();
show(l1,"l1 pop front and back");
cout<<"empty(): "<<l2.empty()<<endl;
l2.clear();
cout<<"empty(): "<<l2.empty()<<endl;
list<int>::iterator itb = remove(l1.begin(),l1.end(),1);
show(l1,"l1 after remove 1");
l1.erase(itb,l1.end());
show(l1,"l1 after remove and erase ");
l1.remove(88);//we should use it's remove()
show(l1,"l1.remove(88)");
cout<<endl<<"--- 5.find ----"<<endl;
list<int>::iterator itc = find(l1.begin(),l2.end(),55);
cout<<"find: "<<*itc<<endl;
cout<<endl<<"--- 6.other ---"<<endl;
int sum = accumulate(l1.begin(),l1.end(),0);
cout<<"sum: "<<sum<<endl;
list<int>::iterator it;
it = max_element(l1.begin(),l1.end());
cout<<"max_element: "<<*it<<endl;
cout<<"size(): "<<l1.size()<<endl;
cout<<"max_size(): "<<l1.max_size()<<endl;
l1.unique();
show(l1,"unique()");
l6.sort();
show(l6,"l6 from l1 sort:");
return 0;
}
4、set
(1)概述
在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。
常见问题
【1】为何map和set的插入删除效率比用其他序列容器高?
因为对于关联容器来说,不需要做内存拷贝和内存移动。set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多
【2】为何每次insert之后,以前保存的iterator不会失效?
iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢(当然被删除的那个元素本身已经失效了)。相对于vector来说,每一次删除和插入,指针都有可能失效,调用push_back在尾部插入也是如此。因为为了保证内部数据的连续存放,iterator指向的那块内存在删除和插入过程中可能已经被其他内存覆盖或者内存已经被释放了。即使时push_back的时候,容器内部空间可能不够,需要一块新的更大的内存,只有把以前的内存释放,申请新的更大的内存,复制已有的数据元素到新的内存,最后把需要插入的元素放到最后,那么以前的内存指针自然就不可用了。特别时在和find等算法在一起使用的时候,牢记这个原则:不要使用过期的iterator
【3】当数据元素增多时,set的插入和搜索速度变化如何?
在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。,当数据量增大一倍的时候,搜索次数只不过多了1次,很快的。
(2)函数
begin() ,返回set容器的第一个迭代器
end() ,返回set容器的最后一个迭代器
clear() ,删除set容器中的所有的元素
empty() ,判断set容器是否为空
max_size() ,返回set容器可能包含的元素最大个数
size() ,返回当前set容器中的元素个数
rbegin ,返回的值和end()相同
rend() ,返回的值和rbegin()相同
删除操作是不进行任何的错误检查的,比如定位器的是否合法等等,所以用的时候自己一定要注意
erase(iterator) ,删除定位器iterator指向的值
erase(first,second),删除定位器first和second之间的值
erase(key_value),删除键值key_value的值
find() ,返回给定值值得定位器,如果没找到则返回end()
count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。
insert(key_value); 将key_value插入到set中 ,返回值是pair<set::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置。
inset(first,second);将定位器first到second之间的元素插入到set中,返回值是void.
(3)代码实例
#include <iostream>
#include <set>
using namespace std;
void show(set<int>st, string s)
{
cout<<s<<endl;
set<int>::iterator it;
for(it = st.begin();it != st.end(); it++)
cout<<*it<<" ";
cout<<endl;
}
int main()
{
cout<<"--- 1.create ---"<<endl;
set<int> s1;
cout<<"--- 2.add ---"<<endl;
s1.insert(1); s1.insert(2); s1.insert(3);
s1.insert(8); s1.insert(8); s1.insert(8);
pair<set<int>::iterator,bool> pr;
pr = s1.insert(5);
if(pr.second)
cout<<*pr.first<<endl;
cout<<"--- 3.get ---"<<endl;
show(s1,"s1:");
cout<<"--- 4.delete ---"<<endl;
s1.erase(2);
show(s1,"s1:");
s1.erase(34);
show(s1,"s1:");
cout<<"--- 5.find ---"<<endl;
set<int>::iterator it1 = s1.find(3);
if(it1 != s1.end())
cout<<"found it "<<endl;
else
cout<<"not exist"<<endl;
cout<<"find: "<<*it1<<endl;
cout<<"count: "<< s1.count(5) <<endl;
show(s1,"s1:");
cout<<"lower_bound(4): "<<*s1.lower_bound(4)<<endl;
cout<<"lower_bound(3): "<<*s1.lower_bound(3)<<endl;
cout<<"lower_bound(99): "<<*s1.lower_bound(99)<<endl;
cout<<"--- 6.oter ---"<<endl;
cout<<"size(): "<<s1.size()<<endl;
cout<<"empty(): "<<s1.empty()<<endl;
s1.clear();
cout<<"empty(): "<<s1.empty()<<endl;
return 0;
}
5.multiset
使用set或multiset之前,必须加入头文件
Set、multiset都是集合类,差别在与set中不允许有重复元素,multiset中允许有重复元素。、
6.multimap
map 与 multimap是存储key-value(键-值 对)类型的容器。
不同之处在于:map只允许key与 value一一对应;multimap一个key可对应多个value;