STL(vector容器)

3.2 vector容器

3.2.1 vector容器基本概念

vector的數據安排以及操作方式,與array非常相似,兩者的唯一差別在於空間的運用的靈活性。Array是靜態空間,一旦配置了就不能改變,要換大一點或者小一點的空間,可以,一切瑣碎得由自己來,首先配置一塊新的空間,然後將舊空間的數據搬往新空間,再釋放原來的空間。Vector是動態空間,隨着元素的加入,它的內部機制會自動擴充空間以容納新元素。因此vector的運用對於內存的合理利用與運用的靈活性有很大的幫助,我們再也不必害怕空間不足而一開始就要求一個大塊頭的array了。

Vector的實現技術,關鍵在於其對大小的控制以及重新配置時的數據移動效率,一旦vector舊空間滿了,如果客戶每新增一個元素,vector內部只是擴充一個元素的空間,實爲不智,因爲所謂的擴充空間(不論多大),一如剛所說,是”配置新空間-數據移動-釋放舊空間”的大工程,時間成本很高,應該加入某種未雨綢繆的考慮,稍後我們便可以看到vector的空間配置策略。

 

3.2.2 vector迭代器

Vector維護一個線性空間,所以不論元素的型別如何,普通指針都可以作爲vector的迭代器,因爲vector迭代器所需要的操作行爲,如operaroe*, operator->, operator++, operator--, operator+, operator-, operator+=, operator-=, 普通指針天生具備。Vector支持隨機存取,而普通指針正有着這樣的能力。所以vector提供的是隨機訪問迭代器(Random Access Iterators).

根據上述描述,如果我們寫如下的代碼:

Vector<int>::iterator it1;

Vector<Teacher>::iterator it2;

it1的型別其實就是Int*,it2的型別其實就是Teacher*.

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>

#include<vector>

using namespace std;

 

int main(){

 

    vector<int> v;

    for (int i = 0; i < 10;i ++){

        v.push_back(i);

        cout << v.capacity() << endl;  // v.capacity()容器的容量

    }

 

 

    system("pause");

    return EXIT_SUCCESS;

}

 

3.2.3 vector的數據結構

Vector所採用的數據結構非常簡單,線性連續空間,它以兩個迭代器_Myfirst和_Mylast分別指向配置得來的連續空間中目前已被使用的範圍,並以迭代器_Myend指向整塊連續內存空間的尾端。

爲了降低空間配置時的速度成本,vector實際配置的大小可能比客戶端需求大一些,以備將來可能的擴充,這邊是容量的概念。換句話說,一個vector的容量永遠大於或等於其大小,一旦容量等於大小,便是滿載,下次再有新增元素,整個vector容器就得另覓居所。

 

注意:

   所謂動態增加大小,並不是在原空間之後續接新空間(因爲無法保證原空間之後尚有可配置的空間),而是一塊更大的內存空間,然後將原數據拷貝新空間,並釋放原空間。因此,對vector的任何操作,一旦引起空間的重新配置,指向原vector的所有迭代器就都失效了。這是程序員容易犯的一個錯誤,務必小心。

 

3.2.4 vector常用API操作

3.2.4.1 vector構造函數

vector<T> v; //採用模板實現類實現,默認構造函數

vector(v.begin(), v.end());//將v[begin(), end())區間中的元素拷貝給本身。

vector(n, elem);//構造函數將n個elem拷貝給本身。

vector(const vector &vec);//拷貝構造函數。

 

//例子 使用第二個構造函數 我們可以...

int arr[] = {2,3,4,1,9};

vector<int> v1(arr, arr + sizeof(arr) / sizeof(int));

 

3.2.4.2 vector常用賦值操作

assign(beg, end);//將[beg, end)區間中的數據拷貝賦值給本身。

assign(n, elem);//將n個elem拷貝賦值給本身。

vector& operator=(const vector  &vec);//重載等號操作符

swap(vec);// 將vec與本身的元素互換。

 

3.2.4.3 vector大小操作

size();//返回容器中元素的個數

empty();//判斷容器是否爲空

resize(int num);//重新指定容器的長度爲num,若容器變長,則以默認值填充新位置。如果容器變短,則末尾超出容器長度的元素被刪除。

resize(int num, elem);//重新指定容器的長度爲num,若容器變長,則以elem值填充新位置。如果容器變短,則末尾超出容器長>度的元素被刪除。

capacity();//容器的容量

reserve(int len);//容器預留len個元素長度,預留位置不初始化,元素不可訪問。

 

3.2.4.4 vector數據存取操作

at(int idx); //返回索引idx所指的數據,如果idx越界,拋出out_of_range異常。

operator[];//返回索引idx所指的數據,越界時,運行直接報錯

front();//返回容器中第一個數據元素

back();//返回容器中最後一個數據元素

 

3.2.4.5 vector插入和刪除操作

insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count個元素ele.

push_back(ele); //尾部插入元素ele

pop_back();//刪除最後一個元素

erase(const_iterator start, const_iterator end);//刪除迭代器從start到end之間的元素

erase(const_iterator pos);//刪除迭代器指向的元素

clear();//刪除容器中所有元素

 

 

3.2.5 vector小案例

3.2.5.1巧用swap,收縮內存空間

 

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>

#include<vector>

using namespace std;

 

int main(){

 

    vector<int> v;

    for (int i = 0; i < 100000;i ++){

        v.push_back(i);

    }

 

    cout << "capacity:" << v.capacity() << endl;

    cout << "size:" << v.size() << endl;

 

    //此時 通過resize改變容器大小

    v.resize(10);

 

    cout << "capacity:" << v.capacity() << endl;

    cout << "size:" << v.size() << endl;

 

    //容量沒有改變

    vector<int>(v).swap(v);

 

    cout << "capacity:" << v.capacity() << endl;

    cout << "size:" << v.size() << endl;

 

 

    system("pause");

    return EXIT_SUCCESS;

}

 

 

3.2.5.2 reserve預留空間

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>

#include<vector>

using namespace std;

 

int main(){

 

    vector<int> v;

 

    //預先開闢空間

    v.reserve(100000);

 

    int* pStart = NULL;

    int count = 0;

    for (int i = 0; i < 100000;i ++){

        v.push_back(i);

        if (pStart != &v[0]){

            pStart = &v[0];

            count++;

        }

    }

 

    cout << "count:" << count << endl;

 

    system("pause");

    return EXIT_SUCCESS;

}

 

    
03 vector 容器  單端數組,動態數組
    構造 賦值
    大小 size  重置大小 resize 容量 capacity
    是否爲空empty  交換數據 swap 兩個容器之間進行
    巧用swap收縮空間
    reserve預留空間
    insert插入 erase刪除(迭代器) clear()清空
    pop_back() 尾刪  front()第一個數據  back()最後一個數據
    逆序遍歷 recerse_iterator rbegin rend
    如何區分迭代器是否支持隨機訪問:
    在迭代器上加一個值,不報錯就支持隨機訪問,否則不支持


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

void test01(){

	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
		cout << v.capacity() << endl; 
		//v.capacity()容器的容量
		//動態數組按2倍方式擴容
		//vector內部有自己的算法 別人問 不知道就可以,內部有一套策略
		
	}

	/*
	   所謂動態增加大小,並不是在原空間之後續接新空間(因爲無法保證原
	   空間之後尚有可配置的空間),而是一塊更大的內存空間,
	   然後將原數據拷貝新空間,並釋放原空間。因此,
	   對vector的任何操作,一旦引起空間的重新配置,
	   指向原vector的所有迭代器就都失效了。
	   這是程序員容易犯的一個錯誤,務必小心。
	
	*/


}
/*
1 vector構造函數
vector<T> v; //採用模板實現類實現,默認構造函數
vector(v.begin(), v.end());//將v[begin(), end())區間中的元素拷貝給本身。
vector(n, elem);//構造函數將n個elem拷貝給本身。
vector(const vector &vec);//拷貝構造函數。

//例子 使用第二個構造函數 我們可以...
int arr[] = {2,3,4,1,9};
vector<int> v1(arr, arr + sizeof(arr) / sizeof(int));

2 vector常用賦值操作
assign(beg, end);//將[beg, end)區間中的數據拷貝賦值給本身。
assign(n, elem);//將n個elem拷貝賦值給本身。
vector& operator=(const vector  &vec);//重載等號操作符
swap(vec);// 將vec與本身的元素互換。

3 vector大小操作
size();//返回容器中元素的個數
empty();//判斷容器是否爲空
resize(int num);//重新指定容器的長度爲num,若容器變長,則以默認值填充新位置。如果容器變短,則末尾超出容器長度的元素被刪除。
resize(int num, elem);//重新指定容器的長度爲num,若容器變長,則以elem值填充新位置。如果容器變短,則末尾超出容器長>度的元素被刪除。
capacity();//容器的容量
reserve(int len);//容器預留len個元素長度,預留位置不初始化,元素不可訪問。




*/

void printVector(vector<int> &v) {
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}


void test02() {
	vector<int> v;
	int arr[] = { 2,3,4,1,9 };
	vector<int> v1(arr, arr + sizeof(arr) / sizeof(int));//數組名相當於begin  後邊那個相當於end
	vector<int>v2(v1.begin(), v1.end());

	printVector(v2);
	vector<int>v3(10, 100);//10個100
	printVector(v3);


	//賦值使用
	vector<int>v4;
	v4.assign(v3.begin(), v3.end());
	printVector(v4);

	v4.swap(v2);
	cout << "交換後的v2" << endl;
	printVector(v4);

	//size()統計元素個數
	cout << "v4容器的大小:  " << v4.size() << endl;//5

	if (v4.empty()) {
		cout << "v4空" << endl;

	}
	else {
		cout << "v4不空!" << endl;
	}
	//if(v4.size()==0) 也是空的
    //v4  2 3 4 1 9
	v4.resize(7);//重新制定大小爲10

	printVector(v4);//默認補充0,填充

	v4.resize(10, -1);//第二個參數是默認值,默認是0,否則根據用戶的條件填充

	printVector(v4);

	v4.resize(3);//刪除後續的
	printVector(v4);

	//reserve提前開闢好空間   元素不可訪問

}

//小技巧
void test03() {
	vector<int> v;
	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
	}
	cout << "v的容量" << v.capacity() << endl;//大於100000
	cout << "v的大小" << v.size() << endl;//100000

	v.resize(3);
	cout << "v的容量" << v.capacity() << endl;//大於100000
	cout << "v的大小" << v.size() << endl;//3

	//巧用swap()
	vector<int>(v).swap(v);
	cout << "v的容量" << v.capacity() << endl;//大於100000
	cout << "v的大小" << v.size() << endl;//3
	//vector<int>(v) 利用v初始化匿名對象  swap交換指針
	//忽然想起 Qt中的qDebug()也是匿名對象,自動回收

}
//reserve(int len);//容器預留len個元素長度,預留位置不初始化,元素不可訪問。

void test04() {
	vector<int> v;
	int* p = NULL;
	int num = 0;
	v.reserve(100000);
	//知道數據量是多少,預留出空間,提高效率,不預留 開闢30次空間



	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
		if (p != &v[0]) {
			p = &v[0];
			num++;
		}
	}
	cout << num << endl;
	//開闢100000個數據用來多少次,開闢了多少次空間

}
/*
4 vector數據存取操作
at(int idx); //返回索引idx所指的數據,如果idx越界,拋出out_of_range異常。
operator[];//返回索引idx所指的數據,越界時,運行直接報錯
front();//返回容器中第一個數據元素
back();//返回容器中最後一個數據元素

5 vector插入和刪除操作
insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count個元素ele.
push_back(ele); //尾部插入元素ele
pop_back();//刪除最後一個元素
erase(const_iterator start, const_iterator end);//刪除迭代器從start到end之間的元素
erase(const_iterator pos);//刪除迭代器指向的元素
clear();//刪除容器中所有元素
*/

void test05() {
	vector<int>v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	cout << "v的front " << v.front() << endl;
	cout << "v的back " << v.back() << endl;
	//找極值 排序,取收尾的操作很方便

	//插入操作
	v.insert(v.begin(), 2,100);//參數一是迭代器,參數二是 有幾個插入的數  參數3是具體插入的內容
	printVector(v);

	//刪除操作
	v.pop_back();//刪了一個元素(尾刪)
	printVector(v);

	v.erase(v.begin());
	printVector(v);

	//刪除所有元素
	//v.erase(v.begin(), v.end());
	v.clear();//清空所有的數據
	if (v.empty()) {
		cout << "爲空" << endl;
	}

}

void test06() {
	//逆序遍歷
	vector<int>v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
	}

	printVector(v);

	//逆序的迭代器
	for (vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); it++) {
		cout << *it << " ";
	}
	cout << endl;
	//vector 迭代器是隨機訪問的迭代器,支持跳躍式訪問
	vector<int>::iterator itBegin = v.begin();
	itBegin =itBegin+3;
	//如果上述寫法不報錯,這個迭代器可以支持隨機訪問迭代器
	

	list<int>l;
	for (int i = 0; i < 10; i++) {
		l.push_back(i);
	}
	//list<int>::iterator lIt = l.begin();
	//lIt = lIt + 1;//報錯,不支持隨機訪問

}





int main() {

	//test01();
	//test02();
	//test03();
	//test04();
  //test05();
	test06();
	return 0;
}


















(本筆記內容整理自網絡資源,侵刪)

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