vector的介紹及使用

vector的介紹

  1. vector是表示可變大小數組的序列容器。
  2. 就像數組一樣,vector也採用的連續存儲空間來存儲元素。也就是意味着可以採用下標對vector的元素 進行訪問,和數組一樣高效。但是又不像數組,它的大小是可以動態改變的,而且它的大小會被容器自 動處理。
  3. 本質講,vector使用動態分配數組來存儲它的元素。當新元素插入時候,這個數組需要被重新分配大小 爲了增加存儲空間。其做法是,分配一個新的數組,然後將全部元素移到這個數組。就時間而言,這是 一個相對代價高的任務,因爲每當一個新的元素加入到容器的時候,vector並不會每次都重新分配大 小。
  4. vector分配空間策略:vector會分配一些額外的空間以適應可能的增長,因爲存儲空間比實際需要的存 儲空間更大。不同的庫採用不同的策略權衡空間的使用和重新分配。但是無論如何,重新分配都應該是 對數增長的間隔大小,以至於在末尾插入一個元素的時候是在常數時間的複雜度完成的。
  5. 因此,vector佔用了更多的存儲空間,爲了獲得管理存儲空間的能力,並且以一種有效的方式動態增 長。
  6. 與其它動態序列容器相比(deques, lists and forward_lists), vector在訪問元素的時候更加高效,在 末尾添加和刪除元素相對高效。對於其它不在末尾的刪除和插入操作,效率更低。比起lists和 forward_lists統一的迭代器和引用更好。

vector的使用

1定義

vector<類型> name

#include<vector>
void test()
{
	vector<int> v1//定義了一個空的vector對象
	vector<char> v2(4,a);//定義了一個vector對象,大小爲4 初始均爲四個字符a
	vector<char> v3(v2.begin(),v2.end());//通過迭代器複製v2到v3
	vector<char> v4(v3);//拷貝構造v4
}

vector迭代器使用
begin()
獲取第一個數據位置的iterator/const_iterator

end()
獲取最後一個數據的下一個位置 的iterator/const_iterator

#include<vector>
void test()
{
	vector<int> v(5,1)
	//可讀可寫迭代器
	vector<int>::iterator it = v.begin();//it爲v的開始位置
	while(it != v.end())
	{
		cout<<*it<<" ";
		*it = 10;//重新賦值爲10;
		it++;//迭代器向後走
	}
	//只讀迭代器
	vector<int>const_iterator cit = v.begin()
	while(it != v.end())
	{
		cout<<*cit<<" ";
		*cit = 10;//重新賦值爲10;
		cit++;//迭代器向後走
	}
	//範圍for
	for(int & num:v)
		cout<<num;
}

反向迭代器
rbegin()
獲取最後一個數據位置的reverse_iterator
rend()
獲取第一個數據前一個位置的 reverse_iterator

#include<vector>
#include<iostream>
void test()
{
	vector<int>::reverse_iterator rit = v.rbegin();    
	// 使用反向迭代器進行遍歷再打印 
	while (rit != v.rend())    
	{        
		cout << *rit << " ";        
		++rit;    
		}    
	cout << endl;
}

2.vector的空間增長

常用接口
size() ———獲取有效字符個數
capacity() ——獲取當前容量大小
empty() ————判斷當前對象是否爲空
resize() ————改變vector對象的size
reserve() ————改變容量,只能擴大,不能縮小

#include<vector>
void test()
{
	vector<int> v(10,100);
	int len = v.size();//v的有效字符爲10
	int capa = v.capacity();//獲取v的容量
	bool true = v.empty();//判斷是否爲空
	v.resize(5)//將v的有效字符變爲5個
	v.resize(8,10)//v的有效字符變爲8個,多出的賦值爲10
	v.resize(15)//有效字符爲15個,多出的默認賦值爲0
	v.reserve(5)//容量不會被縮減到5
	v.reserve(20)//容量擴大爲20
}

注意:
1.capacity的代碼在vs和g++下分別運行會發現,vs下capacity是按1.5倍增長的,g++是按2倍增長的。 這個問題經常會考察,不要固化的認爲,順序表增容都是2倍,具體增長多少是根據具體的需求定義 的。vs是PJ版本STL,g++是SGI版本STL。
2.reserve只負責開闢空間,如果確定知道需要用多少空間,reserve可以緩解vector增容的代價缺陷問 題。
3.resize在開空間的同時還會進行初始化,影響size。

vector的增刪查改

push_back ——尾插
pop_back ——尾刪
find ——查找。(注意這個是算法模塊實現,不是vector的成員接口)
insert ——在position之前插入val
erase ——刪除position位置的數據
swap ——交換兩個vector的數據空間
operator[] ——像數組一樣訪問

	vector<int> v1(10,1);
	int i = 0;
	vector<int>::iterator it = v1.begin();
	while(it != v1.end())
	{
		cout<<*it;//結果爲1111111111
		*it = i++;
		it++;
	}
	cout<<endl;
	for(int & num:v1)
		cout<<num;//結果爲0123456789
	v.push_back(10);//尾部插入10
	for(int & num:v1)
		cout<<num;//結果爲012345678910
	v.pop_back();//刪除尾部10
	for(int & num:v1)
		cout<<num;//結果爲0123456789
	//使用find查找3所在位置的iterator 
	vector<int>::iterator pos = find(v1.begin(), v1.end(), 3); 
	// 在pos位置之前插入30    
	 v.insert(pos, 30);
	 pos = find(v.begin(), v.end(), 3);   
	  // 刪除pos位置的數據    
	  v.erase(pos);
      it = v.begin();    
      while (it != v.end()) 
      {        
      	cout << *it << " ";        
      	++it;    
      }    
      cout << endl;
 //使用[]訪問對象成員
 cout<<v1[0]<<endl;//結果爲0
 v1[0] = 10;//可以通過[]改變對象的值
 //通過[]遍歷v1
 for (size_t i = 0; i < v1.size(); ++i)
        cout << v1[i] << " ";

vector迭代器失效的問題

迭代器的主要作用就是讓算法能夠不用關心底層數據結構,其底層實際就是一個指針,或者是對指針進行了 封裝,比如:vector的迭代器就是原生態指針T*。因此迭代器失效,實際就是迭代器底層對應指針所指向的 空間被銷燬了,而使用一塊已經被釋放的空間,造成的後果是程序崩潰(即如果繼續使用已經失效的迭代器, 程序可能會崩潰)

  1. 會引起其底層空間改變的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、 push_back等
#include <iostream> 
using namespace std; 
#include <vector>
 
int main() 
{    
	vector<int> v{1,2,3,4,5,6};        
	auto it = v.begin();        
	// 將有效元素個數增加到100個,多出的位置使用8填充,操作期間底層會擴容    
	// v.resize(100, 8);        
	// reserve的作用就是改變擴容大小但不改變有效元素個數,操作期間可能會引起底層容量改變    
	// v.reserve(100);        
	// 插入元素期間,可能會引起擴容,而導致原空間被釋放    
	// v.insert(v.begin(), 0);
	// v.push_back(8);        
	// 給vector重新賦值,可能會引起底層容量改變 

出錯原因:
以上操作,都有可能會導致vector擴容,也就是說vector底層原理舊空間被釋放掉, 而在打印時,it還使用的是釋放之間的舊空間,在對it迭代器操作時,實際操作的是一塊已經被釋放的 空間,而引起代碼運行時崩潰。
解決方式:
在以上操作完成之後,如果想要繼續通過迭代器操作vector中的元素,只需給it重新 賦值即可。
2. 指定位置元素的刪除操作–erase

#include <iostream> 
using namespace std; 
#include <vector>
int main() 
{    
	int a[] = { 1, 2, 3, 4 };    
	vector<int> v(a, a + sizeof(a) / sizeof(int));
    // 使用find查找3所在位置的iterator    vector<int>::iterator pos = find(v.begin(), v.end(), 3);
    // 刪除pos位置的數據,導致pos迭代器失效。    
    v.erase(pos);    
    cout << *pos << endl; 
    // 此處會導致非法訪問    
    return 0;
}

出錯原因:erase刪除pos位置元素後,pos位置之後的元素會往前搬移,沒有導致底層空間的改變,理論上講迭代 器不應該會失效,但是:如果pos剛好是最後一個元素,刪完之後pos剛好是end的位置,而end位置是 沒有元素的,那麼pos就失效了。因此刪除vector中任意位置上元素時,vs就認爲該位置迭代器失效 了。
解決方法:
在使用前,對迭代器重新賦值即可。

while (it != v.end())    
{              
	it = v.erase(it);//重新獲取it                
	 ++it;    
}
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章