[STL]标准容器

 

1 STL

1.1 通用算法(函数模板)

   通用算法依赖迭代器实现,可以从头到尾遍历整个容器的方法
   for_each()  find find_if  count count_if sort copy
   iterator find(pos_beg, pos_end, data)
   iterator find_if(pos_beg, pos_end, cond), bool cond(element)

   int count(...), int count_if(...)

#include<algorithm>
#include<iostream>

using namespace std;
template<typename T>
void print(T b, T e)
{
  while( b != e)
	cout << *b++ << endl; 
}

class Person
{
  string name;
  int age;
public:
  Person(const char* ch,int a):name(ch),age(a){}
  friend bool operator<(const Person &a,const Person &b)
  {
	return a.age<b.age;
  }
  friend ostream& operator<<(ostream& os,const Person& p)
  {
	return os<< p.name << ":" << p.age;
  }
};

int main()
{
  Person p[3] = {{"furong",23},{"zengge",28},{"chunge",35}};
  sort(p,p+3);
  print(p,p+3);
  return 0;
}
说明:STL中sort()函数模板默认使用“<”运算进行排序,重载类中的<运算符即可完成排序

 

1.2 容器(类模板)

  a.标准容器:

(1)序列(顺序)式容器(vector是个能够存放任意类型的动态数组,能够增加和压缩数据;deque适合首尾删除增加;list链表)

(2)关联式容器(set不允许重复;multiset允许重复;map不允许重复;multimap允许重复)
  迭代器(内部类iterator,支持* -> ++ == !=),用来访问容器里的内容
  插入迭代器,iostream迭代器,反向,const迭代器,
  五种迭代器:输入,输出,前向,双向,随机访问迭代器
  数组里面,指针是最原始的迭代器;每种容器都自己负责封装迭代器类
 
   b.容器适配器(特殊容器):栈 队列 优先队列
 
   c.函数对象(仿函数):对象能像函数一样使用,比如重载()运算符
 

   d.内存分配器allocator



2 标准容器(类模板)共性

   构造函数(包括无参构造,拷贝构造,区间构造(两个迭代器表示的两个位置))
   析构函数
   迭代器相关函数:.begin()正向iterator,返回指向第一个元素位置的迭代器  
           .end()返回指向超越最后一个位置的迭代器
           .rbegin()反向reverse_iterator,反向迭代器
           .rend()
   标准都支持 *  ->  ==  ++  --  =  !=
   插入:.insert(pos,element)  其中pos是个表示位置的迭代器
   删除:.erase(pos), .erase(pos_beg,pos_end)
   清除:.clear() 清除容器里所以的数据
   大小:.size()  .max_size()
   交换:.swap(c2)  .swap(c1,c2)

   运算:=  >  <  >=  <=  ==  !=

#include<vector>
#include<iostream>
#include<algorithm>
#include"print.h"
using namespace std;

int main()
{
  //vector区间初始化
  int a[7] = {12,45,67,59,98,67,89};
  vector<int> v(a,a+7);
  //迭代器(封装指针)输出
  vector<int>::iterator b = v.begin();//声明迭代器
  while(b != v.end())
	cout << *b++ <<"\t";
  cout << endl;
  //sort()
  sort(v.begin(),v.end());
  cout << "vector排序后:" << endl;
  print(v.begin(),v.end());
  cout << "数组a内容:" << endl;
  print(a,a+7);
  //insert()插入方法为:在当前迭代器位置的前方插入
  b = v.begin();
  v.insert(b,128);
  v.insert(v.end(),256);//128 12 45 59 67 67 89 98 256 
  //v.erase(++++b,b+4); 注意操作危险,vector动态管理内存,迭代器指向可能失效
  v.erase(++v.begin(),++++v.begin());//删除方式:[ )
  print(v.begin(),v.end());
  //交换swap()
  vector<int> vv(a+3,a+7);
  vv.swap(v);
  cout << "v:" ;
  print(v.begin(),v.end());
  cout << "vv:" ;
  print(vv.begin(),vv.end());
  return 0;
}


3 序列式共性vector deque list:

  构造函数:增加了指定元素个数和初始值(初始值默认是0)
  插入:.insert(pos,n,element)  .insert(pos,pos_beg,pos_end)
  赋值:.assign(n,element)  .assign(pos_beg,pos_end) 旧的全部清理掉新的全部插入进来
  调整:.resize(n,element=0)  
  首尾:.front(), .back()  可以修改首尾元素的值
  增删:.push_back(element)  .pop_back() 只删除,返回void

#include<list>
#include<iostream>
#include"print.h"
#include<string>
#include<deque>
using namespace std;

int main()
{
  string str[5] = {"woshi","nihao","shide","haoren","yushi"};
  list<string> lstr(5,"*");//默认为零初始化
  lstr.insert(lstr.begin(),str,str+5);//区间插入
  print(lstr.begin(),lstr.end());
  deque<string> dstr(str,str+5);//区间初始化
  dstr.insert(dstr.begin(),str+2,str+5);//区间插入
  cout << "dstr = ";
  print(dstr.begin(),dstr.end());
  lstr.assign(5,"fuck you!");//覆盖赋值
  lstr.assign(++lstr.begin(),++++++lstr.begin());//删掉了?
  print(lstr.begin(),lstr.end());
  lstr.resize(12,"love");//填充式扩展
  print(lstr.begin(),lstr.end());
  return 0;
}


  3.1 vector个性

     vector迭代器在插入删除之后可能会失效因为可能会重新分配内存,如果插入删除过再用迭代器需要重新去取得
     当前容量:.capacity()
     约定容量:.reserver(n)只要不超过这个容量就不用重新再分配,以免反复重新分配空间
     下标[]:   .operator[](i)不检查越界  .at(i)这个函数做越界检查,越界会抛出异常

#include<iostream>
#include<vector>
#include"print.h"
#include<typeinfo>
using namespace std;

int main()
{
  //测试vector容量分配规律:1 2 4 8 
  vector<double> dv;
  for(int i = 0;i < 10; i++)
  {
	dv.insert(dv.end(),i+0.1);
    cout << "有效/容量:" << dv.size() << "/" <<dv.capacity()<<"\t";
  }
  cout << endl<< "约定容量:" << endl;
  vector<double> dd;
  dd.reserve(9);
  for(int i = 0;i < 10; i++)
  {
	dd.insert(dd.end(),i+0.1);
    cout << "有效/容量:" << dd.size() << "/" <<dd.capacity()<<"\t";
  }
  //测试越界访问检查
  cout << endl<< "dv[10] = " << dv[10] << endl ;
  try{
  cout << "dv.at(10)" << dv.at(10) << endl;
  }
  catch(exception &e)
  {
	cout << "异常:" << e.what() <<endl;
	cout << "类型:" << typeid(e).name()<< endl;
  }
  //vector二维动态数组
  vector< vector<int> > vvi(5,vector<int>(3,128));   //注意 > >中间空格
  vvi[1].assign(3,12);
  vvi[4].assign(5,25);
  for(int i = 0; i < vvi.size();i++)
  {
	for(int j = 0; j < vvi[i].size();j++)
	  cout << vvi[i][j] << " ";
	cout << endl;
  }
  return 0;
}


  3.2 deque的个性

    下标[]: .operator[](i) 不检查越界, .at(i)越界抛异常
     增删: .push_front(element), .push_back() .pop_front() .pop_back()
        适合从前面插入或删除数据
      

  3.3 list的个性(双向链表 )

    增删:.push_front(element), .pop_front(), .remove(element)//==
    不支持下标[]
    除重:.unique()相邻的重复元素只保留一个
    排序:.sort(compare_func=less)默认用小于符号比较,从小到大排序
    倒置:.reverse()颠倒链表中元素顺序
    转移:.splice(pos,list2), .splice(pos,list2,pos2), .splice                              (pos,list2,pos_beg,pos_end)
    归并:.merge(list2)

#include<list>
#include<iostream>
#include"print.h"
using namespace std;

template<typename T>
bool compare(T a,T b)
{
  return a/10 > b/20;
}
int main()
{
  double dd[6] = {12.1,13.5,25.6,78.9,12.1,12.1};
  list<double> ld(dd,dd+6);
  //排序 指定大小顺序
  ld.sort(greater<double>());
  //排序 指定排序法则
  ld.sort(compare<double>);
  //除重  相邻的重复元素只保留一个
  ld.unique();
  print(ld.begin(),ld.end());
  return 0;
}

4 关联式容器的共性   set<K>,  multiset<K>, map<K,V>, multimap<K,V>

都是用二叉查找树实现的,都自动根据关键字排序

  查找:.find(key)返回一个迭代器指向找到的第一个元素,失败返回.end()
  统计:.count(key)统计关键字等于key的元素的个数
  删除:.erase(key)删除关键字等于key的所有元素
  区间:.lower_bound(key)取得关键字为key的第一个元素的位置, .upper_bound(key)取得关键字为key的最后一个元素之后的位置; .equal_range(key)一次取得关键字为key的元素的区间,返回一个pair
  插入: .insert(element)

#include<set>
#include<iostream>
#include"print.h"

using namespace std;

//set类型:date
class date
{
  int year;
  int month;
  int day;
public:
  date(int y,int m,int d):year(y),month(m),day(d){};
  friend bool operator<(date d1,date d2);
  friend ostream& operator<<(ostream &os,const date &d);
};

//重载"<"运算符 
bool operator<(date d1,date d2)
{
  if(d1.year < d2.year) return 1;
  else if(d1.year == d2.year)
  {
	if(d1.month < d2.month) return 1;
	else if(d1.month == d2.month)
	{
	  if(d1.day < d2.day) return 1;
	  else return 0;
	}
	else return 0;
  }
  else return 0;
}

//重载"<<"运算符
ostream& operator<<(ostream &os,const date &d)//形参2为临时变量
{
  return os<< d.year << "-" << d.month << "-" << d.day;
}

int main()
{
  multiset<date> md;
  md.insert(date(1990,10,12));
  md.insert(date(1990,10,12));
  md.insert(date(1990,10,12));
  md.insert(date(1991,1,12));
  md.insert(date(1992,1,12));
  md.insert(date(1992,1,12));
  md.insert(date(1992,1,12));
  md.insert(date(1991,4,12));
  md.insert(date(1991,1,15));
  print(md.begin(),md.end(),'\n');
  
  //查找.find()
  typedef multiset<date>::iterator MI; 
  MI it = md.find(date(1990,10,12));
  if(it == md.end()) cout << "结果不存在!" << endl;
  else cout << "发现目标:" << *it << endl;
  //统计.count()
  it = md.find(date(1990,10,12));
  cout << "发现目标:" << md.count(*it) << "个" << endl;
  //删除关键字项 .erase()
  md.erase(date(1990,10,12));
  print(md.begin(),md.end(),'\n');
  cout << "************************" << endl;
  //查找关键字区间
  MI ib,ie;
  ib = md.lower_bound(date(1992,1,12));
  ie = md.upper_bound(date(1992,1,12));
  print(ib,ie,'\n');
   cout << "************************" << endl;
  pair<MI,MI> p = md.equal_range(date(1992,1,12));
  print(p.first,p.second,'\n');
  return 0;
}
 

   4.1 map的个性

    不允许key重复 ,强调元素是map(key,value)一对
    支持以key为下标访问对应的value的引用,如果key不存在就新增一个元素以这个为key,别的关联式容器不支持以Key为下标
    如果存的强调是对应关系就用map,如果存的只是关心的数据不存在对应关系就用set,set把整个元素作为key来比较。
 

#include<map>
#include<iostream>
#include<string>
#include"print.h"
using namespace std;

int main()
{
  map<int , string> mis;
  //map插入方法,形参为pair或value_type
  mis.insert(map<int,string>::value_type(1,"处女座"));
  mis.insert(pair<int,string>(2,"天秤座"));
  mis.insert(make_pair(3,"双子座"));
  print(mis.begin(),mis.end(),'\n');
  cout << "*************************" << endl;
  //下标操作
  mis[1] = "射手座";
  //关键字插入处理
  mis.insert(make_pair(3,"金牛座")); //关键字没有-插入,重复-不插入
  print(mis.begin(),mis.end(),'\n');
  return 0;
}

#ifndef _PRINT
#define _PRINT 1
#include<iostream>
using namespace std;

template<typename T>
void print(T b,T e,char c)
{
  while(b != e)
	  cout << *b++ << c;
}

template<typename K,typename V>
ostream& operator<<(ostream& os, const pair<K,V>& p)
{
  return os << p.first << ":" << p.second;
}
#endif


   4.2 multimap的个性

  允许重复key ,元素是(key/value)pair对,不支持方括号下标

#include<iostream>
#include<map>
#include<string>
#include"print.h"

using namespace std;

int main()
{
  typedef multimap<string,int> MMSI;
  typedef map<string,int> MSI;
  MMSI mmsi;
  MSI msi;
  mmsi.insert(make_pair("春哥",1000));
  mmsi.insert(make_pair("曾哥",2000));
  mmsi.insert(make_pair("春哥",5000));
  mmsi.insert(make_pair("曾哥",2000));
  mmsi.insert(make_pair("春哥",5000));
  mmsi.insert(make_pair("曾哥",2000));
  mmsi.insert(make_pair("春哥",3000));
  //print(mmsi.begin(),mmsi.end(),'\n');
  //收入统计
  MMSI::iterator ia,ib; //每个迭代器都是一个pair对
  ia = mmsi.begin();
  while(ia != mmsi.end())
  {
	int sum = 0;
	string name = ia->first;
	ib = mmsi.upper_bound(name);
	while(ia != ib) sum += ia++->second;
	msi.insert(make_pair(name,sum));
  }
  print(msi.begin(),msi.end(),'\n');
  return 0;
}


  4.3 set的个性

   元素就是key, 不允许重复key,如果重复就会被抛弃,可以默认被排好序
 

#include<set>
#include<iostream>
#include<string>
#include<fstream>
#include"print.h"
using namespace std;

int main()
{
  set<string> ss;
  ifstream fin("strlist");
  if(!fin) 
  {
	cout << "打开文件失败" << endl;
	return 1;
  }
  string s;
  while(fin >> s) ss.insert(s); //去除相同项
  print(ss.begin(),ss.end(),'\n');
  return 0;
}

 

  4.4 multiset的个性

    元素就是key,允许有重复的key

#include<iostream>
#include<set>
#include<map>
#include<string>
#include"print.h"

using namespace std;

int main()
{
  typedef multiset<string> MS;
  typedef multimap<string,int> MSI;
  MS ms;
  MSI msi;
  string name;
  cout << "输入候选人名称(sky/moon/09): ctrl + d结束"<< endl;
  while(cin >> name)
  {
	ms.insert(name);
  }
  MS::iterator ib = ms.begin(),ie;
  
  while(ib != ms.end())
  {
	msi.insert(make_pair(*ib,ms.count(*ib)));
	ib = ms.upper_bound(*ib);
  }
  
  print(msi.begin(),msi.end(),'\n');
  return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值