在[1]對常用的STL容器進行了概覽,筆者在刷題過程中經常需要查詢一些STL容器的函數,實爲不便,因此在此對STL容器中常用的操作進行筆記。
std::vector
是一種線性數組,每個元素的數據類型都相同,不過和一般的靜態的數組不同的是,其允許通過插入元素,刪除元素實現所謂的動態數組,是常用的數據結構,類似於python中的列表list
。
其涉及到的常用操作有幾大類:
- 初始化操作,涉及到初始化數組時候的一些操作。
- 檢索index,對指定位置的元素進行讀取或者修改。
- 插入元素,在某個指定位置或者某個位置區間插入特定的元素。
- 刪除元素,在某個特定的位置或者區間刪除元素。
- 遍歷元素,屬於檢索元素的一種,不過其操作具有一般性,因此特地拿出來討論。
- 其他操作,包括對元素進行排序
sort
,檢查是否有特定元素等。
接下來進行概覽和舉例說明。
PS: vector.begin()
指向vector的第一個元素的位置,vector.end()
指向vector的最後一個元素的後一個位置。
1. 初始化操作
vector
的構造函數爲:
template < class T, class Alloc = allocator<T> > class vector; // generic template
可以用vector<data_type>
選擇元素的數據類型。一般有如下幾種常用的初始化方式:
vector<int> first; // 空的vector,只是一個列表的頭,裏面沒有元素
vector<int> second (4, 100); // 初始化一個具有4個元素的vector,每個元素的值都是100
vector<int> third (second.begin(), second.end()); // 通過其他vector的迭代器的方式,進行拷貝複製初始化
vector<int> fourth (third); // 直接對其他vector的拷貝複製
int myints[] = {16, 2, 77};
vector<int> fifth (myints, myints+sizeof(myints) / sizeof(int)); // 將數組轉化成vector,需要提供的是數組的首地址和地址偏移。
vector<int> sixth = {1,5,4,6}; // 指定內容進行構造,內容爲1,5,4,6的vector
在作爲函數返回或者傳參數時,可以進行匿名的構造,也就是不需要給予變量名字,如:
return vector<int>(); // 此時返回的就是空的vector
return vector<int>{1,4,5}; // 此時返回的是{1,4,5}
foo(vector<int>{1,4,5})
也可以實現多重vector
vector< vector<int> > vars;
// 二維vector的初始化
int size = 10;
vector<vector<int>> vars(size, vector<int>(size, 0)); // (size,size)的矩陣,元素全部是0
2. 索引元素
索引其元素和索引一般的數組元素相似
vector<int> first = {1,3,4,5,6};
first[1]; // 直接索引
first[1] = 0; //直接可以修改
first.at(1) = 0; // 也可以通過函數索引
*(first.begin()+3); // 也可以通過對迭代器取值得到,而且可以提供偏移比如+3.
first.back(); // 獲取vector的最後一個元素
3. 遍歷元素
遍歷元素可以通過以下方式進行:
- 採用迭代器
vector<int> vars = {1,3,5,6,7,8};
for (vector<int>::iterator it = vars.begin(); it != vars.end(); ++it){
*it = 10; // 遍歷每一個元素
}
通過對迭代器進行加減可以實現遍歷某一區間的元素:
vector<int> vars = {1,3,5,6,7,8};
for (vector<int>::iterator it = vars.begin()+1; it != vars.end()-1; ++it){
*it = 10; // 遍歷每一個元素
}
當然如果你用auto
關鍵字,你也可以這樣:
vector<int> vars = {1,3,5,6,7,8};
for (auto it = vars.begin(); it != vars.end(); ++it){
*it = 10; // 遍歷每一個元素
}
vector<int> vars = {1,3,5,6,7,8};
for (auto &v:vars)
cout << v << endl;
這種方法對於遍歷所有元素很方便
- 用索引的方式遍歷,這種方式是最直接的
vector<int> vars = {1,3,5,6,7,8};
int vsize = vars.size();
for (int i = 0; i < vsize: ++i){
vars[i];
}
4. 插入元素操作
對於線性的vector來說,如果是在最後一個位置添加一個元素,類似於python
中的list.append()
,那麼可以:
vector<int> vars ;
vars.push_back(10);
如果是需要在中間的某個位置插入元素,用insert()
:
vector<int> vars = {1,2,3,4,5};
vars.insert(vars.begin(), 100); // 插入單個元素,在vars的第0元素位置插入100,位置用迭代器表示
vars.insert(vars.begin(), 2, 100); // 插入多個相同的元素,此處插入2個100
vector<int> cop = {6,7,8};
vars.insert(vars.end(), cop.begin(), cop.end()); // 也可以進行vector之間的拼接
5. 刪除元素
vector<int> vars = {1,2,3,4,5,6};
vars.pop_back(); // 彈出最後一個元素,注意只是彈出,不返回其值,用vector.back()返回其值
vars.clear(); // 清空vector
auto iter = vars.erase(vars.begin()+1);
// 刪除單個元素,指定迭代器,刪除後vector的大小減1,但是容量不變。
// 其返回一個迭代器,指向被刪除元素後的第一個元素。
auto iter = vars.erase(vars.begin(), vars.begin()+2); // 刪除一個範圍內的值,指定開頭,結尾的迭代器即可。
其中在algorithm
頭文件中提供了remove
操作,其本質是對vector中的值進行匹配,如果匹配到了,則移到vector的末端。
例如
std::vector<std::string> words { "one", "none","some", "all”, "none", "most","many"};
auto iter = std::remove(std::begin(words), std::end(words), "none");
此處第二句將會匹配words
中的字符串none
,並且檢查其後一個元素,如果是不符合none
的,則把它前移,覆蓋掉前一個的none
,就結果而言,vector中的最後的若干個元素都變成了none
,因此這裏的remove
並不是實質上的移除,而是移到了末尾的位置,並且將其設爲了空字符串。如果此時用vector.size()
我們會發現其大小並沒有改變。
爲了釋放最後的無用的空間,我們結合erase
,有:
words.erase(iter, words.end()); // 此處的iter是由remove返回的迭代器
6. 其他操作
其他常見的操作有sort
排序,max_element
求最大值, min_element
求最小值, find
查找值,swap
交換值,distance
查找值的位置等函數,這些函數在頭文件<algorithm>
中。
sort
排序
vector<int> vars = {2,4,1,6,7,3,9};
sort(vars.begin(), vars.end()); // 默認是升序排列,輸出如 1,2,3,4,6,7,9
// 也可以指定特定的排序函數,取代默認的升序排序,甚至可以對非數值類型的數據結構進行排序。
bool sortFunc(const int &num1, const int &num2) {
return num1 > num2 ; // 降序排序
// return num1 < num2; 升序排序
// 返回爲true的將會放置於之前,false的元素爲之後
}
sort(vars.begin(), vars.end(), sortFunc);
max_element
,min_element
vector<int> vars = {2,4,1,6,7,3,9};
auto iter = max_element(vars.begin(), vars.end()); // 返回的是迭代器,指向的是最大值的位置,需要取值的話加*取值。
int max_value = *iter;
auto iter = min_element(vars.begin(), vars.end()); // 返回的是迭代器,指向的是最小值的位置,需要取值的話加*取值。
int min_value = *iter;
通過指定特定比較函數,可以實現不同數據結構的比較,如:
struct node {
int x, y;
};
bool cmp1(node a, node b) {
return a.x > b.x;
}
vector<node> v1(3);
node max_node = *max_element(v1.begin(), v1.end(), cmp1);
find
查找值的位置
此函數返回第一個匹配指定值的數據的位置。
vector<int> vars = {1,2,3,4,5,6};
int myints[] = {1,2,3,4,5,6};
int *p = find(myints, myints+6, 5); // 查找數值5的位置,如果找到了返回其位置的指針,否則將指向最後一個元素的下一個元素的位置,如
if (p != myints+6)
cout << "found in myints at location :" << p-myints << endl;
else
cout << "element not found in the arrays" << endl;
// 同樣的,對於vector也是適用的
vector<int>::iterator iter = find(vars.begin(), vars.end(), 5);
if (iter != iter.end())
cout << "found in myints at location :" << iter-vars.begin() << endl;
else
cout << "element not found in the arrays" << endl;
distance
求距離
求指定的迭代器之間的元素距離,類似於指針地址詳見,該函數在頭文件<iterator>
,如:
vector<int> vars = {1,2,3,4,5,6};
vector<int>::iterator iter = find(vars.begin(), vars.end(), 5);
cout << distance(vars.begin(), iter) << endl; // 類似於 iter-vars.begin()
Reference
[1]. https://blog.csdn.net/LoseInVain/article/details/104189784