zoukankan      html  css  js  c++  java
  • 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);

  • 相关阅读:
    字典序全排列算法研究
    【转】 SVM算法入门
    孤儿进程与僵尸进程[总结]
    Thymeleaf——入门与基本概述
    Springboot+vue项目学习整合(-)vue的安装
    WebService技术详解 (一)
    什么是NOSQL(SQL和NOSQL对比图文详解)
    数据库优化和扩容(图文详解)
    Spring Cloud原理详解(附案例+五大核心组件大量手绘图)
    spring STS download URL
  • 原文地址:https://www.cnblogs.com/pylblog/p/9830108.html
Copyright © 2011-2022 走看看