zoukankan      html  css  js  c++  java
  • STL之vector

      因为在写一些算法题,一般的在线编译器好像都是用vector作为参数,所以有必要对vector总结一下:

    7.3 vector

      vector的本质是一个动态数组(dynamic array),类似于c用malloc分配空间。在<vector>头文件内,vector的定义如下:

    namespace std
    {
        template <typenameT,typename Allocator = allocator<T>>
        class vector;
    }

      注意:第二个模板参数可省略,用默认的内存分配器就好了。

    7.3.1 vector的能力

      因为内存是连续分配的,所以提供随机访问的能力,如果在末尾添加或删除元素,则性能相当的好。我想,因该是将类成员的size直接减1(原谅我还看不懂满是宏的源码==)。然而在中间删除或添加则会导致O(n)的操作时间,或者当size满了之后再添加也需要O(n)的时间,所以提前定好容量显得至关重要。

      下面介绍初始化函数:

    vector<Elem> c          //空vector
    vector<Elem> c(c2)     //构造一个与c2vector的拷贝,包括容量与元素
    vector<Elem> c=c2     //同上
    vector<Elem> c(rv)    //使用右值来构造(move)
    vector<Elem> c=rv    //同上
    vector<Elem> c(n)     //用elem的default构造函数来初始化n个elelm,容量大小为n。
    vector<Elem> c(n,elem) //elem是类型Elem的一个实例,使用它的拷贝构造函数来初始化n个Elem。
    vector<Elem> c(beg,end) //使用[beg,end)之间的迭代器来初始化。
    vector<Elem> c(initlist)     //使用初始化列来初始化
    vec.~vector()            //析构函数

    7.3.2 vector的操作

    非易更性操作(Nonmodifying operation)

    c.empty()    //bool,是否为空。但用size()==0也许更快
    c.size()        //返回大小
    c.max_size()    //返回元素个数的最大可能数
    c.capacity()        //返回容量
    c.reserve(num)    //当且仅当容量不足的时候才扩大
    c.shrink_to_fit()    //降低容量
    c1==c2        //逐个元素比较大小
    c1!=c2        //逐个元素调用!=
    c1<c2         //之类的大小比较就不写了

      在这里,非易更性操作指的是调用这些函数之后,原有的指针与迭代器仍然有效。然而这里的坑需要注意的是reserve与shrink_to_fit调用成功后指针与迭代器无效,只是原有的逻辑内容未发生变化。

    赋值(assignment)

    c=c2        //c2的内容拷贝赋值给c
    c=rv        //用右值的内容移动给c(move)
    c=initlist        //用初始化列初始化
    c.assign(n,elem)    //记住,是从开始复制n个元素。n超过了容量大小会自动适配
    c.assign(beg,end)        //[beg,end) 复制范围内的元素
    c.assign(inilist)
    c1.swap(c2)        //置换c1与c2的数据,然而这里原有的指针迭代器也会被置换。
    swap(c1,c2)        //同上

    元素访问(Element Access)

    c[idx]        //不检查范围
    c.at[idx]    //超出范围会抛出异常,安全的做法
    c.front()    //返回第一元素,不检查容器是否为空
    c.back()     //返回最末元素,不检查容器是否为空

      总结一下:使vector原有的迭代器与指针失效有如下两种情况:

      (1)在索引位置上安插或移除元素

      (2)由容量变化而引起的内存重新分配

    迭代器(iterator)

    c.begin()
    c.end()
    c.cbegin()    //常量迭代器
    c.cend()
    c.rbegin()    //反向迭代器,指向了容器最末尾的元素,++往着首位
    c.rend()
    c.crbegin()
    c.crend()

    安插与移除(Inserting and Removing)

    c.push_back(Elem)
    c.pop_back()        //移除最后一个元素
    c.insert(pos,Elem)    //在Iterator pos位置前插入元素
    c.insert(pos,n,Elem)    //插入n个元素
    c.insert(pos,beg,end)    //在位置pos之前插入[beg,end)个元素
    c.insert(pos,initlist)
    c.emplace(pos,args...)    //调用Elem的以args为参数的构造函数初始化
    c.emplace_back(args...)    //在末尾添加
    c.erase(pos)    //删除元素并返回之后的迭代器
    c.rease(begin,end)
    c.resize(num)    //将元素数量改为num,如果size变大,剩下的调用默认初始化
    c.resize(num,Elem)    //不同的是,调用Elem的拷贝
    c.clear()        //移除所有元素,清空,但内存仍然保留,不同的size变为0

      需要注意的是emplace与insert不同的是,insert插入的是拷贝,而emplace插入的是以args初始化的元素

    7.3.3 将vector当作C-Style Array使用

      可以调用c.data()获得首地址,注意这个首地址不同于迭代器,通常少用。

    7.3.4 异常处理(Exception Handling)

      有几种清空C++STL做出保证会抛出异常

    1.push_back()时发生异常,元素不会被插入到末尾,即不发生效用
    2.如果元素的copy/move未发生异常,则容器的相关操作要么成功要么不发生效用
    3.pop_back()不会发生异常
    4.swap(),clear()不发生异常
    5.如果元素的copy/move未发生异常,则容器的相关操作要么成功要么不发生效用,包括POD(plain old data)简朴的老式数据,如C-struct。

    7.3.6 Class vector<bool>

      这是模板特化类,与bool不同的是,这里的bool只占用一个位,而不是一个字节,所以迭代器在这里无效,同时内存空间也是原来的八分之一。

    操作 效果
    c.flip() 将所有bool元素反相(negate)
    c[idx].flip() 将idx所指位置反相
    c[idx]=val 将idx位置复制第一bit(0或1)
    c[idxl]=c[idx2]  

      这里需要注意的是front与back,at等函数返回的都是引用(reference)

      谈一谈初学c++时遇到的一个坑,考虑如下函数

    for(auto i=v.begin(),i!=v.end();i++)
        {
            if(condition)
                {
                    v.erase(i);
                }
        }

      错误的原因是删除了之后内存布局有变化,所以迭代器会失效,为nullptr,所以会错误。、

      扩充一下例子:

        vector<int> a{ {1,1,2,3,4,5,1} };
        for (auto i = a.begin(); i != a.end(); i++)
        {
            if(*i == 1)
            {
                i=a.erase(i);
            }
        }
        vector<int> a{ {1,1,2,3,4,5,1} };
        for (auto i = a.begin(); i != a.end(); i++)
        {
            while(*i == 1)
            {
                i=a.erase(i);
                if (i == a.end())
                    break;
            }
        }
        vector<int> a{ {1,1,2,3,4,5,1} };
        for (auto i = a.begin(); i != a.end(); i++)
        {
            while(*i == 1)
            {
                i=a.erase(i);
                if (i == a.end())
                    break;
            }
            if (i == a.end())
                break;
        }

      只有最后一个才是对的,在自己的机子上调试一下吧。

      ps:在容器中删除相同元素的简单做法:vec.erase(remove(vec.begin(),vec.end(),val),vec.end())。

  • 相关阅读:
    【bzoj1707/Usaco2007 Nov】tanning分配防晒霜——贪心+优先队列
    【bzoj1754/Usaco2005 qua】Bull Math——高精度乘法
    【bzoj1709/Usaco2007 Oct】Super Paintball超级弹珠——递推
    【bzoj2060/Usaco2010 Nov】Visiting Cows 拜访奶牛——树形dp
    【bzoj1710/Usaco2007 Open】Cheappal 廉价回文——区间dp
    【bzoj1828/Usaco2010 Mar】balloc 农场分配——贪心+差分+优先队列
    【bzoj4552/Tjoi2016&Heoi2016】排序——二分+线段树/平衡树+线段树分裂与合并
    【bzoj2083/Poi2010】Intelligence test——二分+贪心
    【bzoj1596/Usaco2008 Jan】电话网络——dfs
    【bzoj1782/Usaco2010 Feb】slowdown 慢慢游——dfs序+树状数组
  • 原文地址:https://www.cnblogs.com/manch1n/p/10317672.html
Copyright © 2011-2022 走看看