C++ Array 和 Vector容器


Array

array是c++ 11新增的序列容器,和其他容器的區別是,array的大小是固定的,無法動態擴展或者收縮。這也就意味着,在使用該容器的過程無法借由增加或移除元素而改變其大小,它只允許訪問或者替換存儲的元素。在使用該容器之前,代碼中需引入 <array> 頭文件

初始化

#include <array>

std::array<double, 10> values;

由此,就創建好了一個名為 values 的 array 容器,其包含 10 個浮點型元素。但是,由於未顯式指定這 10 個元素的值,因此使用這種方式創建的容器中,各個元素的值是不確定的(array 容器不會做默認初始化操作)。
通過如下創建 array 容器的方式,可以將所有的元素初始化為 0 或者和默認元素類型等效的值:

std::array<double, 10> values {};

當然,在創建 array 容器的實例時,也可以像創建常規數組那樣對元素進行初始化:

std::array<double, 10> values {0.5,1.0,1.5,2.0};

可以看到,這里只初始化了前 4 個元素,剩余的元素都會被初始化為 0.0。

成員函數

array 容器還提供有很多功能實用的成員函數。

  • 迭代器函數:begin(),end(),cbegin(),cend(),rbegin(),rend(),crbegin(),crend()
  • size() == max_size()返回容器中當前元素的數量,其值始終等於初始化 array 類的第二個模板參數 N。
  • empty()判斷容器是否為空,和通過size()==0判斷條件功能相同,但效率更高。
  • at() 返回容器中 n 位置處元素的引用,該函數自動檢查 n 是否在有效的范圍內,如果不是則拋出 out_of_range 異常。用at()訪問相比下標方式更安全,但是因為多了安全檢查性能更低。
  • front(),back() 返回容器中第一個元素和最后一個元素的直接引用,該函數不適用於空的 array 容器。
  • data() 返回一個指向容器首個元素的指針。利用該指針,可實現復制容器中所有元素等類似功能(values.data() == & values[0] == values.begin())。
  • fill(val) 將 val 這個值賦值給容器中的每個元素。
  • array1.swap(array2) 交換 array1 和 array2 容器中的所有元素,但前提是它們具有相同的長度和類型。

image

另外,在<array>頭文件中還重載了get()全局函數,該重載函數的功能是訪問容器中指定的元素,並返回該元素的引用。需要注意的是,該模板函數中,參數的實參必須是一個在編譯時可以確定的常量表達式,所以它不能是一個循環變量。也就是說,它只能訪問模板參數指定的元素,編譯器在編譯時會對它進行檢查。

std::cout << std::get<3>(values) << std::endl;

array遍歷

double total = 0;
for(size_t i = 0 ; i < values.size() ; ++i)
{
    total += values[i];
}
double total = 0;
for(auto& value : values)
    total += value;
for (auto i = values.begin(); i < values.end(); i++) {
	cout << *i << " ";
}
#include <numeric>
int result = accumulate(values.begin(), values.end(), 0);

Vector

vector 容器是 STL 中最常用的容器之一,它和 array 容器非常類似,都可以看做是對 C++ 普通數組的“升級版”。不同之處在於,array 實現的是靜態數組(容量固定的數組),而 vector 實現的是一個動態數組,即可以進行元素的插入和刪除,在此過程中,vector 會動態調整所占用的內存空間,整個過程無需人工干預。

vector 常被稱為向量容器,因為該容器擅長在尾部插入或刪除元素,在常量時間內就可以完成,時間復雜度為 \(O(1)\);而對於在容器頭部或者中部插入或刪除元素,則花費時間要長一些(移動元素需要耗費時間),時間復雜度為線性階 \(O(n)\)

初始化

  • vector():創建一個空vector
  • vector(int nSize):創建一個vector,元素個數為nSize
  • vector(int nSize,const t& t):創建一個vector,元素個數為nSize,且值均為t
  • vector(const vector&):復制構造函數
  • vector(begin,end):復制[begin,end)區間內另一個數組的元素到vector中
std::vector<double> values;

注意,這是一個空的 vector 容器,因為容器中沒有元素,所以沒有為其分配空間。當添加第一個元素(比如使用 push_back() 函數)時,vector 會自動分配內存。

在創建好空容器的基礎上,還可以像下面這樣通過調用 reserve() 成員函數來增加容器的容量:

values.reserve(20);

這樣就設置了容器的內存分配,即至少可以容納 20 個元素。注意,如果 vector 的容量在執行此語句之前,已經大於或等於 20 個元素,那么這條語句什么也不做;另外,調用 reserve() 不會影響已存儲的元素,也不會生成任何元素,即 values 容器內此時仍然沒有任何元素。

還需注意的是,如果調用 reserve() 來增加容器容量,之前創建好的任何迭代器(例如開始迭代器和結束迭代器)都可能會失效,這是因為,為了增加容器的容量,vector<T> 容器的元素可能已經被復制或移到了新的內存地址。所以后續再使用這些迭代器時,最好重新生成一下。

除了創建空 vector 容器外,還可以在創建的同時指定初始值以及元素個數,比如:

std::vector<int> primes {2, 3, 5, 7, 11, 13, 17, 19};

這樣就創建了有8個元素的 vector 容器。

在創建 vector 容器時,也可以指定元素個數:

std::vector<double> values(20);

注意,圓括號 () 和大括號 {} 是有區別的,前者(例如 (20) )表示元素的個數,而后者(例如 {20} ) 則表示 vector 容器中只有一個元素 20。

第二個參數指定了所有元素的初始值,因此這 20 個元素的值都是 1.0。

std::vector<double> values(20, 1.0);

還可以通過一個vector初始化另一個vector,或者一個vector的迭代器范圍初始化另一個vector

std::vector<int> primes {2, 3, 5, 7, 11, 13, 17, 19};

std::vector<int> other_primes(primes);
std::vector<int> third_primes(primes.begin()+3, primes.end());

一些特殊初始化

初始化二維數組時,可以先確定第一維大小時,初始化如下:

下面兩種方法效果完全相同。

vector<vector<int>> nums(10);

vector<vector<int>> nums(10, vector<int>());

需要初始化二維零數組時,可以這樣初始化:

// 初始化二維 10x10 的0數組
vector<vector<int>> nums(10, vector<int>(10, 0));

需要將 vector 從 0 開始初始化:

vector<int> nums(10);

iota(nums.begin(), nums.end(), 0);
// nums = [0, 1, 2, ..., 8, 9]

成員函數

  • 迭代器函數:同array

增加數據

  • void push_back(const T& x):向量尾部增加一個元素X
  • iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一個元素x
  • iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n個相同的元素x
  • iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一個相同類型向量的[first,last)間的數據

刪除數據

  • iterator erase(iterator it):刪除向量中迭代器指向元素
  • iterator erase(iterator first,iterator last):刪除向量中[first,last)中元素
  • void pop_back():刪除向量中最后一個元素
  • void clear():清空向量中所有元素

迭代器

  • reference at(int pos):返回pos位置元素的引用
  • reference front():返回首元素的引用
  • reference back():返回尾元素的引用
  • iterator begin():返回向量頭指針,指向第一個元素
  • iterator end():返回向量尾指針,指向向量最后一個元素的下一個位置
  • reverse_iterator rbegin():反向迭代器,指向最后一個元素
  • reverse_iterator rend():反向迭代器,指向第一個元素之前的位置

其他函數

  • size() 返回實際元素個數
  • max_size() 返回元素個數的最大值。這通常是一個很大的值,一般是 \(2^{32}-1\),所以我們很少會用到這個函數。
  • resize() 改變實際元素個數
  • capacity() 返回當前容量
  • reserve() 改變容器容量
  • shrink_to_fit() 將內存減少到等於當前元素實際所使用的大小。
  • at() 使用經過邊界檢查的索引訪問元素,同array。
  • operator[ ] 重載了 [ ] 運算符,可以向訪問數組中元素那樣,通過下標即可訪問甚至修改 vector 容器中的元素
  • front(), back() 分別是第一個和最后一個元素的引用
  • data() 返回指向容器中第一個元素的指針。
  • emplace() 在指定的位置直接生成一個元素。
  • emplace_back() 在序列尾部生成一個元素。

vector內存分配

和 array 容器不同,vector 容器可以隨着存儲元素的增加,自行申請更多的存儲空間。因此,在創建 vector 對象時,我們可以直接創建一個空的 vector 容器,並不會影響后續使用該容器。
但這會產生一個問題,即在初始化空的 vector 容器時,不能使用迭代器。也就是說,如下初始化 vector 容器的方法是不行的:

#include <iostream>
#include <vector>
int main()
{
    std::vector<int> values;
    int val = 1;
    for (auto first = values.begin(); first < values.end(); ++first, val++) {
        *first = val;
    }
    return 0;
}

除此之外,vector 容器在申請更多內存的同時,容器中的所有元素可能會被復制或移動到新的內存地址,這會導致之前創建的迭代器失效。

#include <iostream>
#include <vector>
int main(int argc, char const *argv[])
{
	std::vector<int> v(1);
	auto begin = &v[0]; // v.data() == &v[0]
	int times = 0;
	for (int i = 0; i < 10000000; ++i)
	{
		v.push_back(i);
		if (begin != &v[0])
		{
			times++;
			std::cout << "vector reallocator "<<times << " times" << " ......" << std::endl;
			begin = &v[0];
		}
	}
	return 0;
}

數據訪問

std::vector<int> values{1,2,3,4,5};
// 輸出第三個數
std::cout << *(values.data() + 2) << std::endl;
std::cout << values.at(2) << std::endl;
std::cout << values[2] << std::endl;

數據遍歷

std::vector<int> values{1,2,3,4,5};

// 使用迭代器遍歷
for(auto it = values.begin(); it!= values.end(); it++)
{
	std::cout << *it << std::endl;
}
// 使用下標
for(size_t i = 0; i < values.size(); i++)
{
	std::cout << values[i] << std::endl;
}
// c++11 新方法
for(auto &i: values)
{
	std::cout << i << std::endl;
}


免責聲明!

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



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