STL標准庫-容器-vector


技術在於交流、溝通,本文為博主原創文章轉載請注明出處並保持作品的完整性。

向量容器vector是一個動態數組,內存連續,它是動態分配內存,且每次擴張的原來的二倍.

他的結構如下


 

一 定義 

vector< 類型 > 標識符(最大容量,初始所有值)

vector是一種類模板,那么他有很多行為與類相似

頭文件 #include <vector>

    //a.定義 vector<typeName> v;
    vector<int> v;
    
    //b.拷貝構造 vector<typeName> v1(v); 例:vector<int> v1(v); 
    vector<int> v1(v);
   
    //c.賦值拷貝
    v1 = v; //如果v的size比v1的size大,則自動擴充v1的空間,反之亦然
    
    //d.按指定元素個數定義
    vector<int> v2(5); //v2含有5個值為0的元素
    
    //e.指定元素個數及類型
    vector<int> v3(5,10);//v3包含5個值為10的int類型元素
    
    //f.與array間的轉換
    int a[3]={0,1,2}; vector<int> v4(a,a+3);    

 


 

二 基本使用

   vector<int> v;
    //在vector尾端插入元素
    //但是沒有在前面插入元素,上面的vector結構圖中,我們可以看出來vector是一種向后擴充的容器,
    //如果在前面插入,那后面所有的元素將后移,造成巨大的消耗,所以沒有push_front()
    //同理沒有pop_front()
    v.push_back(1);
    
    //刪除最后一個元素
    v.pop_back();
    
    //返回元素個數
    int count = v.size();
    
    //重新設定vector的size
    v.resize(2*(v.size()));
    
    //判斷容器是否為空
    bool isEmpty = v.empty();
    
    //[index]操作,返回下表為index的元素
    int tmp = v[1];
    
    //定義迭代器
    vector<int> ::iterator iter = v.begin();
    
    for(int i = 0; i<3; i++ )
    {
        v.push_back(1); // 1 1 1
    }
    //在 v的前面插入兩個 5
    v.insert(iter, 2, 5); // 5 5 1 1 1
    
    //在頭部插入3
    v.insert(v.begin(), 3);//3 5 5 1 1 1
    
    //在尾部插入3
    v.insert(v.end(), 3);//3 5 5 1 1 1 3
    
    //下表5的前面插入3
    v.insert(v.begin()+5, 3);//3 5 5 1 1 3  1 3
    
    //刪除指定下標元素
    v.erase(v.begin()+1); //3 5 1 1 3 1 3
    
    //清空
    v.clear();
    
    //起始地址
    v.data();
    
    //最后一個元素后面的地址
    v.end();
    
    //實際內存大小
    v.capacity();
    
    //at(下標)
    v.at(1);
    
    //返回最后一個元素
    v.back();
    
    //返回第一個元素
    v.front();
    
    //將指定區間內的元素賦值給v
    v.assign(v.begin()+1, v.begin()+2);
    
    //賦值 將三個 1 賦值給v 那么vecotr將變為 1 1 1
    v.assign(3, 1);

  //最大內存
   v.max_size();

    //輸出
    for(auto iii : v)
    {
        cout << iii <<endl;
    }

 

 


 

三 vector支持的算法

增加頭文件#include<algorithm> //算法

#include <algorithm>
int main()
{
    //可以使用的全局算法有
    //搜索算法:find() 、search() 、count() 、find_if() 、search_if() 、count_if()
    //分類排序:sort() 、merge()
    //刪除算法:unique() 、remove()
    //生成和變異:generate() 、fill() 、transformation() 、copy()
    //關系算法:equal() 、min() 、max()
    vector<int> c;
    
    for(int i = 0; i<10; i++ )
    {
        c.push_back(i); //
    }

    //查找函數 find(begin,end, searchItem)
    auto pItem = ::find(c.begin(), c.end(), 3);
    
    if(pItem != c.end())
        cout << "找到了: " << *pItem << endl;
    else
        cout << "沒找到" << endl;
    
    
    vector<int> c1;
    
    for(int i = 0; i<10; i++ )
    {
        c1.push_back(i+10); //
    }
    
    //查找函數search 是否包含子序列容器向量 如果包含 返回包含位置
    auto pItem1 = ::search(c.begin(), c.end(), c1.begin()+2, c1.begin()+5);
    
    if(pItem1 != c.end())
        cout << "找到了: " << *pItem1 << endl;
    else
        cout << "沒找到" << endl;
    
    //算法就不一一舉例了
    return 0;
}

 輸出結果


 

四 內存管理

上面提到過vector的擴充是以2倍的形式擴充,它的擴充過程可以理解成  if (v.size()元素個數 > v.capacity()實際內存) v.resize(2*v.capacity())

當vector發現元素個數大於實際內存時, vector將重新申請一塊內存為原來的內存2倍的空間 然后將原來的元素一一copy過去,我們都知識申請內存是非常耗時的,所以我們一定要把握好vector的內存尺度

下面來測試一下

    void vector_test_capactity()
    {
        //創建vector
        std::vector<int> v;
        for(int i = 0; i<10 ; i++)
        {
            cout<<"容器內元素個數: " << v.size() << " "<<"vector內存大小: " << v.capacity()<<endl;
            v.push_back(i);
        }
    }

輸出結果


 

Source Code 

下圖是vector類圖,類圖中的函數為vector一些常用函數,現在來分析一下這些函數

 

下面是我在Qt中找出的vector的源代碼

_Vector_base<_Tp>與_Vector_impl<_Tp>

 1   template<typename _Tp, typename _Alloc>
 2         struct _Vector_base
 3         {
 4             typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
 5             rebind<_Tp>::other _Tp_alloc_type;
 6             typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer
 7             pointer;
 8             
 9             struct _Vector_impl
10             : public _Tp_alloc_type
11             {
12                 pointer _M_start;
13                 pointer _M_finish;
14                 pointer _M_end_of_storage;
15                 ...
16             }
17             
18             pointer
19             _M_allocate(size_t __n)//申請內存
20             {
21                 typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
22                 return __n != 0 ? _Tr::allocate(_M_impl, __n) : 0;
23             }
24             
25             void
26             _M_deallocate(pointer __p, size_t __n)//釋放內存
27             {
28                 typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
29                 if (__p)
30                     _Tr::deallocate(_M_impl, __p, __n);
31             }
32         }

你會發現_Vector_base中has a(組合)一個_Vector_impl類,這個類里面包含三個指針分別是_M_start,_M_finish,_M_end_of_storage,結合一下下圖你就會明白這三個指針的含義

圖中的start和finish,end_of_storage分別是上面的三個指針

這個時候我們看下面的源代碼begin(),end(),capacity()是不是很容易理解了,_GLIBCXX_NOEXCEPT是不拋出任何異常

    iterator
    begin() _GLIBCXX_NOEXCEPT
    { return iterator(this->_M_impl._M_start); }//返回它的start指針
    
    ...
    
    const_iterator
    end() const _GLIBCXX_NOEXCEPT
    { return const_iterator(this->_M_impl._M_finish); }//返回finish指針
    
    ...
    
    size_type
    capacity() const _GLIBCXX_NOEXCEPT
    { return size_type(this->_M_impl._M_end_of_storage//返回start-finish
                       - this->_M_impl._M_start);
    }

下面我們來看一看vector<_Tp>類,幾個相對常用的函數push_back(), operator=和insert()

    template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector : protected _Vector_base<_Tp, _Alloc>
    {
        ...
     void
     push_back(const value_type& __x)()
     ...
     vector&
     operator=(const vector& __x);
        ...
        iterator
        insert(const_iterator __position, size_type __n, const value_type& __x)
    }

1.push_back()

      void
      push_back(const value_type& __x)
      {
        if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)//如果不需要申請內存
          {
             _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,__x);//將x賦給finish
             ++this->_M_impl._M_finish; // => ++finish 
          }
        else
        #if __cplusplus >= 201103L
            _M_emplace_back_aux(__x);
        #else
            _M_insert_aux(end(), __x);
        #endif
      }

 _M_emplace_back_aux

#if __cplusplus >= 201103L
  template<typename _Tp, typename _Alloc>
    template<typename... _Args>
      void
      vector<_Tp, _Alloc>::
      _M_emplace_back_aux(_Args&&... __args)
      {
    const size_type __len =
      _M_check_len(size_type(1), "vector::_M_emplace_back_aux");
    pointer __new_start(this->_M_allocate(__len));//申請一段新的內存,將新的start指針指向新內存的起始位置
    pointer __new_finish(__new_start);//初始化finish指針
    __try
      {
        _Alloc_traits::construct(this->_M_impl, __new_start + size(),
                     std::forward<_Args>(__args)...);
        __new_finish = 0;

        __new_finish
          = std::__uninitialized_move_if_noexcept_a
          (this->_M_impl._M_start, this->_M_impl._M_finish,
           __new_start, _M_get_Tp_allocator());//將finish指針指向新內存的尾端

        ++__new_finish;
      }
    __catch(...)
      {
        if (!__new_finish)//申請不成功銷毀
          _Alloc_traits::destroy(this->_M_impl, __new_start + size());
        else
          std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
        _M_deallocate(__new_start, __len);
        __throw_exception_again;
      }
    std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
              _M_get_Tp_allocator());//銷毀舊內存
    _M_deallocate(this->_M_impl._M_start,
              this->_M_impl._M_end_of_storage
              - this->_M_impl._M_start);
    this->_M_impl._M_start = __new_start;
    this->_M_impl._M_finish = __new_finish;
    this->_M_impl._M_end_of_storage = __new_start + __len;
      }

 

2.operator=,運用assign函數重新賦值vector

      vector&
      operator=(initializer_list<value_type> __l)
      {
        this->assign(__l.begin(), __l.end());
        return *this;
      }

 3.insert(),參數,插入坐標,內存大小,插入變量

      iterator
      insert(const_iterator __position, size_type __n, const value_type& __x)
      {
        difference_type __offset = __position - cbegin();//獲取間隔
        _M_fill_insert(begin() + __offset, __n, __x);//插入變量
        return begin() + __offset;//返回插入位置
      }

參考<<侯捷STL標准庫>>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM