STL

一. 首先介绍几个概念:
    容器:           同一种类型对象的集合, 每个对象都有一个对应的整数索引值.
    顺序容器:       元素排列次序与元素值无关, 而是由元素添加到容器里的顺序决定.
                    vector(向量)          支持快速随机访问
                    list(列表)            支持快速插入/ 删除
                    deque(双端队列)       双端队列
    顺序窗口适配器: 在顺序容器的基础上, 通过定义新的接口来适应基础的容器类型.         
                    stack(栈)             后进先出 (LIFO) 栈     
                    queue(队列)           先进先出 (FIFO) 队列
                    priority_queue        有优先级管理的队列
    迭代器(iterator): 是一种检查容器内元素并遍历元素的数据类型.
                      所有的容器都定义了迭代器类型, 只有少数的容器支持下标操作 (如: vector)
                   
                    vector <int> vect;
                    vector <int>::iterator iter=vect.begin();   //指向第一个元素 vect[0].
    注:    .end() 指向最后一个元素的下一个, 指向了一个不存在的元素.
           .end() == .begin()   则表示该容器为空.
    解引用操作符(*):  iter=vect.begin();   则 *iter= vect[0];

二. 重点介绍 vector(向量):
     
                                 vector 初始化
    -----------------------------------------------------------------------
    vector<T> v1          vector 保存类型为T 的对象. 默认构造函数 v1 为空;
    vector<T> v2(v1)      v2 是v1 的一个副本 (v1, v2 必须为同一类型);
    vector<T> v3(n, i)    v3 包含n 个值为i 的元素;
    vector<T> v4(n)       v4 含有值初始化的元素的n 个副本
    -----------------------------------------------------------------------
    vector<int> fvec(10)    // 10 elements, each initialized to 0 ;
    vector<string> svec(10) // 10 elements, each an empty string;
                               vector 对象的操作
    -----------------------------------------------------------------------
    v.empty()           如果v 为空, 则返回true , 否则返回false ;
    v.size()            返回v 中元素的个数;
    v.push_back(t)      在v 的末尾增加一个值为t 的元素;
    v[n]                返回v 中位置为n 的元素;
    v1=v2               把v1 的元素替换为v2 中元素的副本;
    v1==v2              如果v1 与v2 相等, 则返回true ;
    !=, <, <=, >, >=    保持这些操作符惯有的含义.
    -----------------------------------------------------------------------
    string word;
    vector<string> text;
    while(cin>>word){
        text.push_back(word);
    }
    for(vector<int>::size_type ix=0; ix!= ivec.size(); ++ix)
        ivec[ix]=0;   // 用size_type 类型作为vector 的下标类型;  还有更通用的, 迭代器:
                      // size_type 为 .size() 的返回值类型( 大多数为 unsigned 型);
   
    for(vector<int>::iterator iter= ivec.begin(); iter!= ivec.end(); ++iter)
        *iter=0;

C++复习 09 顺序容器

九. 顺序容器:
  001 顺序容器类型:
        vector            支持快速随机访问.
        list              支持快速插入删除.
        deque             双端队列.
      顺序容器适配器:
        stack            后进先出栈LIFO.
        queue            先进先出栈FIFO.
        priority_queue   有优先级管理的队列.
  002 顺序容器的定义,所有的容器都是模板,要定义具体的容器,必须在容器名后加一对尖括号, 括号里提供容器存放元素的类型.
        #include <vector>
        #include <list>
        #include <deque>
        vector<string> svec;
        list<int> ilist;
        deque<Sales_item> items;    //Sales_item 为自定度数据类型
  003 顺序容器的构造函数:
        C<T> c;     创建一个名为c 的空容器.
        C c(c2);    创建容器c2 的副本c, c 和c2 必须具有相同的容器类型.
        C c(b, e);  创建容器c, 其元素是迭代器 b和e 标示范围内的元素的副本, e标示一个停止指针,指向的内容并不复制.
        C c(n, t);  用n 个t 元素创建容器c, 只适合顺序容器,不适合关联容器.
        C c(n);     创建n 个值初始化的元素的容器c. 只适合顺序容器, 不适合关联容器.
        vector<int> ivec;
        vector<int> ivec2(ivec);   // ok.
        list<int> ilist(ivec);     // error, ivec是vector类型, 而ilist是list类型.
        vector<double> dvec(ivec); // error, 容器内的元素类型不同.
  004 将一个容器复制给另一个容器时, 类型必须匹配:  容器类型和元素类型都必须相同.
      使用迭代器时, 不要求容器类型相同, 容器内的元素类型也可以不同, 只要它们互相兼容, 能够将要复制的元素转换为
      所构建的新容器所构建的元素类型.  采用这种方式可以复制不能直接复制的容器, 特别的, 可以复制另外容器的一个
      子序列:
     
        //vector<string> svec;
        list<string> slist(svec.begin(), svec.end());    // !!!!
        vector<string>::iterator mid = svec.begin() + svec.size()/2;  // 指向vector 的中间元素;
        deque<string> front(svec.begin(), mid);
        deque<string> back(mid, svec.end());
      类似的, 可以通过内置数组的指针来初始化一个容器:
        char *words[] = {"stately", "plump", "buck", "mulligan"};
        size_t words_size = sizeof(words)/sizeof(char *);
        list<string> wordsList(words, words + words_size);
      初始化指定数目的元素:
        const list<int>::size_type list_size = 64;   // size_type 为 .size() 的返回值类型( 大多数为 unsigned 型);
        list<string> slist2(list_size, "heipi o");
        list<int> ilist2(list_size);
  005 容器元素的限制:  必须支持赋值运算, 对象必须可以复制. 引用类型不可以作为容器的元素 (不能赋值), 标准输入
      输出不能作为容器的元素.  如果类没有默认的构造函数,那么在定义容器的时候, 必须定义空的容器, 或者提供显式
      构造函数的参数.  假设Foo只有一个需要一个int参数的构造函数, 那么:
        vector<Foo> empty;      // ok
        vector<Foo> bad(2);     // error, 无法默认的创建元素, 所以不行.
        vector<Foo> fine(2, 0); // ok, 通过参数0, 创建两个元素.
      可以定义容器的容器:
        vector< vector<string> > lines;
        lines.push_back(svec);
  006 常用的迭代器运算:
        *iter                返回迭代器iter所指向的元素的引用.
        iter->mem            对iter解引用,获取指定元素中mem的成员,等效于(*item).mem
        ++iter/iter++/--iter/iter--
        iter1 == iter2       比较两个迭代器是否指向同一个元素 (iter1 != iter2).
      vector 和 deque容器的额外运算:
        iter +/- n
        iter +/- = n
        iter1 - iter2
        >, >=, <, <=
      注意啦: 在list容器中不支持" +/- n"的操作, 也不支持逻辑关系运算.
  007 使用迭代器编写程序时,必须留意那些使迭代器失效的操作,防止野指针问题.通常,要求涉及迭代器的代码尽可能短小.
  008 容器定义的类型:
        size_type                 无符号整形, 足以存储此容器类型的最大可能容器长度;
        iterator                  此容器类型的迭代器类型;
        const_iterator            元素的只读迭代器类型;
        reverse_iterator          按逆序寻址元素的迭代器;
        const_reverse_iterator    元素的只读( 不能写) 逆序迭代器;
        difference_type           足够存储两个迭代器差值的有符号整形, 可为负数;
        value_type                元素的类型;
        reference                 元素的左值类型 ,是value_type& 的同义词;
        const_reference           元素的常量左值类型, 等效于 const value_type& ;
  009 容器的begin和end操作, 每个操作还和容器是否为const有关:
        c.begin()             返回一个迭代器, 它指向容器c 的第一个元素;
        c.end()               返回一个迭代器, 它指向容器c 的最后一个元素的下一位置;
        c.rbegin()            返回一个逆序迭代器, 它指向容器c 的最后一个元素;
        c.rend()              返回一个逆序迭代器, 它指向容器c 的第一个元素前面的位置;
 
  010 容器中添加元素的操作:
        c.push_back(t)        在容器末尾加t, 返回void.
        c.push_front(t)       在容器前端加t, 只适用于list和deque容器类型, 返回void.
        c.insert(p, t)        在迭代器p 的前边插入t, 返回指向新添加元素的迭代器.
        c.insert(p, n, t)     在迭代器p 的前边插入n 个t, 返回void.
        c.insert(p, b, e)     在迭代器p 的前边插入迭代器b 和e 标记范围内的元素, 返回void.
        vector<string> svec;
        list<string> slist;
        string spouse("Beth");   // 等同于slist.push_front(spouse).
        slist.insert(slist.begin(), spouse);  // vector没有push_front,但是可以采用在begin前插入的方式实现该功能.
                                        // 要注意,对于vector容器,在前部或中间插入元素,是非常耗费资源的一个行为.
        svec.insert(svec.begin(), spouse);    // 借用insert(p,t)的返回值,循环向容器的头部添加元素.
        list<string>::iterator iter = slist.begin();
        while(cin >> spouse){
            iter = ilist.insert(iter, spouse);
        }     //插入一段元素.
        svec.insert(svec.end(), ilist.begin(), ilist.end());
        string sarr[4] = {"wangyi", "aichao", "master", "huawei"};
        svec.insert(svec.begin(), sarr, sarr + 4);
 
        要注意,添加元素可能造成迭代器失效. 比如在vector中添加元素, 可能会导致整个容器的重新加载, 迭代器自然
        也就无效了.   因此不要保存begin()或end()操作的返回值, 而是每次使用时都要执行一次该函数.
        vector<int>::iterator first = v.begin();
        while(first != v.end()){
          first = v.insert(first, 42);
          ++first;
        }
  011 关系操作符:  容器的比较是基于容器内元素的比较, 如果元素不支持某种类型的比较, 容器也就不能做这种比较运算.
        如果两个容器具有相同的长度而且所有元素相等,那么两个元素就相等.
        如果两个容器的长度不相同,但较短的容器中所有元素都等于较长容器中对应的元素,则称较短的容器小于另一个容器.
        如果两个容器都不是对方的初始子序列,则它们的比较结果取决于所比较的第一个不相等的元素.
        /*
          ivec1: 1 3 5 7 9 12
          ivec2: 0 2 4 6 8 10 12
          ivec3: 1 3 9
          ivec4: 1 3 5 7
          ivec5: 1 3 5 7 9 12
        */
        ivec2 < ivec1
        ivec1 < ivec3
        ivec4 < ivec1
        ivec1 == ivec5
  012 容器大小的操作:
        c.size()           返回容器c 中元素个数, 返回类型为 c::size_type ;
        c.max_size()       返回容器c 中可容纳最多元素个数, 返回类型是 c::size_type ;
        c.empty()          空则 true , 否则 false ;
        c.resize(n)        调整容器c 的长度大小, 使其能容纳n 个元素;
                           如果n<c.size(), 则删除多出来的元素; 否则, 添加初始值给新添加的元素.
        c.resize(n,t)      调整容器c 的长度大小, 使其能容纳n 个元素;
                           新添加的元素, 都用t来初始化. resize操作可能会使迭代器失效.
  013 访问元素:
      注意: 访问元素返回的是元素的引用, begin()和 end()返回的是指针.
        if (!list.empty()){
          list<int>::reference val1 = *ilist.begin();
          list<int>::reference val2 = ilist.front();
          list<int>::reference last1 = *--ilist.end();
          list<int>::reference last2 = ilist.back();
        }
        c.back()    返回容器c 的最后一个元素的引用. 如果c 为空, 则该操作未定义;
        c.front()   返回容器c 的第一个元素的引用. 如果c 为空, 则该操作未定义;
        c[n]        返回下标为n 的元素的引用.  如果n<0 或n>=c.size(), 则该操作未定义;
                    (只适用于vector和deque容器.)
        c.at(n)     返回下标为n 的元素的引用. 如果给出的下标无效, at函数会抛出out_of_range 异常,所以不推荐
                    使用, 最好还是用迭代器.  如果容器为空 ,那么所有访问容器的操作都是没有定义的(也就是说只
                    有鬼才知道会返回点什东西), 导致程序出现严重的错误.  (只适用于vector和deque容器.)
  014 删除元素:
        c.erase(p)       删除迭代器p 指向的元素, 返回被删除元素后边元素的迭代器.
        c.erase(b, e)    删除迭代器b 和e 范围内的元素, 返回被删除段后面元素的迭代器.
        c.clear()        删除容内全部的元素, 返回void.
        c.pop_back()     删除容器c 的最后一个元素, 返回void, c不能为空.
        c.pop_front()    删除容器c 的第一个元素, 返回void, c不能为空, 只适用于list或deque.
        删除第一个或者最后一个元素, 注意, pop_back()和pop_front() 都是不返回值的.
        while(!ilist.empty()){
          // process(ilist.front());
          ilist.pop_front();
        }
        删除容器内的一个元素, 要注意, erase是不检查迭代器参数是否有效的.
        string searchValue("Quasimodo");
        list<string>::iterator iter = find(slist.begin(), silist.end(), searchValue);
        if(iter != slist.end())
          slist.erase(iter);
      
        slist.clear();    // 删除容器内的所有元素.
        slist.erase(slist.begin(), slist.end());
  015 赋值与swap:   除swap外, 所有的操作, 都可以用earse 和insert 取代.
        c1 = c2          删除容器c1 中所有元素, 然后将c2 的元素复制给c1, c1 和c2 的类型
                         (包括容器类型和元素类型)必须相同;
        c1.swap(c2)      交换内容: 调用完该函数后, c1 中存放的是c2 原来的元素, c2 中存放的则是c1 原来的
                         元素, c1 和c2 的类型必须相同,该函数的执行速度通常要比将c2 的元素复制到c1 的操作快;    
                 
        c.assign(b, e)   重新设置c 的元素: 将迭代器b 和e 标记的范围内所有元素复制到c 中, b 和e 必须不是
                         指向c 中元素的迭代器;
        c.assign(n, t)   将容器c 重新设置为存储n 个值为t 的元素;
          带有一对迭代器的assin函数, 允许我们将一个容器的元素赋给另一个不同类型的容器.
          assign 操作首先删除容器中所有的元素, 然后将其参数所指定的新元素插入到该容器中;  所以当两个容器类型相
     同, 其元素类型也相同时, 可得用 "=" 赋值运算符, 否则, 必须使用 assign 操作.  例如:  利用 assign 操作可以实
     现将vector 容器中一段char * 类型的元素赋给string 类型的list 容器 :
          
  016 容器的capacity(容量) 和 reserve 成员:
      为了使vector 容器实现快速的内存分配, 其实际分配的容量要比当前所需的空间多一些.  vector 容器预留了这些
      额外的存储区, 用于存放新添加的元素.  于是, 不必为每个新元素重新分配空间, 所以, 比起list 和deque 容器, 
      vector 的增长效率要高一些.
      capacity      获取在容器需要分配更多的存储空间之前能够存储的元素总数;
      reserve       告诉容器应该预留多少个元素的存储空间;
        vector<int> ivec;
        cout<< "ivec::size " << ivec.size() << "capacity: " << ivec.capacity() << endl;
        for(vector<int>::size_type ix = 0; ix != 24; ++ix)
            ivec.push_back(ix);
        cout<< "ivec::size " << ivec.size() << "capacity: " << ivec.capacity() << endl;
        ivec.reserve(50);
        cout<< "ivec::size " << ivec.size() << "capacity: " << ivec.capacity() << endl;
        while(ivec.size() != ivec.capacity())
            ivec.push_back(0);
        cout<< "ivec::size " << ivec.size() << "capacity: " << ivec.capacity() << endl;
        ivec.push_back(50);
        cout<< "ivec::size " << ivec.size() << "capacity: " << ivec.capacity() << endl;    // 表明:  当vector
                                      容器不得不分配新的存储空间的时候, 以加倍当前容量的分配策略实现重新分配;
           
  017 容器的选用:
        如果无法确定应该采用哪种容器, 则编写代码时尝试只使用vector 和list 容器都提供的操作(使用迭代器,而
        不是下标), 并且避免随机访问元素. 这样编写代码, 在必要时, 可很方便的将程序从使用vector 容器修改为
        使用list 容器.
  018 容器适配器:
        适配器的通用类型和操作:
        size_type           一种类型, 足以存储些适配器类型最大对象的长度;
        value_type          元素类型;
        container_type      基础容器的类型, 适配器在此容器类型上实现;
        A a;                创建一个新的空适配器, 命名为a ;
        A a(c);             创建一个新的空适配器a , 初始化为容器c 的副本 ;
        关系操作符          ==  !=  <  <=  >  >=  ;
 
  019 覆盖基础容器类型:
        #include <stack>
        #include <queue>
        默认的stack 和queue 都是基于deque 容器实现的, 而priority_queue 则是在vector 容器上实现.  在创建适配器
        时, 通过将一个顺序容器指定为适配器的第二个类型实参, 可覆盖其关联的基础容器类型:
            stack< string, vector<string> > str_stack;
            priority_queue< int, list<int> > ipr_queue;
  020 栈适配器的操作:
        s.empty()         如果栈为空, 则返回true , 否则返回false .
        s.size()          返回栈中元素的个数.
        s.pop()           删除栈顶元素, 但不返回其值.
        s.top()           返回斩定元素, 但不删除其值.
        s.push(item)      将item压入栈顶.
// 09020.cpp
        #include <stack>
        #include <iostream>
        using std::stack;
        using std::cout;
        using std::cerr;
        using std::endl;
        int main(){
        const stack<int>::size_type stk_size = 10;
        stack<int> intStack;
        int ix = 0;
          while(intStack.size() != stk_size){
            intStack.push(ix++);
          }
        int error_cnt = 0;
          while(!intStack.empty()){
            int value = intStack.top();
            if (value != --ix){
              cerr << "oops! expected " << ix << " received " << value << endl;
              ++error_cnt;
            }
            cout << value << " ";
            intStack.pop();
          }
          cout << endl;
          cout << "Our program ran with " << error_cnt << " errors!" << endl;
          return 0;
        }
021 队列(queue) 和优先级队列(priority_queue) 支持的操作:
        q.empty()        如果队列为空, 则返回true , 否则返回false .
        q.size()         返回队列中元素的个数.
        q.pop()          删除队列元素, 但不返回其值.
        q.front()        返回队首元素, 但不删除该元素, 只适用于队列.
        q.back()         返回队尾元素, 但不删除该元素, 只适用于队列.
        q.top()          返回具有最高优先级的元素, 但不删除该元素, 只适合优先级队列.
        q.push(item)     对于队列, 在队尾压入一个新元素, 对于优先级队列, 在适当的位置插入新元素.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值