常用容器之二—— vector 和 list 。
目錄
vector(向量):
vector是一個能夠存放任意類型的動態數組,只能在尾部進行插入和刪除,其實它的用法和數組一樣,只是它的功能比數組強大。
優點:
1.可以隨機訪問任意一個元素。(和數組一樣)
2.它是動態數組,動態數組是當內存不夠的時候,它可以自動擴增,而不需要我們人爲地進行擴增。
缺點:
和數組一樣,不能很好的進行插入和刪除操作。
必須加頭文件 #include<vector>
先簡單介紹一下函數 push()、empty()、pop()、size()、capacity()、max_size()。
push_back(); //在向量尾部增加一個元素
empty(); //判斷向量是否爲空
pop_back(); //刪除向量中最後一個元素
size(); //返回向量中元素的個數
resize(); //設置大小(調整容器的長度)
capacity(); //返回當前向量的容量
max_size(); //返回可允許的元素數量的最大值
其實這些函數的用法與之前我們所學的string和stack、queue裏面的用法是一樣的 ,特別是capacity()和resize()函數。
具體請參照之前 string 的博客。
reserve(); //設置容量(調整容器的容量大小)
在這裏主要區分一下 resize() 和 reserve() 函數。
1. resize(n)函數:
resize(n):調整容器的長度大小,使其能容納n個元素
如果n小於當前的size,則刪除多出來的元素,反之,不夠的用值初始化元素的默認值來填充。
resize(n,t):這是對於n大於當前的size的情況時,就將新增加的元素都初始化爲t(即用t來填充)。
2. reserve(n)函數:
reserve(n):預分配n個元素的存儲空間。
如果n小於或者等於capacity,其容量就不會變,反之,就重新分配內存空間,從而使capacity=n。
簡單點說,就是 resize()函數與容器的size有關,而reserve()函數與容器的capacity有關。
區別:
調用resize()函數後,所有的空間都已經初始化了,所以可以直接訪問;而reserve()函數預分配出的空間沒有被初始化,所以不可訪問。
可以看到,最開始增加元素數量爲10時,而此時容量16比10大,這是因爲計算機認爲你可能還要再增加元素,所以就多開闢了一些空間。
另外還有一些函數,front()、back()。
front(); //返回首元素
back(); //返回尾元素
以上函數就不再細說了,在下面的代碼中都會經常用到。
初始化
//Vector<類型>標識符
vector<int>v; //創建一個空的 vector
//Vector<類型>標識符(最大容量)
vector(int n); //創建一個元素個數爲 n 的vector
以上兩種最好還是用第二種形式。
原因:
可以看到,隨着元素個數的增加,容量也由0變爲了1,而我們前面學string的時候就學習過容量capacity()函數的特性,當元素個數超過了容量之後,此時我們就需要創建一個更大容量的數組,然後把數據複製到這個新數組中,這樣會大大降低效率,所以我們儘量不這樣做,相比之下,所以我們還是儘量採取以下形式:(提前爲其分配空間 )
//Vector<類型>標識符(最大容量,初始值)
vector(int n,const t) //創建一個 vector,元素個數爲n,且值均爲t
//Vector<類型>標識符(begin,begin+n)
vector<類型>v1(); //先構造容器v1
vector<類型>v(v1.begin(),v1.begin()+n); //用v1將v初始化
這樣也可以:
用數組對容器進行初始化
總之是可以這樣用的,至於其中的道理,我是這樣來理解記憶的(雖然不一定理解對了,但最起碼能幫助記住):
以上就是初始化的方法。
訪問
直接使用中括號來訪問 //與數組用法一樣
對了,要是想讓它們都輸出在第一行,就這樣寫就好了:
at();
區別:中括號與at()函數的區別就在於at()能檢測是否越界,具體的我們在學string時都有詳細瞭解過,如果還不明白的話可以去看一下之前的string的博客。
賦值
插入
insert();
刪除
erase();
清空
clear();
收縮內存
swap();
可以看到,當我們使用swap來收縮內存的時候,其容量也確實隨之變了。
list(雙向鏈表):
優點:
1. 與向量(vector)相比,它可以快速的進行插入和刪除操作。
2. 不使用連續的內存空間就可以隨意的進行動態操作。
缺點:
1. 由於它是鏈表,所以它隨機訪問比較慢,相比vector不能使用at()來訪問。
2. 相對於 vector 佔用了更多的內存。
必須加頭文件 #include<list> 。
初始化
它的初始化與向量(vector)的初始化方法基本上是一樣的(也是上面那5種方法)。
基本函數
它的基本函數與上面向量(vector)的大同小異,可以參照上面的。
還有函數:
begin(); //返回指向第一個元素的迭(die)代器
end(); //返回末尾的迭(die)代器
下面來列舉一下不同於以上的函數:
賦值
list assign(); //給list賦值
也可以這樣:
當然鏈表list同以上vector一樣也可以直接將一個鏈表賦值給另一個鏈表,如下:
合併
merge();
刪除
remove();
倒轉(逆序)
reverse(); //將鏈表list中的元素倒轉
排序
sort();
交換
swap();
刪除重複元素
unique(); //刪除list中重複的元素
以上是兩個比較常用的容器vector和list的相關函數以及用法的總結,其實可以把它們兩個看成正好相反的兩個,也是比較有意思的哈哈。