走近STL - Vector,再次見面

在Leecode上做了一些vector的題目,有了新的感悟,所以重新對這篇文章進行一次脫胎換骨式的修改。

Vector是STL中一個很常用的容器。
作用:Vector可以理解爲是一個可以存放 任意的統一種類的數據的動態數組

能來看的對vector應該是有了解的,閒話不多說。

1、Vector,再次見面,還請多多關照

Vector的數據結構與array非常相似,不同的地方在於array是靜態的,一旦確定了範圍之後便不能改變(不定長數組零擔別論)。
要換個更大的空間是比較麻煩的,一切都得自己手動來。
Vector是動態分配空間的,相對比較友好,如果需要擴容的話它的內部機制會自己去處理。


2、Vector基本函數使用

  1. 創建
#include<vector>

vector<int>test;	//初始化一個Vector實例,用於存放int型數據,實例名字叫test

vector<int>test2 = test;	//以test1爲標準創建test2

再看一個vector<int>test3(10);
//創建一個vector容器,大小爲10,內容默認置空 //不是很建議這種做法啊,因爲我今天使用這種初始化方式出了bug,我往裏面插成段的值的時候只能插入第一個,後面就無法插入了。
//再說了,你不用自己分配空間,STL都給你安排的好好的。

當然,初始化方式千千萬,放多了反而讓人眼花繚亂,會基本的最實用的夠了。

  1. 插入元素
test.insert(test.begin()+i,a);	//在第i個元素前插入a

test.insert(test.begin()+i,te2.begin(),te2.end());	
//插入一段相同數據類型數據,第一個參數放插入位置(指針/迭代器形式),第二三個參數放待插入元素起始位置

test.push_back(a);	//往尾部插入
  1. 刪除元素
test.erase(test.begin());
test.erase(test.begin(),test.begin()+5);//刪除區間(第一個元素到第五個元素)

test.clear();	//清空

test.pop_back();	//刪除尾部元素

刪除呢,還有個比較靈活的方式:

test.erase(it);	//這個it是迭代器

關於刪除有一個必須·要注意的點:不要在foreach的時候進行刪除操作,如果你一定要在遍歷的時候進行刪除,你最好看一下下一行那個鏈接。

對於增刪,對於初學者有一個坑在等着,不過我已經幫你們踩平了,點進來看看

  1. 遍歷元素
    當然,你可以使用數組下標形式訪問元素,因爲vector重載了 [] 操作,不過不建議。雖然是很方便,但是有諸多限制,要是隨便就任你操作數據,那人家封裝起來幹什麼?
    我們應該養成使用下面這種迭代器訪問的方式。
vector<int>::iterator it;	//初始化一個vector<int>類型的迭代器
for(it = test.begin();it!=test.end();it++)	//從頭遍歷到尾
{
	cout<<*it<<endl;	//取出內容
}

關於迭代器還需要知道的是:vector的迭代器支持前後向,及重載了 +,—,++,-- 操作。

還有一個叫at()的函數,這個好用。

test.at(2);		//用這個比直接用下標要好的地方在於它會檢測越界
  1. 頭尾指針
    這四個函數的區別要清楚:begin()、end()、front()、back()。我喜歡稱它們爲頭尾指針。
    我也不知道爲什麼有人要就這些區別長篇大論。
begin():指向容器的第一個元素的地址。
front():指向容器的第一個元素的值。
end():和begin()配套
back():和front()配套
  1. 容器容量
test.size();	//容器已存入數據量
test.capacity();	//容器還能存多少數據量

其實不用擔心容器不夠大,容量要滿的時候它會自己擴容。

  1. 排序
#include<algorithm>
/*test.*/sort(test.begin(),test.end());	//從頭到尾,默認從小到大排序
這裏要非常注意,前面那個test. 被我註釋掉了,因爲sort是屬於算法範疇,不是容器的類方法。

//一般排序都是要自定義排序的:
bool Comp(const int &a,const int &b)
{
    return a>b;
}
sort(test.begin(),test.end(),Comp);	//這樣就降序排序。 
  1. 其他

swap(test,test2);	//交換test和test2中的數據

test.resize(20);	//重置大小

reverse(test);		//元素翻轉

如果要問爲什麼沒有 “修改數據的部分”,參見第四點“遍歷數據”。


10、unique()函數

這個函數用來清理容器中的重複項,但前提是容器經過排序了。
而且,它不提供刪除操作,只是把重複項移到容器後面的部分,所以直接size()的話大小是不會變的。
如果要清理重複項,這樣:nums.erase(unique(nums.begin(),nums.end()),nums.end());


最後再提一下兩個頭文件:

#include<vector>	//vector類相關
#include<algorithm>	//容器算法

vector的元素不僅僅可以是int,double,string,還可以是結構體,但是要注意:結構體要定義爲全局的,否則會出錯。

特別注意:

使用vector需要注意以下幾點:

1、如果你要表示的向量長度較長(需要爲向量內部保存很多數),容易導致內存泄漏,而且效率會很低;

2、Vector作爲函數的參數或者返回值時,需要注意它的寫法:

double Distance(vector&a, vector&b) 其中的“&”絕對不能少!!!


Vector的數據結構

所謂動態增添大小,並不是在原有空間之後再開闢空間,顯然那也不太現實。
而是以原大小的兩倍大小尋找一塊新空間,將內容真實的拷貝過去,然後釋放原空間。
不過就算刪除元素過半也不會將內存放出來。

但是,需要牢記的一點是:對於Vector的一切操作,一旦引起空間的重新分配,那麼指向原有空間的迭代器將會全部失效。

關於這點,我也做了一個測試代碼:
可測可不測,結果我都註釋好了

#include <iostream>

#include<vector>

using namespace std;

int main()
{
    vector<int> vec1;
    //vector<int>::iterator it1 = vec1.begin();
    //放這裏試試
    vec1.push_back(1);
     cout<<"left size :"<<vec1.capacity()<<endl;	//1
    vec1.push_back(6);
     cout<<"left size :"<<vec1.capacity()<<endl;	//2
    vec1.push_back(5);
     cout<<"left size :"<<vec1.capacity()<<endl;	//4
    vec1.push_back(4);
     cout<<"left size :"<<vec1.capacity()<<endl;	//4
    vec1.push_back(3);
     cout<<"left size :"<<vec1.capacity()<<endl;	//8
    //vector<int>::iterator it1 = vec1.begin();
    //放這裏試試
    vec1.push_back(3);
     cout<<"left size :"<<vec1.capacity()<<endl;	//8
    vec1.push_back(3);
     cout<<"left size :"<<vec1.capacity()<<endl;	//8
    vec1.push_back(3);
     cout<<"left size :"<<vec1.capacity()<<endl;	//8
    vec1.push_back(2);
     cout<<"left size :"<<vec1.capacity()<<endl;	//16

    vector<int>::iterator it1 = vec1.begin();
//這個循環用於在6之後插入4
    while (it1 != vec1.end())
    {
        if (3 == *it1)
        {
            vec1.insert(it1+1, 4);
            cout<<"insert:"<<*it1<<endl;
        }
        it1++;
    }

//執行完插入操作,將值全部打印
    for(it1 = vec1.begin();it1!=vec1.end();it1++)
    {
        cout<<*it1<<endl;
    }
    cout<<"it1over"<<endl;

//準備執行對元素‘3’的刪除
    vector<int>::iterator it2 = vec1.begin() ;
    while (it2 != vec1.end())
    {
        if (3 == *it2)
        {
             //it2 =vec1.erase(it2);
             vec1.erase(it2);	//這裏有沒有都一樣,都指向刪除之後的那個位置
             cout<<"delete:"<<*it2<<endl;
        }
        else
            it2++;
    }
//執行完刪除操作,將容器數據進行打印
    for(it2 = vec1.begin();it2!=vec1.end();it2++)
    {
        cout<<*it2<<endl;
    }
    cout<<"it2over"<<endl;

//爲測試方便,這裏直接清空Vector,看看它放不放空間
    vec1.clear();
    cout<<"clear left size :"<<vec1.capacity()<<endl;	//16
    return 0;
}

這一章就先到這裏吧

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