C++-STL:vector用法總結


一、簡介

vector,是同一類型的對象的集合,這一集合可看作可變大小的數組,是容器的一種。

  1. 對於容器來說,其重要特性之一便是於可以在運行時高效地添加元素
  2. 類似於數組,vector采用連續內存地址來存儲元素,因此vector屬於順序容器。也就意味着可以采用下標對vector的元素進行訪問,和數組一樣高效;同時它比數組更加靈活,它的大小(size)是可以動態改變的,且它的大小會被容器自動處理。
    • vector分配空間策略:vector會分配一些額外的空間以適應可能的增長,使得分配的存儲空間(capacity)比實際需要的存儲空間更大。不同的庫采用不同的策略權衡空間的使用和重新分配,vc里是每次增大當前capacity的一半。但是無論如何,重新分配總是對數增長的間隔大小,在末尾插入一個元素的時候則能夠在常數時間的復雜度完成的。
  3. 在這里應理解好sizecapacity之間的關系,這將有助於理解vec.resize()vec.reserve()的區別:
    • 容器的capacity是其size的上界,size總是<=capacity;當所需求的size>當前capacity時,vector便會如上文所述一般對capacity進行動態分配,以滿足目標size需求。
    • 我們使用[]操作符時,只能訪問size大小內的容器空間,這才是真正存在對象的內存空間;而>size同時<capacity的內存則屬於“野”內存。
  4. 與其它動態序列容器相比(deques, lists and forward_lists), vector在訪問元素的時候更加高效,在末尾添加和刪除元素相對高效。對於其它不在末尾的刪除和插入操作,效率更低。比起lists和forward_lists統一的迭代器和引用更好。

二、用法

1. 頭文件

#include<vector>

2. vector的聲明及初始化

(1)不帶參數的構造函數初始化

// 初始化一個size為0的vector
vector<int> vec;

(2)帶參數的構造函數初始化
僅指定vector大小,此時每個元素值為默認值0

vector<int> vec(10);    //初始化了10個默認值為0的元素

指定vector大小和元素初始值

vector<int> vec(10,1); //初始化了10個值為1的元素
// 或是
vettor<int> vec = {1, 2, 3}; //初始化了1,2,3這3個元素

(3)通過同類型的vector初始化

vector<int> temp(5,1);
// 通過temp容器初始化一個元素相同的vec向量
vector<int> vec(temp);

通常來說,前三種便足夠我們平時使用了。

(4)通過數組地址初始化

int a[5] = {1,2,3,4,5};
// 以數組a的元素初始化vector,注意地址是從0到5(左閉右開區間)
vector<int> vec(a, a+5);

(5)通過insert函數初始化
使用同類型的vector以及insert函數初始化

// insert初始化方式將同類型的迭代器對應的始末區間(左閉右開區間)內的值插入到vector中
vector<int> temp(6,6);
vecot<int> vec;
// 將temp[0]~a[2]插入到vec中,vec.size()由0變為3
vec.insert(vec.begin(), temp.begin(), temp.begin() + 3);

使用數組以及insert函數初始化

int a[6] = {6,6,6,6,6,6};
vector<int> vec;
// 將a的所有元素插入到vec中
vec.insert(vec.begin(), a, a+7);

通過insert函數添加m個值為n的元素

// 在vec開始位置處插入6個1
vec.insert(vec.begin(), 6, 1);

(6)通過copy函數賦值

vector<int> vec(5,1);
int a[5] = {2,2,2,2,2};
vector<int> target(10);

// 將vec中元素全部拷貝到target開始的位置中,注意拷貝的區間為vec.begin() ~ vec.end()的左閉右開的區間
copy(vec.begin(), vec.end(), target.begin());

// 拷貝區間也可以是由數組地址構成的區間
copy(a, a+5, vec.begin() + 5);

3. vector基本操作

1)容量相關

  • 容器目前大小:vec.size()
  • 容器目前容量:vec.capacity()
  • 容器最大允許容量:vec.max_size();
  • 判斷容器是否為空:vec.empty()
  • 請求容器capacity減少至size大小:vec.shrink_to_fit()
  • 更改容器容量:vec.reverse(size_type n)
  • 更改容器大小
    • 目標size小於當前size則截取前目標size個元素;大於則以元素填充存儲空間至目標size
    • vec.resize(size_type n)僅指定size修改后大小n,需元素填充則以默認值0填充
    • vec.resize(size_type n, value_type val)指定目標size大小n以及填充元素的值val

2)修改元素

  • 末尾添加元素:vec.push_back(value_type val)
  • 末尾刪除元素:vec.pop_back()
  • 對容器賦值:
    • vec.assign(const_iterator first, const_iterator last)將同類型容器目標區間[first, last)內的元素賦給調用者
    • vec.assign(size_type n, const T& x = T())將n個x賦給調用者
  • 在指定位置插入元素:
    • vec.insert(const_iterator position, value_type& val)在指定位置position插入元素val
    • vec.insert(const_iterator position, size_type n, value_type& val)在指定位置position插入n個元素val
    • vec.insert(const_iterator position, InputIterator first, InputIterator last)在指定位置插入同類型容器目標區間內的元素
  • 在指定位置刪除元素
    • vec.erase(const_iterator position)刪除指定位置的素
    • vec.erase(const_iterator first, const_iterator last)刪除指定區間內的元素
  • 與另一個容器交換元素:vec.swap(vector& x)
  • 清空容器元素:vec.clear()
    • 調用這個方法后,vec的size置為0但capacity不一定會重新分配

3)使用迭代器

  • 聲明迭代器(類似指針):vector<size_type>::Iterator i
    • 訪問迭代器指向的元素:*i
  • 可寫迭代器
    • 指向容器開頭:vec.begin()
    • 指向容器結尾(指向最后一個元素再往后的一個內存):vec.end()
  • 只讀迭代器(不能通過該指針來修改元素)
    • 指向容器開頭:vec.cbegin()
    • 指向容器結尾:vec.cend()

4)訪問元素

  • 訪問指定位置元素。通過下面兩個方法的比較可以看到,我們平時應優先使用vec.at(i):
    • vec[i]下標訪問。不會下標檢查是否越界,越界時返回一串無規律整形。
    • vec.at(i)通過at函數訪問。如果越界會拋出out of range的異常
  • 訪問第一個元素:vec.front()
  • 訪問最后一個元素:vec.back()
  • 返回一個元素組成的數組的指針:int* p = vec.data()

4. 常用操作

1)遍歷元素

```
vector<int>::iterator it;
for (it = vec.begin(); it != vec.end(); it++) {
    cout << *it << endl;
}    
//或者
for (size_t i = 0; i < vec.size(); i++) {
    cout << vec.at(i) << endl;
}
```

2)元素翻轉

```
#include <algorithm>
reverse(vec.begin(), vec.end());
```

3)元素排序

```
#include <algorithm>
sort(vec.begin(), vec.end()); //采用的是從小到大的排序
//如果想從大到小排序,可以采用上面反轉函數,也可以采用下面方法:
bool Comp(const int& a, const int& b) {
    return a > b;
}
sort(vec.begin(), vec.end(), Comp);
```

文章最后,我個人認為頭文件<algorithm>中的reverse()函數寫得特別優雅,在此貼出源碼

template <class BidirectionalIterator>
void reverse (BidirectionalIterator first, BidirectionalIterator last)
{
  while ((first != last) && (first != --last)) {
    std::iter_swap (first,last);
    ++first;
  }
}

主要參考資料

  1. C++ STL之vector用法總結
  2. C++-api


免責聲明!

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



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