c++ vector 複製_C++:vector小指南(附帶一些新手錯誤)
技術標籤:c++ vector 複製
參考文章:
1.C++_vector操作_劉同學的部落格-CSDN部落格_vector
2.C++ vector 容器淺析 | 菜鳥教程
1. vector
- vector是向量型別,可以容納許多型別的資料,因此也被稱為容器
- (可以理解為動態陣列,是封裝好了的類)
- 進行vector操作前應新增標頭檔案#include <vector>
1.1 vector 建立:
一維(不指定列長):
vector<int>a;
二維(指定行數,固定列長):
int N = 5, M = 6; vector<vector<int>>obj(N, vector<int>(M)); //定義二維動態陣列5行6列
輸出結果(預設填充0):
二維(指定行數,不固定列長):
int N = 5, M = 6;
vector<vector<int> > obj(N); //定義二維動態陣列大小5行
for (int i = 0; i < obj.size(); i++)//動態二維陣列為5行(i+3)列,值全為0
{
obj[i].resize(i+3);
}
輸出結果(預設填充0):
1.2 一維vector初始化:
方式1.
//定義具有10個整型元素的向量(尖括號為元素型別名,它可以是任何合法的資料型別),不具有初值,其值不確定 vector<int>a(10);
方式2.
//定義具有10個整型元素的向量,且給出的每個元素初值為1
vector<int>a(10,1);
方式3.
//用向量b給向量a賦值,a的值完全等價於b的值
vector<int>a(b);
方式4.
//將向量b中從0-2(共三個)的元素賦值給a,a的型別為int型
vector<int>a(b.begin(),b.begin+3);
方式5.
//從陣列中獲得初值
int b[7]={1,2,3,4,5,6,7};
vector<int> a(b,b+7);
1.3 vector物件的常用內建函式使用(舉例說明)
#include<vector>
vector<int> a,b;
//b為向量,將b的0-2個元素賦值給向量a
a.assign(b.begin(),b.begin()+3);
//a含有4個值為2的元素
a.assign(4,2);
//返回a的最後一個元素
a.back();
//返回a的第一個元素
a.front();
//返回a的第i元素,當且僅當a存在
a[i];
//清空a中的元素
a.clear();
//判斷a是否為空,空則返回true,非空則返回false
a.empty();
//刪除a向量的最後一個元素
a.pop_back();
//刪除a中第一個(從第0個算起)到第二個元素,也就是說刪除的元素從a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)結束
a.erase(a.begin()+1,a.begin()+3);
//在a的最後一個向量後插入一個元素,其值為5
a.push_back(5);
//在a的第一個元素(從第0個算起)位置插入數值5,
a.insert(a.begin()+1,5);
//在a的第一個元素(從第0個算起)位置插入3個數,其值都為5
a.insert(a.begin()+1,3,5);
//b為陣列,在a的第一個元素(從第0個元素算起)的位置插入b的第三個元素到第5個元素(不包括b+6)
a.insert(a.begin()+1,b+3,b+6);
//返回a中元素的個數
a.size();
//返回a在記憶體中總共可以容納的元素個數
a.capacity();
//將a的現有元素個數調整至10個,多則刪,少則補,其值隨機
a.resize(10);
//將a的現有元素個數調整至10個,多則刪,少則補,其值為2
a.resize(10,2);
//將a的容量擴充至100,
a.reserve(100);
//b為向量,將a中的元素和b中的元素整體交換
a.swap(b);
//b為向量,向量的比較操作還有 != >= > <= <
a==b;
2. 順序訪問vector的幾種方式,舉例說明
2.1. 對向量a新增元素的幾種方式
(1)向向量a中新增元素
vector<int>a;
for(int i=0;i<10;++i){a.push_back(i);}
(2)從陣列中選擇元素向向量中新增
int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=0;i<=4;++i){b.push_back(a[i]);}
(3)從現有向量中選擇元素向向量中新增
int a[6]={1,2,3,4,5,6};
vector<int>b;
vector<int>c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();++it)
{
b.push_back(*it);
}
(4)從檔案中讀取元素向向量中新增
ifstream in("data.txt");
vector<int>a;
for(int i;in>>i){a.push_back(i);}
2.2 從向量中讀取元素
(1)通過下標方式獲取(元素必須存在!)
int a[6]={1,2,3,4,5,6};
vector<int>b(a,a+4);
for(int i=0;i<=b.size()-1;++i){cout<<b[i]<<endl;}
(2)通過迭代器方式讀取
int a[6]={1,2,3,4,5,6};
vector<int>b(a,a+4);
for(vector<int>::iterator it=b.begin();it!=b.end();it++){cout<<*it<<" ";}
3.幾個常用的演算法
#include<algorithm>
//對a中的從a.begin()(包括它)到a.end()(不包括它)的元素進行從小到大排列
sort(a.begin(),a.end());
//對a中的從a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素為1,3,2,4,倒置後為4,2,3,1
reverse(a.begin(),a.end());
//把a中的從a.begin()(包括它)到a.end()(不包括它)的元素複製到b中,從b.begin()+1的位置(包括它)開始複製,覆蓋掉原有元素
copy(a.begin(),a.end(),b.begin()+1);
//在a中的從a.begin()(包括它)到a.end()(不包括它)的元素中查詢10,若存在返回其在向量中的位置
find(a.begin(),a.end(),10);
4.常見錯誤總結(都是我跳過的坑..)
(1)在建立vector時,若沒有指定列長,則向量中不存在任何元素,無法被讀取。如:
vector<int>a;
for (int i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
結果:程式或許可以正常執行,但是不會輸出任何內容。
(2)只有vector某位置已經存在元素時,才可以用下標去賦值/改值。如:
vector<int>a;
for (int i = 0; i < a.size(); i++)
{
a[i] = i + 2;
cout << a[i];
}
結果:程式或許可以正常執行,但是不會輸出任何內容。
(3)出現警告 warning C4018: “<”: 有符號/無符號不匹配。如:
以下程式碼將被警告:
vector<int>a(10,1);
for (int i = 0; i < a.size(); i++)
{
cout << a[i] << " ";
}
警告原因:
a 是一個vector容器,a .size() 在容器說明中被定義為: unsigned int 型別, 而 i 是 int 型別,所以會出現: 有符號/無符號不匹配警告。
也就是:在 比較運算子 前後 的 數值型別 要相同,問題可能在左側,也可能在右側,具體情況具體分析!
修改方法:
將 i 改為 unsigned int 型別即可。
(4)在自定義類資料成員中新增 vector 時,出現錯誤:“應輸入型別說明符”。如:
問題分析:
①vector是封裝的類,當在一個類中定義另一個類時,就會出現這樣的報錯;
②問題實質在於,當定義 vector 的時候同時呼叫了 vector 的帶參建構函式。我們可以將“N”放到類的建構函式中去。如:
class Init_Population
{
private:
int N = 10;
vector<vector<int>>generate_population;
public:
//建構函式
Init_Population()
{
generate_population.resize(N);
}
};
參考:C++ vector 實現二維陣列時, 在類的標頭檔案中定義時遇到"應輸入型別符"的問題?
③其他解決方式
一般在類外(主函式、任何函式中)定義vector時,都可以“直接初始化”,即定義的同時就指定行寬列長等。
既然在類中定義vector不可以“直接初始化”,那麼就使用“拷貝式初始化”。如:
//改成花括號
int N = 10;
vector<vector<int>>generate_population{ N };
參考:為何在類中初始化另一個類會出錯? - 知乎 https://www.zhihu.com/question/329974084
(5)一個關於類和物件的小插曲,寫在這是因為起初以為是vector無法被return,最後發現不是vector的問題。問題如下:
#include<iostream>
using namespace std;
#include<vector>
class Init_a
{
private:
int i, j;
int N = 10;
vector<int>a;
public:
//給向量 a 賦值
void SetValue()
{
for (i = 0; i < N; i++)
{
a.push_back(i + 1);
}
}
//獲取向量 a 的資料
int GetValue(int k)
{
return a[k];
}
};
int main()
{
int N = 10;
Init_a a1;
a1.SetValue();
//正確!(物件一致,才有功能上的延續性)
for (int i = 0; i < N; i++)
{
cout << a1.GetValue(i) << " ";
}
錯誤!(物件不一致,功能上不具有延續性)
//Init_a a2;
//for (int i = 0; i < N; i++)
//{
// cout << a2.GetValue(i) << " ";
//}
return 0;
system("pause");
}
引以為戒:程式碼幹太久,容易變傻。。這種小毛病還真不太好發現!
(6)錯誤 "xxxx":C++提示非標準語法;請使用 "&" 來建立指向成員的指標
修改
在提示的那一行認真檢查類成員函式的呼叫,如
Widget.name
//Widget.name(); 正確的呼叫方式
原因
此時使用的應該是類的成員函式,而不是類的成員變數當我們使用類的成員函式時,VS編輯器並不會自動幫我們加上圓括號(它會提示是成員函式,還是成員變數哦[圖示顏色不同]),所以很多新手會忘記加()以表示函式的呼叫。當不加括號是,也就是函式不傳入引數(void也是引數哦)的話,編譯器將會理解成函式指標(在c++中,函式名就是函式的起始地址),但函式指標需要這樣寫
&Widget.name
也是個小馬虎導致的問題,隨便記錄一下。。
(7)容器(vector)作為函式引數如何傳參
參考:c++ 函式vector傳參_h799710的部落格-CSDN部落格
之前的一些函式使用陣列傳參的,用了vector後,傳參出錯,需要用vector的傳參方式了。
vector傳參的三種方式:
- void func1(vector vet); //傳送數值
- void func2(vector &vet); //引用
- void func3(vector *vet); //指標
這三種方式產生的效果:
- 呼叫拷貝建構函式,形參改變不會影響到實參
- 不呼叫拷貝構函式,形參改變影響到實參
- 不呼叫拷貝構函式,形參改變影響到實參
程式碼如下:
void func1(vector<int> vet) {
vet.emplace_back(1);
}
void func2(vector<int> &vet) {
vet.emplace_back(2);
}
void func3(vector<int> *vet) {
vet->emplace_back(3); //指標用 ->
}
int main() {
vector<int> vet;
func1(vet);
cout << vet[0] << endl; //!!!報錯,因為實參不會改變(想正常執行可註釋掉這句)
vector<int> vet2;
func2(vet2);
cout << vet2[0] << endl; //輸出 2
vector<int> vet3;
func3(&vet3); //這裡取得是指標
cout << vet3[0] << endl; //輸出 3
//system("pause");
return 0;
}
小結:
- vector最好採用引用或者指標的傳參,因為如果資料量大的時候,拷貝會非常的慢;如果只是不想讓資料被修改,可以在vector前加上const。
- 之前用陣列喜歡用指標傳參,但是在vector中不是那麼方便,vector指標傳參後,每一次呼叫值都需要加上取地址符&,有點麻煩。用引用傳參好一點。