本質
內部是一個數組,增加和刪除的時候涉及到大量元素移動、復制,所以耗時
數組大小可變,當插入操作超過默認大小,會重新分布內存
內部維護的是拷貝的數據,對原數據進行操作,不會更改vector內部數據
頭文件
#include <vector>
需要使用std 命名空間
增加
定義 vector<int> test{1, 2, 3, 4};
1.在尾部直接插入元素
test.push_back(1);
2.使用迭代器,第一個參數傳入一個指向當前vector的迭代器,第二個參數傳入值
test.insert(test.begin(), 1); //在頭部插入
有多個重載函數:
填充指定個數的元素
test.insert(test.begin(), 10, 1); //第一個參數是迭代器位置,第二個參數是個數,第三個參數是值
插入迭代器范圍的數據
test.insert(test.begin(), test.begin(), test.end());
第一個參數是插入迭代器位置,第二個參數和第三個參數是范圍,左閉右開
3.值得注意的是,由於vector是可變的,像vector插入后,可能使所有指向vector的指針、迭代器失效
當添加到一定大小,vector就會重新分配空間,將舊的空間元素拷貝到新空間中,釋放舊空間
4.函數的參數的迭代器由於3的原因可能失效,但是返回值一定不會失效
看源碼可知返回值使用begin() + __offset,而不是傳入的參數迭代器,就是因為可能內存重新分配
如果你在做一個循環插入或者賦值的首推薦
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> test{1, 2, 3, 4};
for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end(); test_iterator++) {
if(*test_iterator == 3) {
test_iterator = test.insert(test_iterator, 4);
if( test_iterator + 1 == test.end()) {
break;
}
test_iterator++;
}
}
return 0;
}
當滿足條件插入后,防止迭代器失效,使用insert的返回值進行重新賦值,之后的 test_iterator++;是因為test_iterator當前指向4,如果不連着加兩次會陷入死循環,下一個再加就到了4
刪除
1.刪除尾部元素
test.pop_back();
2.使用迭代器
test.erase(test.begin()); //參數為迭代器位置,返回值為迭代器位置
多個重載函數
test.erase(test.begin(), test.end() - 1); //刪除迭代器的范圍元素,左閉右開
3.迭代器循環刪除,這個是比較有爭議的
對於erase的返回值:
An iterator pointing to the next element (or end()).
指向下一個元素的迭代器
關於erase有詳述
本人這里認為返回的迭代器就是指向的你刪除元素之后的元素,注意的是迭代器本身沒有改變,只不過是元素遷移了
循環刪除推薦
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> test{1, 2, 3, 4};
for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end();) {
if(*test_iterator == 3) {
test_iterator = test.erase(test_iterator);
}
else {
test_iterator++;
}
}
return 0;
}
4.網上好多提到remove函數
千篇一律都是remove和erase搭配,我erase明明就可以實現,要remove干嘛呢?
為了刪除范圍內所有的指定元素,erase函數只能刪除單個的,要不就是一個范圍,沒有remove這種條件的刪除
remove不是成員函數,不能真正的刪除
這里先說__remove_if,remove本質也是__remove_if
__remove_if是有條件的刪除,第一個參數和第二個參數代表范圍,第三個參數構建一個value值的對象
然后在__remove_if內部對給定值比較,做了一個for循環賦值,把不等於給定值的都移動到前面
這樣到最后,把等於給定值的第一個迭代器返回
這就是remove的核心,的確不能直接刪除元素,但是remove對整個迭代器區間的元素進行了重新賦值分配,划分了兩撥,前面是不含有給定值的,后面是含有給定值的來個圖片
之后就是配合erase的迭代器區間刪除函數就可以了
remove頭文件是#include <algorithm>
例子
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> test{1,3,3,3,4,3};
for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end(); test_iterator++) {
std::cout << *test_iterator << std::endl;
}
test.erase(remove(test.begin(), test.end(), 3), test.end());
for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end(); test_iterator++) {
std::cout << *test_iterator << std::endl;
}
//刪除前1,3,3,3,4,3
//刪除后1,4
return 0;
}
訪問和改動
1.使用迭代器進行修改
STL中迭代器有兩種,一種是const_iterator,一種是iterator,區別就是const_iterator只能讀取和調用const相關的函數,iterator都可以
本質就是const和非const的區別
我們可以使用迭代器-> 調用迭代器指向的內存變量的函數,迭代器-> 和 內存變量. 的操作是一樣的
也可以使用 *迭代器. 的操作,這樣就是拿到迭代器指向的變量然后操作
2.c.back(); //返回c中尾元素的引用,如果c為空,函數未定義
3.c.front(); //返回c中首元素的引用,如果c為空,函數未定義
4.c[n]; //返回c中下標為n的元素引用,如果n>=c.size(),行為未定義
5.c.at[n]; //返回下標為n的元素引用,如果下標越界,拋出異常
這些訪問元素的成員函數返滬的都是引用,容器是const,返回的是const引用,不是const,返回普通引用。內部根據const重載了訪問函數
添加刪除都要考慮迭代器失效問題
使用insert和erase返回值更新迭代器