C++複習(一):STL庫之vector容器

vector可以看做一個順序容器,它支持隨機訪問迭代器。

1、構造和賦值

#include<iostream>
#include<vector>
#include<string>
using namespace std;

//以下int,string等可替換成其他類型,若類型爲struct和class時可能還需考慮操作符重載
vector<int> vec1;    //創建一個空vector。不能加括號,會出問題。
vector<int> vec2(5);    //創建一個大小爲5、值均爲0的vector
vector<string> vec3(5);    //創建一個大小爲5、值均爲空字符串的vector
vector<string> vec4(5, "hello");    //創建一個大小爲5、值均爲"hello"的vector
vector<int> vec5 = { 7,3,5,2 };    //創建一個vector並賦值{7,3,5,2}
vector<int> vec6(vec5);    //創建一個和vec5值相同的vector
vector<int> vec7(vec5.begin(), vec5.begin() + 3);    //通過迭代器賦值{7,3,5}

//下標賦值
vec5[2] = 6;    //vec5值爲{7,3,6,2}

2、vector和數組相互轉化

#include<algorithm>

//數組轉化爲vector
int arr1[4] = { 1,2,3,4 };
vector<int> vec8(arr1, arr1 + 4);    //vec8值爲{1,2,3,4}

//vector轉化爲數組,暴力賦值或用algorithm庫函數copy,以下爲使用copy的方法
int* arr2=new int[vec8.size()];
copy(vec8.begin(), vec8.end(), arr2);    //arr2值爲{1,2,3,4}

3、大小、容量、如何改變

大小、容量

vec5.size()    //返回vec5中元素的個數,即vec5的大小,應爲4。
vec5.capcity()    //返回vec5當前能夠容納的元素數量,即vec5的容量,應爲4。STL中只有vector和string有這個屬性。一般沒什麼用。
vec5.max_size()    //返回容器所能容納的最大元素數目。這是系統或者庫所實施的限制,但是容器不一定保證能達到該大小,有可能在還未達到該大小的時候,就已經無法繼續分配任何的空間了。這個函數似乎沒有什麼卵用。

改變大小或容量

這部分參考:https://www.cnblogs.com/dengwuxie/p/7275101.html

//改變大小
void resize(size_type n, const T& c = T());
/*
其中n是要保留的元素個數,如果是要新增元素的話,c則是新增元素的默認初始值。
對於n值的大小,分三種情況:
(1)如果n大於容器當前的大小(即容器的size,這裏和capacity無關),則在容器的末尾插入n-size()個初始值爲c的元素;如果沒有指定初始值,那就元素類型的默認構造函數來初始化。
(2)如果n小於容器當前的大小,則刪除末尾的size()-n個元素,這樣就導致容器的大小變了,size 變小了。但是這種類型的容器在刪除一個元素的時候並不會釋放元素本身的內存空間【這也是爲了保留這塊空間以避免將來要插入新元素的時候又要進行存儲空間重分配】,所以容器的容量即capacity其實是沒有改變的。
(3)n等於容器當前的大小,則什麼也不做。
*/

//增加容量
void reserve(size_type n);
/*
對於n值的大小,分兩種情況:
(1)如果n大於容器現有的容量(capacity),比如你容器原來是100的容量,我現在指定n=200,那麼就需要在自由內存區爲整個容器重新分配一塊新的更大的連續空間【因爲vector是順序容器,所以存儲空間是連續的,如果之前的存儲空間不夠了,必須這樣做】,然後將容器內所有的有效元素從舊位置全部複製到新位置,這個過程是調用拷貝構造函數,然後釋放舊位置的所有存儲空間,並調整容器的元素位置指示器。所以reserve的時候如果n比原來的大,結果只是讓容器的冗餘容量(即沒有分配元素的存儲區)變大,容器的實際大小,即元素個數並沒有改變。
(2)如果n小於容器原來的容量,那麼這個函數什麼作用都沒有。相當於白調用了。
*/

/*
顯然,reserve和resize的共同點就是:都不縮減容器本身的容量。即對內存空間並沒有影響。那麼要是當你覺得容器的容量太多的時候,應該如何縮減容量呢。這時候需要用到一個利用swap函數的技巧,參見本文第8條。
*/

4、插入和刪除

//尾部插入
vector<int> vec9;    //值爲{}
vec9.push_back(3);    //值爲{3}
vec9.push_back(2);    //值爲{3,2}

//指定位置插入
vec9.insert(vec9.begin(), 7);    //值爲{7,3,2}
vec9.insert(vec9.begin()+2, 5);    //值爲{7,3,5,2}

//尾部刪除
vec9.pop_back();    //值爲{7,3,5}

//指定位置刪除
vec9.erase(vec9.begin()+1);    //值爲{7,5}

//指定位置插入另一個vector
vec9.insert(vec9.end(), vec5.begin(), vec5.end());    //vec9尾部插入vec5,值爲{7,5,7,3,6,2}

//清空
vec9.clear();    //值爲{}

5、遍歷

//下標遍歷
for (int i = 0; i < vec5.size(); i++) {
	cout << vec5[i] << " ";
}
cout<<endl;

//迭代器遍歷
vector<int>::iterator it = vec5.begin();
for(; it != vec5.end(); ++it){
	cout << (*it) << " ";
}
cout<<endl;

6、vector中的迭代器和引用

//迭代器
vec5.begin();    //返回頭部迭代器,指向第一個元素
vec5.end();    //返回尾部迭代器,指向最後一個元素的後一個位置
vec5.rbegin();    //反向迭代器,指向最後一個元素
vec5.rend();    //反向迭代器,指向第一個元素的前一個位置

//引用,好像沒什麼卵用,賦值可以直接通過下標賦值
vec5.at(2);    //返回位置2元素的引用
vec5.front();    //返回首元素的引用
vec5.back();    //返回尾元素的引用

7、查找,排序和反轉

//查找,排序和反轉都要用到algorithm庫
//用find函數查找。這種查找方式爲順序查找,在需要查找大量數據時最好還是用set或者hashmap比較快。
find(vec5.begin(), vec5.end(),3)    //查找vec5中3的位置,返回一個迭代器
//若找不到則返回vec5.end(),可用下行代碼判斷3是否在vec5中
if(find(vec5.begin(), vec5.end(),3)==vec5.end())    //若爲true,則3不在vec5中
//若找到則返回vec5中第一個3的迭代器
vector<int>::iterator it = find(vec5.begin(), vec5.end(),3);
if(it!=vec5.end())
    cout<<*it<<endl;    //輸出迭代器中的值

//用sort函數排序
sort(vec5.begin(), vec5.end())    //對vec5從小到大排序,值爲{2,3,6,7}
sort(vec5.begin(), vec5.end(), less<int>())    //對vec5從小到大排序,值爲{2,3,6,7}
sort(vec5.begin(), vec5.end(), greater<int>())    //對vec5從大到小排序,值爲{7,6,3,2}

//反轉
//用reverse函數排序
reverse(vec5.begin(), vec5.end())    //對vec5反轉,值爲{2,3,6,7}

//用vector的反向迭代器rbegin()和rend()反轉
//TODO:以後補充,基本也不會用這個方法進行反轉

8、其他常用函數

//判斷是否爲空
vec9.empty()    //返回vec9是否爲空,應爲true

//判斷兩個vector是否相等,直接用==、!=來判斷
if(vec5==vec9)

//甚至可以用<、>來判斷兩個vector的大小,按字典序排序
//但不是嚴格弱序的,即vector無法作爲std::map.find()的key值無法滿足a1<a2,a2<a3-->a1<a3的場景。
//沒怎麼看懂什麼意思。鏈接在這https://www.cnblogs.com/deityde1127/p/11937377.html
if(vec5<vec9)

//交換兩個vector的數據
//會影響capacity屬性,可以用來釋放內存,可參考https://www.cnblogs.com/mazhenyu/p/8295316.html。
vec5.swap(vec9)    //vec5和vec9交換數據。

9、有趣的簡單操作(不限於vector,僅用vector舉例)

求vector<int> v中最大最小值

//max_element和min_element在algorithm庫函數中
int max = *max_element(v.begin(),v.end()); 
int min = *min_element(v.begin(),v.end());

求vector<int> v所有元素的和

#include<numeric>
//accumulate的返回值類型爲第三個參數的類型,每次累加會先把vector中元素轉成第三個參數的類型再累加,所以當vector元素類型爲double時,第三個參數應寫成0.0,而不是0。若vector類型爲stirng,則用此函數可實現所有元素的連接。
int sum = accumulate(v.begin(),v.end(), 0);    //第三個參數爲累加的初值

對vector<int> arr排序並記錄排序前的下標。

struct Node {
	int val, index;
	bool operator<(const Node& b){
		if (this->val < b.val)
			return true;
		return false;
	}
};

vector<int> arr={9,5,2,7};    //arr的定義
vector<Node> vec;
for (int i = 0; i < arr.size(); i++) {
	Node tmp;
	tmp.val = arr[i];
	tmp.index = i;
	vec.push_back(tmp);
}
sort(vec.begin(), vec.end());
for (int i = 0; i < vec.size(); i++) {
	int index = vec[i].index;    //至此,訪問到排序後下標爲i數據的原下標index。
}

統計vector<int> arr中各個元素出現的次數

#include<map>

vector<int> arr={2,2,3,1,3};    //arr的定義
map<int, int> m;
for (i = 0; i < arr.size(); i++){
    if (m.end() != m.find(arr[i]))    //查找m中是否有arr[i]
        m[arr[i]]++;    //有的話,計數+1
    else
        m.insert(pair<int, int>(arr[i], 1));    //沒有的話,將arr[i]加入m,並計數爲1。
}
for (auto it : m){    //用迭代器訪問m中所有元素
    cout << it.first << " " << it.second << endl;
}

10、內存釋放

主要參考https://blog.csdn.net/hellokandy/article/details/78500067

vector其中一個特點:內存空間只會增長,不會減小。STL實現者在對vector進行內存分配時,其實際分配的容量要比當前所需的空間多一些。就是說,vector容器預留了一些額外的存儲區,用於存放新添加的元素,這樣就不必爲每個新元素重新分配整個容器的內存空間。

即使使用clear(),vector所佔用的內存空間依然如故,無法保證內存的回收。

如果需要空間動態縮小,可以考慮使用deque。如果vector,可以用swap()來幫助你釋放內存。

vector<int>().swap(arr);    //將arr與空的vector交換數據及內存。
//這個之前生成的匿名的vector在這行代碼結束後內存就應該被釋放了。

11、二維數組簡單操作

//構造二維數組{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
//方法一
vector<vector<int>> vec2d = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
//方法二
vector<vector<int>> vec2d;
for(int i = 0; i < 3; i++){
    vector<int> vec1d;
    vec1d.push_back(3 * i + 1);
    vec1d.push_back(3 * i + 2);
    vec1d.push_back(3 * i + 3);
    vec2d.push_back(vec1d);
}

//遍歷上述數組
for(int i = 0; i < 3; i++){
    for(int j = 0; j < 3; j++){
        cout<< vec2d[i][j] << " ";
    }
    cout<<endl;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章