zoukankan      html  css  js  c++  java
  • STL基础学习(STL中的容器解析、代码展示、例题分析,帮助你学STL)

    STL就是Standard Template Library(C++标准模板库),下面是关于STL中的各种内容

    STL中的几个基本概念:

    1.容器:可容纳各种数据类型的数据结构。

    可以用于存放各种类型的数据(基本类型的变量,对象等)的数据结构。
    容器分为三大类:
    (1) 顺序容器  
    vector:后部插入/删除,直接访问 deque:前/后部插入/删除,直接访问 list:双向链表,任意位置插入/删除

    1) vector  头文件 <vector>
        实际上就是个动态数组。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能。
     2) deque   头文件 <deque>
        也是个动态数组,随机存取任何元素都能在常数时间完成(但性能次于vector)。在两端增删元素具有较佳的性能。
     3) list    头文件 <list> 
        双向链表,在任何位置增删元素都能在常数时间完成。不支持随机存取。
       上述三种容器称为顺序容器,是因为元素的插入位置同元素的值无关。
    ( 2)关联容器
    set:快速查找,无重复元素 multiset :快速查找,可有重复元素 map:一对一映射,无重复元素,基于关键字查找 multimap :一对一映射,可有重复元素,基于关键字查找,前2者合称为第一类容器 

    关联式容器内的元素是排序的,插入任何元素,都按相应的排序准则来确定其位置。关联式容器的特点是在查找时具有非常好的性能。
    1) set/multiset:   头文件 <set>
       set 即集合。set中不允许相同元素,multiset中允许存在相同的元素。
    2) map/multimap:   头文件 <map>
       map与set的不同在于map中存放的是成对的key/value。
       并根据key对元素进行排序,可快速地根据key来检索元素
       map同multimap的不同在于是否允许多个元素有相同的key值。
       上述4种容器通常以平衡二叉树方式实现,插入和检索的时间都是 O(logN)
    (3)容器适配器
    stack:LIFO queue:FIFO priority_queue:优先级高的元素先出 

    对象被插入容器中时,被插入的是对象的一个复制品。
    许多算法,比如排序,查找,要求对容器中的元素进行比较,所以,放入容器的对象所属的类,还应该实现 == 和 < 运算符。
    1) stack  :头文件 <stack>
    栈。是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项。即按照后进先出的原则
    2) queue :头文件 <queue>
       队列。插入只可以在尾部进行,删除、检索和修改只允许从头部进行。按照先进先出的原则。
    3)priority_queue :头文件 <queue>
    优先级队列。最高优先级元素总是第一个出列

    所有标准库容器共有的成员函数:
    相当于按词典顺序比较两个容器大小的运算符:   =, < , <= , >  , >=, == , !=
    empty : 判断容器中是否有元素
    max_size: 容器中最多能装多少元素
    size:   容器中元素个数
    swap: 交换两个容器的内容
    只在第一类容器中的函数:
    begin  返回指向容器中第一个元素的迭代器
    end     返回指向容器中最后一个元素后面的位置的迭代器
    rbegin  返回指向容器中最后一个元素的迭代器
    rend    返回指向容器中第一个元素前面的位置的迭代器
    erase   从容器中删除一个或几个元素
    clear   从容器中删除所有元素

    2.迭代器:可依次存取容器中元素的东西

    用于指向第一类容器中的元素。有const 和非 const两种。
    通过迭代器可以读取它指向的元素,通过非const迭代器还能修改其指向的元素。迭代器用法和指针类似。
    定义一个容器类的迭代器的方法可以是:
    容器类名::iterator   变量名;
    或:
    容器类名::const_iterator 变量名;
    访问一个迭代器指向的元素:
    * 迭代器变量名
    迭代器上可以执行 ++ 操作, 以指向容器中的下一个元素。如果迭代器到达了容器中的最后一个元素的后面,则迭代器变成past-the-end值。
    使用一个past-the-end值的迭代器来访问对象是非法的,就好像使用NULL或未初始化的指针一样。

    算法:用来操作容器中的元素的函数模板。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象。
    函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用。
    比如,数组int array[100]就是个容器,而 int * 类型的指针变量就可以作为迭代器,可以为这个容器编写一个排序的算法,以下是各种算法:

    #include <vector>
    #include <iostream>
    using namespace std;
    int main()  {
    vector<int> v; //一个存放int元素的向量,一开始里面没有元素
    v.push_back(1);
    v.push_back(2); 
    v.push_back(3);  
    v.push_back(4);
    vector<int>::const_iterator i;   //常量迭代器
    for( i = v.begin();i != v.end();i ++ ) 
    cout << * i << ",";
    cout << endl;

    vector<int>::reverse_iterator r;  //反向迭代器
    for( r = v.rbegin();r != v.rend();r++ ) 
    cout << * r << ",";
    cout << endl;
    vector<int>::iterator j;   //非常量迭代器
    for( j = v.begin();j != v.end();j ++ ) 
    * j =  100;
    for( i = v.begin();i != v.end();i++ ) 
    cout << * i << ",";
    }
    输出结果:
    1,2,3,4,
    4,3,2,1,
    100,100,100,100,

    STL 中的迭代器按功能由弱到强分为5种:
       1. 输入:Input iterators 提供对数据的只读访问。
       1. 输出:Output iterators 提供对数据的只写访问
       2. 正向:Forward iterators 提供读写操作,并能一次一个地向前推进迭代器。
       3. 双向:Bidirectional iterators提供读写操作,并能一次一个地向前和向后移动。
       4. 随机访问:Random access iterators提供读写操作,并能在数据中随机移动。
    编号大的迭代器拥有编号小的迭代器的所有功能,能当作编号小的迭代器使用。

    不同迭代器所能进行的操作(功能):

    所有迭代器: ++p, p ++
    输入迭代器: * p, p = p1, p == p1 , p!= p1
    输出迭代器: * p, p = p1
    正向迭代器: 上面全部
    双向迭代器: 上面全部,--p, p --,
    随机访问迭代器: 上面全部,以及:
    p+= i, p -= i, 
    p + i: 返回指向 p 后面的第i个元素的迭代器
    p - i: 返回指向 p 前面的第i个元素的迭代器
    p[i]:  p 后面的第i个元素的引用
    p < p1, p <= p1, p > p1, p>= p1
    容器所支持的迭代器类别:

    容器 迭代器类别
    vector 随机
    deque 随机
    list  双向
    set/multiset 双向
    map/multimap 双向
    stack 不支持迭代器
    queue 不支持迭代器
    priority_queue 不支持迭代器
    例如,vector的迭代器是随机迭代器,所以遍历 vector 可以有以下几种做法:
    vector<int> v(100);
    vector<int>::value_type i; //等效于写 int i;(P687)
    for(i = 0;i < v.size() ; i ++)
    cout << v[i];
    vector<int>::const_iterator ii;
    for( ii = v.begin(); ii != v.end ();ii ++ )
    cout << * ii;
    //间隔一个输出:
    ii = v.begin();
    while( ii < v.end()) {
    cout << * ii;  
    ii = ii + 2; 
    }

    而 list 的迭代器是双向迭代器,所以以下代码可以:
    list<int> v;
    list<int>::const_iterator ii;
    for( ii = v.begin(); ii != v.end ();ii ++ )
    cout << * ii;
    以下代码则不行:
    for( ii = v.begin(); ii < v.end ();ii ++ )
    cout << * ii;
    //双向迭代器不支持 <
    for(int i = 0;i < v.size() ; i ++)
    cout << v[i]; //双向迭代器不支持 []
    例子:

    #include <vector>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    main()  {
    int array[10] = {10,20,30,40};
    vector<int> v;
    v.push_back(1); v.push_back(2);
    v.push_back(3); v.push_back(4);
    vector<int>::iterator p;
    p = find(v.begin(),v.end(),3);
    if( p != v.end())
    cout << * p << endl;
    p = find(v.begin(),v.end(),9);
    if( p == v.end())
    cout << "not found " << endl;
    p = find(v.begin()+1,v.end()-2,1);
    if( p != v.end())
    cout << * p << endl;
    int * pp = find( array,array+4,20);
    cout << * pp << endl;
    }
    输出:
    3
    not found
    3
    20


    例:
    int main()  { int i;
    int a[5] = {1,2,3,4,5 };    vector<int>  v(5);
    cout << v.end()  - v.begin() << endl;
    for( i = 0;i < v.size();i ++ )  v[i] = i;
    v.at(4) = 100;
    for( i = 0;i < v.size();i ++ )
    cout << v[i] << "," ;
    cout << endl;
    vector<int> v2(a,a+5);  //构造函数
    v2.insert( v2.begin() + 2, 13 ); //在begin()+2位置插入 13
    for( i = 0;i < v2.size();i ++ )
    cout << v2[i] << "," ;    
                return 0;
    }

    输出:


    5
    0,1,2,3,100,
    1,2,13,3,4,5,


    例:
    int main()  {
    const int SIZE = 5;
    int a[SIZE] = {1,2,3,4,5 }; 
    vector<int> v (a,a+5);  //构造函数
    try {
    v.at(100) = 7;
    }
    catch( out_of_range e) {
    cout << e.what() << endl;
    }
    cout << v.front() << “,” << v.back() << endl;
    v.erase(v.begin());
    ostream_iterator<int> output(cout ,“*");
    copy (v.begin(),v.end(),output);
    v.erase( v.begin(),v.end());  //等效于 v.clear();


    if( v.empty ())
    cout << "empty" << endl;
    v.insert (v.begin(),a,a+SIZE);
    copy (v.begin(),v.end(),output);
    }  


    // 输出:
    invalid vector<T> subscript
    1,5
    2*3*4*5*empty
    1*2*3*4*5*

    关于 ostream_iterator, istream_iterator的例子
    int main()  {
    istream_iterator<int> inputInt(cin);
    int n1,n2;
    n1 = * inputInt; //读入 n1
    inputInt ++;   
    n2 = * inputInt; //读入 n2
    cout << n1 << "," << n2 << endl;
    ostream_iterator<int>> outputInt(cout);
    * outputInt = n1 + n2;  cout << endl;
    int a[5] = { 1,2,3,4,5};
    copy(a,a+5,outputInt);  //输出整个数组
                return 0;
    }

    程序运行后输入 78  90敲回车,则输出结果为:
    78,90
    168
    12345


    例';

    #include <set>
    #include <iostream>
    using namespace std;
    int main()  {
    typedef set<double,less<double> > double_set;
    const int SIZE = 5;
    double a[SIZE] = {2.1,4.2,9.5,2.1,3.7 };
    double_set doubleSet(a,a+SIZE);
    ostream_iterator<double> output(cout," ");
    cout << "1) ";
    copy(doubleSet.begin(),doubleSet.end(),output);
    cout << endl;
          pair<double_set::const_iterator, bool> p;
          p = doubleSet.insert(9.5); 
          if( p.second ) 
    cout << "2) " << * (p.first)  << " inserted" << endl;
          else
                cout << "2) " << * (p.first)  << " not inserted" << endl;
          return 0; }



    输出:
    1) 2.1 3.7 4.2 9.5
    2) 9.5 not inserted


    #include <iostream>
    #include <map>
    using namespace std;
    ostream & operator <<( ostream & o,const pair<  int,double> & p)
    {
    o << "(" << p.first  << "," << p.second << ")";
    return o;
    }
    int main()  {
    typedef map<int,double,less<int> > mmid;
    mmid pairs;
    cout << "1) " << pairs.count(15) << endl;
    pairs.insert(mmid::value_type(15,2.7));
    pairs.insert(make_pair(15,99.3));//make_pair生成pair对象
    cout << "2) " << pairs.count(15) << endl;
    pairs.insert(mmid::value_type(20,9.3));

          mmid::iterator i;
          cout << "3) ";
          for( i = pairs.begin(); i != pairs.end();i ++ )
        cout << * i  << ",";
    cout << endl;
    cout << "4) ";
    int n =  pairs[40];//如果没有关键字为40的元素,则插入一个
    for( i = pairs.begin(); i != pairs.end();i ++ )
    cout << * i  << ",";
    cout << endl;
    cout << "5) ";
    pairs[15] = 6.28; //把关键字为15的元素值改成6.28
    for( i = pairs.begin(); i != pairs.end();i ++ )
    cout << * i  << ",";
                return 0;
    }



    输出:
    1) 0
    2) 1
    3) (15,2.7),(20,9.3),
    4) (15,2.7),(20,9.3),(40,0),
    5) (15,6.28),(20,9.3),(40,0),


    如何用程序用来统计一篇英文文章中单词出现的频率(为简单起见,假定依次从键盘输入该文章) 
           #include <iostream

    > #include <map>

    using namespace std;

    int main() {  

      map<string, int> wordCount;   

     string word;    

    while (cin >> word)        

    ++wordCount[word];       

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

         cout<<"Word: "<<(*it).first<<" Count: "<<(*it).second<<endl;      

      return 0; }



    例:

    #include <queue>
    #include <iostream>
    using namespace std;
    int main()  {
    priority_queue<double> priorities;
    priorities.push(3.2);
    priorities.push(9.8);
    priorities.push(5.4);
    while( !priorities.empty() ) {
    cout << priorities.top() << " ";    priorities.pop();
    }
         return 0;

    //输出结果:9.8 5.4 3.2


    例:

    int main()  {
    const int SIZE = 10;
    int a1[] = { 2,8,1,50,3,100,8,9,10,2 };
    vector<int> v(a1,a1+SIZE);
    ostream_iterator<int> output(cout," ");
    vector<int>::iterator location;
    location = find(v.begin(),v.end(),10);
    if( location != v.end()) {
    cout << endl << "1) " << location - v.begin();
    }
      sort(v.begin(),v.end());
           if( binary_search(v.begin(),v.end(),9)) 
               cout << endl << "3) " << "9 found";
          else
        cout << endl << " 3) " << " 9 not found";       
          return 0;
    }

    输出:(无sort语句)


    1) 8
    2) 3
    3) 9 not found

    输出: (有sort语句)
    1) 8
    2) 3
    3) 9 found






  • 相关阅读:
    Redis命令总结
    jvisualvm远程监控Tomcat
    CentOS6安装glibc-2.14,错误安装libc.so.6丢失急救办法
    vsan分布式存储数据恢复全过程
    linux文件系统损坏修复方法,亲测可用
    案例讲解服务器硬盘离线数据恢复方法-数据恢复
    服务器数据丢失恢复过程
    数据恢复工程师讲述Linux服务器数据恢复过程
    了解这一点轻松解决Oracle数据库系统报错问题
    浅析RAID0/1安全差别及处理数据安全的应对方式
  • 原文地址:https://www.cnblogs.com/zhangaihua/p/3718114.html
Copyright © 2011-2022 走看看