C++学习笔记11_STL

STL又叫标准模板库,提供各种容器。

STL是C++一部分,不休要额外安装什么,它被内建在编译器之内。

STL重要特点是,数据结构和实现分离。

*所谓迭代器,类似一个游标,使用++指向下一个元素,使用--指向前一个元素。实际上“迭代器”是一个对象,封装了指针,重载了操作符。

 

1.  动态数组,可变数组

#include<vector>//存放容器的

#include<algorithm>//STL的算法

void CallBackPrintVector(int v)//因为知道迭代器是vector<int>,所以形参为int

{

  cout<<v<<end;

}

int main()

{

  vecotor<int>  v;

  v.push_back(10);//添加元素

  //通过STL提供的算法,进行遍历。容器提供迭代器,迭代器作为for_each参数。v.begin()提供一个开始的迭代器。

     vector<int> ::iterator pBegin = v.begin();// vector<int> ::iterator可能是内部类。begin是指向第一个元素

     vector<int> ::iterator pEnd = v.end();//end是指向最后一个元素,再后一个位

  for_each(pBegin , pEnd , CallBackPrintVector) ;

   //for_each其实是一个算法, 传入beign和end,实质上是为了判断什么时候结束迭代。传入回调函数,是每次迭代都触发。

  //也可以:

  for(vector<int> ::iterator  it=pBegin; it!=pEnd; it++)

  {

    CallBackPrintVector(*it);//应该是重写了*号操作符。

  }

}

 for_each还可以:

class/struct Op{  void operator()(int a) ;}

for_each(pBegin , pEnd , Op()) ;//传入重写()操作符的Op类的匿名对象

//

反向迭代器 v.rbegin(),v.rend()

// 

vector实现动态增长:如果空间不足,会重新申请更大的内存,将原空间的数据拷贝到新空间,再将新元素插入。所以叫动态数组。

//

v.size();//返回元素个数;

//

v.resize(10,(重载)多出来部分的默认值);//如果容器变短,那么超出的元素被剔除;

//

v.empty();//判断是否为空;

//

v.capacity();//获取容量,根据插入原理,每次都拷贝数据到新空间,会很低效,所以有大于size的容量;

//

vector支持随机访问,意思是,v.insert(v.begin()+2,100);//v.begin()+2就是随机访问,可以任意跳。其他容器就不一定了,可能只能进行++操作

//

vector在删除的时候,并不会自动收缩内存区域,所以要 verctor<int>(v).swap(v)   ,以收缩空间。首先,vector<int>(v),是以v来实例化一个匿名的对象,长队和v一样,然后vector<int>(v).swap(v),将匿名对象的指针,和v交换。也可以v.resize()

//

v.reserve(10000);//在调用push_back前预留空间,这样子的话,就不需要在空间不够的时候,重新开辟,然后拷贝了。只是开辟内存空间,没有初始化的。

//

2. string容器

char *是指针,string是类

string封装了char*,管理这个字符串,是一个char*容器

不用考虑内存释放,越界

int main()

{

  string s1;

  string s2(10,'a');

  string s3("absdfasdf");

  string s4(s3);

  

  for(int i=0;i<s1.size();i++)

  {

    s1[i];//如果用中括号形式,访问越界,直接挂了,没有办法捕获异常。重写了[]符号

    s1.at(i);//访问越界,会抛出异常 out_of_range

  }

}

find()从前往后查找。int index= find("aaa");

rfind()从后先前查找

//字符串比较

if(s1.compare(s2)==0)

{

  //相等

}

//字符串擦除

s.erase(0,2);

//char*转string

int main(){

  char *s = "aaa";

  string sstr(s);

}

//string转char*

int main(){

  string str ="aaa";

  const char* cstr = str.c_str();

}

 

3. Deque容器

在头部和尾部插入,删除,都很快的容器。

可随机存取,效率高。(应该是连续的内存空间)

.push_back():从尾部插入

.pop_back():从尾部删除

.push_front():从头部插入

.pop_front():从头部删除

.begin() 头部迭代器

.front():返回第一个元素

d1.swap(d2):交换两个空间的元素

#include<deque>

int main()

{

  deque<int> d1;

  deque<int> d2(10,5);//用10个5初始化

  deque<int> d3(d2.begin(),de.end());

  deque<int> d4(d3);

  for(deque<int>::iterator it=d4.begin();it!=d4.end();it++)

  {

    cout<< *it;

  }

  cout<<endl;

}

 **排序函数

void print(int e);

int main()

{

  deque<int> de;

  de.push_back(10);

  de.push_back(11);

  //...

  sort(de.begin(),de.end());//排序,应该是跟for_each,是一个在deque头文件中声明的函数

  for_each(de.begin(),de.end(),print);  

  de.pop_front();//删除第一个元素

  de.pon_back();//删除最后一个元素

}

 

4.  对于sort的特别使用

class Person

{

  public:

  int age;

  string Name;

  Person(int age,char * Name);

}

//排序规则

bool compareCallblack(Person &p1, Person&p2)

{

  return p1.age < p2.age;//这里决定是正序还是倒序,<是从小到大排序

}

int main()

{

  Person p1(1,"tom"),p2(2,"marry");

  Vector ps ;

  ps.push_back(p1);

  ps.push_back(p2);

  sort(ps.begin(),ps.end(),compareCallblack);

}

 

5. stack 容器,先进后出的容器

push():压栈

pop():出栈,删除最后入栈的

top():获取栈顶元素

注意:栈不能遍历,不提供迭代器,更不支持随机存取

#include<int>

int main()

{

  stack<int> s1;

  stack<int> s2(s1);

  s1.push(10);

  s1.push(20);

  s1.push(30);//栈顶

  s1.pop();//删除栈顶元素

  while(!s1.empty())

  {

    cout<<s1.top();

    s1.pop();

  }

}

 

6. queue容器

先进先出,在一端插入,另一端出

push():入队操作

pop():删除队头,即删除最先如队的

front():队头元素,即最先入队的

注意:队列不能遍历,不提供迭代器,更不支持随机存取

int main()

{

  queue<int> q;

  q.push(1);

  q.push(2);

  q.push(3);

  q.push(4);

  while(q.size()>0)

  {

    cout<<q.front();

    q.pop();

  }

}

//输出1234

 

7. List容器

链表,包含数据域和指针域,链表内存结构是非连续的

添加删除元素,时间复杂度都是常数,不需要移动数据。

链表的内存没有像vector一样,有所预留。

提供迭代器。

List不支持随机访问,一般sort都要支持随机访问的,所以,List自己提供sort算法。

int main()

{

  list<int> mlist;

  list<int> milist2(10,10);

  list<int> mlist3(mlist2.begin(),mlist2.end());

  //

  mlist.insert(mlist.begin(),200);//在从头插入

  mlist.insert(mlist.end(),200);//在尾插入

  //

  mlist.pop_back();//删除最后一个

  mlist.remove(200);//能去除所有200的值,应该有重载,能调像sort一样,删除符合条件的值

  //

  for(list<int>::iterator it=mlist3.begin();it!=mlist3.end();it++)

  {

    cout<< *it;

  }

}

mlist.push_back();//往后插入

mlist.push_front();//往前插入

mlist.sort(compareCallblack);//排序

 

8. set容器

//是基于二叉树算法的容器,二叉树是用于查找数据的一种优化算法

set只提供insert()方法,因为是自动排序的,所以没有其他方法添加数据

set不能插入重复元素

set要改变元素的值,只能先删除,再插入

int mian()

{

  set<int > s1;

  s1.insert(1);

  //...

  for(set<int >::itertor it=s1.begin();it!=s1.end();it++)

  {

     cout<s1;

  }

}

注意:无论按什么顺序插入,set会根据算法自动排序,所以按顺序插入是没有意义的。而且其遍历方法,分为先序,中序,后序方法。

s.erase(value);//删除

s.erase(s.begin());//

multset容器可以放重复元素,这是与set唯一的区别

//查找

set只有实只(map有key和value(实)值)

s.find(key);//查找key是否存在,如果存在,返回该元素的迭代器,否则,返回s.end(); 注意: end是指向比最后一个元素还要后的位置的

int main()

{

  set<int > s;

  set<int>::interator ret= s.find(4);

  if(ret==s.end())

  {

    cout<<"not found"<<endl;

  }

  //查找大于

  set<int> ::interator s1.lower_bound(2);//找第一个小于等于其值的

  set<int> ::interator s1.upper_bound(2);//找第一个大于等于其值的

  pair< set<int>::iterartor, set<int>::iterartor>  pairIterator = s1.equal_range(2);//返回upper_bound和lower_bound的结果

  pairIterator .first;

  pairIterator .secord;

  if(pairIterator .first==s1.end())

  {}

}

 set制定一个排序规则

例一:

//C++坑真多,和sort又不一样了

class mycmopare

{

  public :

    bool operator()(inv v1,int v2)

    {

      return v1>v2;

    }

}

int main()

{

  set<int ,mycmopare> s1;//估计里面自行实例化一个对象,然后调用operator排序

  s1.insert(7);

  s1.insert(6);

}

例二:

class person

{

  public:

    int age;

    string Name;

    person(int age,string name);

}

//仿函数

class mycompare

{

  bool operator()(person &p1, person&p2) 

  {

    return p1.age>p2.age;

  }

}

int main()

{

  ser<person,mycompare> sp;//set需要排序,当放对象前,需要告知其排序准则,所以在构造前要模板形式传入

  person p1=person(10,"a"),p2=person(1,"b")

  sp.insert(p1);

  sp.insert(p2);

  for(set<person,mycompare>::iterator it=sp.begin();it!=sp.end();ip++)

  {

    cout<<(*sp).age<<endl;

  }

  //

  p3 = person(1,"c")

  sp.find(p3);//这样是可以查到的,因为是根据mycompare重载()操作符函数,是以age排序的。

}

 9.  Map容器

Map会根据Key自动排序,Map封装了pair类;

不支持随机访问

#include<map>

int main()

{

  map<int , int > mymap;

    pair<map<int,int>::iterator,bool> ret = mymap.insert(pair<int,int>(1,1)); //创建匿名的pair<int,int>对象放进去

  //返回迭代器,以及是否成功的pair对象

  if(ret->second)

  {

    cout<<"插入成功"<<endl;

  }

  mymap.insert(make_pair(2,1));

  mymap.insert(map<int,int>::value_type(3,1));

  mymap[40]=40;//第四种构造方式,如果key不存在,那么就插入pair,如果Key存在,就修改value值。如果cout<<mymap[40]<<endl,key不存在的话,也会插入,并赋一个默认值。

  for(map<int,int>::iterator it = mymap.begin();it!=mymap.end();i++)

  {

    cout<<"key:"<<(*it).first<<"value:"<<it->second;

  }

}

//

例二:

class   person

{

  public :  

    string Name;

    person(string name):Name(name);

}

struct mycompare//可以写成类,偷懒就写struct

{

  bool operator()(person &p1,person &p2)

  {

    return p1.Name!=p2.Name;  

  }

}

int main()

{

  map<person,int,mycompare> mymap; //由于要自动排序,自定义的数据类型,要告知其排序规则

  mymap.insert(make_pair(person("tom"),20));

}

 

 

10. multimap

//multimap的key可以相同,而且相同key的键值,放在连续的存储空间

//类似于部门和员工,Key是部门id

.count(key);//返回key的元素个数

int main()

{

  multimap<int , Worker> workerGroup;

  workerGroup.insert(make_pair(1,Worker("张三")));

  //按组打印

  multlmap<int,worker> ::iterator it = workerGroup.find(1);//返回针对一个Key的迭代器,迭代下去,能遍历这个key的所有value

  int count = workerGroup.count(1);

  for(int i=0;i<count;i++,it++)

  {

    cout<<it->second.workername<<endl;

  }

}

 

11. 函数元素的深拷贝和浅拷贝

元素是如何放进容器中的?用引用,还是浅拷贝,还是深拷贝?

如果元素存在指针成员,就涉及浅拷贝问题。

元素放到容器中,是进行浅拷贝的,所以,放到容器中的元素,要重写拷贝构造函数、析构函数。

 

12.  函数对象,仿函数
class A

{

  public :  bool  operator (const  int  &a);

}

int main()

{

  A a;

  a();//仿函数调用,容器也是这个原理,那么就不需要使用函数指针了

}

 

13. 绑定适配器

#include <vector>

#include<algorithm>

#include<functional>

struct P

{

   void operator()(int v)

  {}

}

int main()

{

  verctor<int> a;

  a.push_back(1);

  //..

  for_each(a.being(),a.end(),P());//传入一个重写()操作符的匿名对象

}

 //但是,因为operator只能传一个参数,而且这个参数是for_each内赋值的,要想传多一个参数,那么:

struct Pp:public binary_function<int,int,void> //这里第一个int应该是int v中的 ,第二个int是 inv val中的,第三个,应void operator()的void

{

  

  void operator()(int v,int val)

  {}

}

//

for_each(a.being(),a.end(), bind2nd( P() , 1000 ));

//绑定适配器,将一个一元函数对象,变为二元的

猜测:

struct bind2nd

{

  bind2nd(binary_function<int,int,void> p, int val);

  binary_function<int,int,void>  P;

  int val;

  void operator()(int v)

  {

     return P(v,val);

  }

}

 

14. 取反适配器

not2

struct cmp

{

    bool operator()(int a,int b)

  {

    return a>b;

  }

}

void main()

{

  vector<int> v;

  v.push_back(1);

  //...

  sort(v.begin(),v.end(),cmp());//不传cmp()匿名对象,那么就按升序排了。

}

//使用适配器 not2

 

struct cmp2:public binary_function<int,int,bool>

    bool operator()(int a,int b)

  {

    return a>b;

  } 

}

sort(v.begin(),b.end(),not2(cmp2)); //这里的效果是,对cmp2的结果,再取反,又变回从小到大了。

 

取反适配器not1,针对一元对象

struct cmp3

    bool operator()(int a)

  {

    return a>5;

  } 

}

vector<int>::iterator it = find_if(v.begin(),v.end(),cmp3());//返回大于5的

//

struct cmp4: public unary_fuction<int,bool>

    bool operator()(int a)

  {

    return a>5;

  } 

}

//

vector<int>::iterator it = find_if(v.begin(),v.end(),not1(cmp4()));//此时返回小于5的

//

注意,判断方法:

if(it==v.end())

{

  cout<<"not found"<<endl;

 }

 

15. 函数对象适配器

ptr_func

void fun1(int v)

{

    

}

void fun2(int v,int val)

{

    

}

int main()

{

  vector<int> v;

  //..

  for_each(v.begin(),v.end(), ptr_func( fun1));//不传对象也行,传函数名

  //

  for_each(v.begin(),v.end(), bind2ndptr_func( fun2), 10));//不传对象也行,传函数名

}

 

16. 成员函数适配器

mem_fun_ref(存放的对象),mem_fun(存放的是指针)

如果容器中,存放的是对象,那么for_each中,希望调用类的方法

class person

{

  public:

    string name;

    void show();//不需要传参,因为本身就带person *const this;

}

void main()

{

  vecotor<person> v;

  v.push_back(person("zhangsan"));

  //..

  for_each(v.begin(),v.end(),mem_fun_ref(&Person::show));

}

//如果放的是对象指针

void main()

{

  vecotor<person*> v;

  v.push_back(&(person("zhangsan")));

  //..

  for_each(v.begin(),v.end(),mem_fun(&Person::show));

}

 

17. 其他函数

 find

void int main()

{

  vector<int> v;

  v.push_bakc(10);

  //..

  vector<int>::iterator ret = find(v.begin(),v.end(),8);

  if(ret!=v.end()) { cout<<"found"<<endl;}

  //

}

//

class person

{

  public: 

    int id;

    int age;

    person(int id,int age) :id(id),age(age);

    

       bool operator ==(person &p) const // ==必须重载,因为find里面,将匿名对象作为const引用,并调用==操作符重载方法。(const对象,成员方法必须标记为const)

    {

      return p.id==this->id;

    }

}

int main()

{

  vecotor<person> v1;

  v1.push_back(person(1,2));

  v1.push_back(person(2,2));

  verctor<person> ::iterator ret = find(v.begin(),v.end(),p1); //

}

binary_serch 二分查找法

返回bool类型,只能告知有没有找到

int main()

{

  vector<int> v;

  v.push_back(1);

  //..

  bool ret = binary_serch(v.begin(),v.end(),1);

  //

}

 

adiacent_find

查找相邻重复的元素迭代器

vector<int> :: iterator it=adiacent_find(v.begin(),v.end());

 

find_if

根据条件,查找第一个

bool cp(int val)

{

  return val > 3;

}

vector<int>::iterator =  find_if(v.begin(),v.end(),cp);//估计传过去,就F()这样的,或TT++这样,*TT这样,直接调传过去的()、++、*这样的操作符函数。

 

count_if

int  num = count_if(v.begin(),v.end(),cp);

 

转载于:https://www.cnblogs.com/pylblog/p/9830108.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值