vector
vector的資料安排以及操作方式,與array非常相似,兩者的唯一差別在於空間的運用的靈活性。Array是靜態空間,一旦配置了就不能改變,要換大一點或者小一點的空間,可以,一切瑣碎得由自己來,首先配置一塊新的空間,然後將舊空間的資料搬往新空間,再釋放原來的空間。Vector是動態空間,隨著元素的加入,它的內部機制會自動擴充空間以容納新元素。因此vector的運用對於記憶體的合理利用與運用的靈活性有很大的幫助,我們再也不必害怕空間不足而一開始就要求一個大塊頭的array了。
Vector的實現技術,關鍵在於其對大小的控制以及重新配置時的資料移動效率,一旦vector舊空間滿了,如果客戶每新增一個元素,vector內部只是擴充一個元素的空間,實為不智,因為所謂的擴充空間(不論多大),一如剛所說,是”配置新空間-資料移動-釋放舊空間”的大工程,時間成本很高,應該加入某種未雨綢繆的考慮,稍後我們便可以看到vector的空間配置策略。
Vector維護一個線性空間,所以不論元素的型別如何,普通指標都可以作為vector的迭代器,因為vector迭代器所需要的操作行為,如operaroe*, operator->, operator++, operator--, operator+, operator-, operator+=, operator-=, 普通指標天生具備。Vector支援隨機存取,而普通指標正有著這樣的能力。所以vector提供的是隨機訪問迭代器(Random Access Iterators).
#include <vector> // 包含 vector 標頭檔案
// 建立一個儲存 int 型別的 vector
std::vector<int> intVector;
// 向 vector 尾部新增元素
intVector.push_back(42);
// 獲取 vector 的大小(元素個數)
int size = intVector.size();
// 獲取 vector 的容量(當前分配的儲存空間大小)
int capacity = intVector.capacity();
// 訪問 vector 中的元素
int element = intVector[0]; // 使用下標訪問
// 遍歷 vector 中的所有元素
for (int i = 0; i < intVector.size(); ++i) {
std::cout << intVector[i] << " ";
}
// 使用迭代器進行遍歷
for (auto it = intVector.begin(); it != intVector.end(); ++it) {
std::cout << *it << " ";
}
以上就是所有vector常用的語法,具體透過下述一個小例子來說。
vector<int> regina;
for (int i = 0; i < 10; i++) {
regina.push_back(i);
cout << regina.capacity() << endl;
}
int* start = ®ina[0];
int* end = ®ina[regina.size() - 1];
for (; start <= end; start++) {
cout << *start << endl;
}
Vector所採用的資料結構非常簡單,線性連續空間,它以兩個迭代器_Myfirst和_Mylast分別指向配置得來的連續空間中目前已被使用的範圍,並以迭代器_Myend指向整塊連續記憶體空間的尾端
。所謂動態增加大小,並不是在原空間之後續接新空間(因為無法保證原空間之後尚有可配置的空間),而是一塊更大的記憶體空間,然後將原資料複製新空間,並釋放原空間。因此,對vector的任何操作,一旦引起空間的重新配置,指向原vector的所有迭代器就都失效了。這是程式設計師容易犯的一個錯誤,務必小心。
常用操作
assign(beg, end);//將[beg, end)區間中的資料複製賦值給本身。
assign(n, elem);//將n個elem複製賦值給本身。
vector&operator=(const vector &vec);//過載等號運算子
swap(vec);// 將vec與本身的元素互換。
--------
size();//返回容器中元素的個數
empty();//判斷容器是否為空
resize(int num);//重新指定容器的長度為num,若容器變長,則以預設值填充新位置。如果容器變短,則末尾超出容器長度的元素被刪除。
resize(int num, elem);//重新指定容器的長度為num,若容器變長,則以elem值填充新位置。如果容器變短,則末尾超出容器長>度的元素被刪除。
capacity();//容器的容量
reserve(int len);//容器預留len個元素長度,預留位置不初始化,元素不可訪問。
-------------
at(int idx); //返回索引idx所指的資料,如果idx越界,丟擲out_of_range異常。
operator[];//返回索引idx所指的資料,越界時,執行直接報錯
front();//返回容器中第一個資料元素
back();//返回容器中最後一個資料元素
-------------
insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count個元素ele.
push_back(ele); //尾部插入元素ele
pop_back();//刪除最後一個元素
erase(const_iterator start, const_iterator end);//刪除迭代器從start到end之間的元素
erase(const_iterator pos);//刪除迭代器指向的元素
clear();//刪除容器中所有元素
在C++的STL中,capacity()
和size()
是vector
類的兩個成員函式,用於獲取vector
物件的容量和大小。
capacity()
函式返回vector
物件在不重新分配記憶體的情況下能夠容納的元素數量。換句話說,capacity()
表示vector
當前分配的記憶體空間大小,而不是vector
實際包含的元素數量。當vector
中的元素數量達到當前容量時,如果需要繼續新增元素,vector
會分配更大的記憶體空間,並將原有元素複製到新的記憶體空間中。size()
函式返回vector
物件當前包含的元素數量。換句話說,size()
表示vector
中實際儲存的元素數量,而不考慮vector
實際分配的記憶體空間大小。
舉個例子,假設你有一個vector
物件regina
,初始時capacity()
可能為10,而size()
為0。這意味著regina
的記憶體空間能夠容納10個元素,但實際上它目前並沒有儲存任何元素。當你向regina
中新增元素時,size()
會逐漸增加,直到等於capacity()
,此時vector
可能會重新分配更大的記憶體空間。
總結一下:
capacity()
:表示vector
當前分配的記憶體空間大小,不考慮實際儲存的元素數量。size()
:表示vector
實際儲存的元素數量,不考慮分配的記憶體空間大小。
vector<int> regina;
for (int i = 0; i < 100000; i++) {
regina.push_back(i);
}
cout << "capacity:" << regina.capacity() << endl;
cout << "size:" << regina.size() << endl;
//此時 透過resize改變容器大小
regina.resize(10);
cout << "capacity:" << regina.capacity() << endl;
cout << "size:" << regina.size() << endl;
//容量沒有改變
vector<int>(regina).swap(regina);
/*在建立臨時vector物件時,它會使用剛好
足夠的記憶體來儲存regina的元素,並且不會有
額外的記憶體佔用。然後透過swap函式,regina
會將自己的記憶體與臨時vector進行交換,
從而達到釋放多餘記憶體的目的。*/
cout << "capacity:" << regina.capacity() << endl;
cout << "size:" << regina.size() << endl;
在這段程式碼中,我們首先向
regina
中新增了10萬個元素,然後呼叫resize(10)
將regina
的大小改變為10。接著透過建立臨時vector
物件並與regina
交換來釋放多餘的記憶體。讓我解釋一下容量是如何變小的。
- 初始狀態:
- 在向
regina
中新增10萬個元素後,capacity()
可能會大於或等於10萬,因為vector
在需要時會分配比實際所需更多的記憶體,以減少頻繁的重新分配和複製。- 呼叫
resize(10)
:
- 當呼叫
resize(10)
時,regina
的大小被改變為10,但它的容量仍然可能保持不變。這是因為resize
函式通常只改變vector
的大小,而不會改變其容量,除非指定了新的容量值。- 透過臨時
vector
物件和swap
釋放多餘記憶體:
- 接著使用了一個巧妙的技巧,建立了臨時的
vector
物件,並透過swap
函式釋放了regina
中多餘的記憶體。這樣做會使regina
的容量變得剛好足夠儲存當前的元素數量,沒有額外的記憶體佔用。
vector VS valarray VS array
std::vector
:std::vector
是標準庫中最常用的動態陣列容器。- 它可以動態增長和縮小,即在執行時可以新增或刪除元素。
vector
內部使用動態記憶體分配來儲存元素,因此可以根據需要動態調整其大小。- 支援隨機訪問,插入和刪除操作效率較高。
std::valarray
:std::valarray
代表值陣列,是用於執行數學運算的陣列。valarray
提供了一些數學運算函式,如對每個元素進行操作、求平方根、求平均值等。valarray
的設計旨在提供高效能的數學運算,但在某些情況下可能不夠靈活。- 在實際開發中,
valarray
往往被認為是一個在數值計算方面更專業的工具,而不是通用的容器。
std::array
:std::array
是固定大小的陣列容器,其大小在編譯時確定。array
在記憶體中是連續儲存的,類似於原生陣列,但提供了更多的功能和安全性。array
提供了陣列的基本功能,如隨機訪問、迭代器等,但大小固定,不能動態增長或縮小。
#include <iostream>
#include <vector>
#include <valarray>
#include <array>
int main() {
// 1. std::vector 例子
std::vector<int> vec = {1, 2, 3, 4, 5};
vec.push_back(6); // 新增元素
for (int i : vec) {
std::cout << i << " ";
}
std::cout << "\n";
// 2. std::valarray 例子
std::valarray<int> valarr = {1, 2, 3, 4, 5};
valarr += 5; // 對每個元素加5
for (int i : valarr) {
std::cout << i << " ";
}
std::cout << "\n";
// 3. std::array 例子
std::array<int, 5> arr = {1, 2, 3, 4, 5};
for (int i : arr) {
std::cout << i << " ";
}
std::cout << "\n";
return 0;
}