欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ vector的基本使用示例詳解

 更新時間:2023年03月07日 09:39:12   作者:rygttm  
這篇文章主要介紹了C++ vector的基本使用,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、vector和string的聯(lián)系與不同

1.
vector底層也是用動態(tài)順序表實現(xiàn)的,和string是一樣的,但是string默認存儲的就是字符串,而vector的功能較為強大一些,vector不僅能存字符,理論上所有的內(nèi)置類型和自定義類型都能存,vector的內(nèi)容可以是一個自定義類型的對象,也可以是一個內(nèi)置類型的變量。

2.
vector在使用時需要進行類模板的實例化,因為傳遞的模板參數(shù)不同,則vector存儲的元素類型就會有變化,所以在使用vector的時候要進行類模板的顯式實例化。
類模板的第二個參數(shù)是空間配置器,這個學到后面再說,而且這個參數(shù)是有缺省值的,我們只用這個缺省值就歐克了,所以在使用vector時,只需要關(guān)注第一個參數(shù)即可。

在這里插入圖片描述

void test_vector1()
{
	string s;
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	//string和vector底層都是用數(shù)組實現(xiàn)的,所以他們都支持迭代器、范圍for、下標+[]的遍歷方式
	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";//string和vector的底層都是數(shù)組,所以可以使用[],但list就不能使用[]了,所以萬能的方法是迭代器。
	}
	cout << endl;

	vector<int>::iterator it = v.begin();//iterator實際是某種類型的重定義,在使用時要指定好類域。
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	for (auto e : v)//不就是迭代器嗎?
	{
		cout << e << " ";
	}
	cout << endl;

	cout << v.max_size() << endl;//int是10億多,因為int占4個字節(jié),42億÷4。
	cout << s.max_size() << endl;//max_size的大小是數(shù)據(jù)的個數(shù),我的編譯器的char是21億多。不用管他,這接口沒價值。

	//vector<char> vstr;
	//string str;
	//vector<char>不能替代string,即使兩者都是字符數(shù)組也不行,因為string有\(zhòng)0
}

二、vector的擴容操作

1.resize() (缺省值為匿名對象)&& reserve()

1.
對于string和vector,reserve和resize是獨有的,因為他們的底層都是動態(tài)順序表實現(xiàn)的,list就沒有reserve和resize,因為他底層是鏈表嘛。

2.
對于reserve這個函數(shù)來說,官方并沒有將其設(shè)定為能夠兼容實現(xiàn)縮容的功能,明確規(guī)定這個函數(shù)在其他情況下,例如預留空間要比當前小的情況下,這個函數(shù)的調(diào)用是不會引起空間的重新分配的,也就是說容器vector的capacity是不會被影響的。

在這里插入圖片描述

3.
有的人可能認為縮容只要丟棄剩余的空間就好了,但其實沒有那么簡單,你從C語言階段free空間不能分兩次free進行釋放就可以看出來,一塊已經(jīng)申請好的空間就是一塊兒獨立的個體,不能說你保留空間的一部分丟棄剩余的一部分,這樣是不行的,本質(zhì)上和操作系統(tǒng)的內(nèi)存管理有關(guān)系,如果對這部分知識有興趣,可以下去研究一下。

4.
但值得注意的是縮容表面看起來是降低了空間的使用率,想要提高程序的效率,但實際上并未提高效率,縮容是需要異地縮容的,需要重新開空間和拷貝數(shù)據(jù),代價不小,所以平常不建議對空間進行縮容。

在這里插入圖片描述

5.
vector的resize和string的resize同樣具有三種情況,但vector明顯功能比string要更健壯一些,string類型只能針對于字符,而vector在使用resize進行初始化空間數(shù)據(jù)時,對內(nèi)置類型和自定義類型均可以調(diào)用對應的拷貝構(gòu)造來初始化,所以其功能更為健壯,默認將整型類型初始化為0,指針類型初始化為空指針。

在這里插入圖片描述

void test_vector2()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	//resize和reserve對于vector和string是獨有的,對于list而言,就沒有reserve和resize

	cout << v.capacity() << endl;
	v.reserve(10);
	cout << v.capacity() << endl;
	v.reserve(4);
	cout << v.capacity() << endl;//并不會縮容,縮容并不會提高效率,縮容是有代價的,某種程度上就是以空間換時間。

	v.resize(8);//int、指針這些內(nèi)置類型的默認構(gòu)造就把他們初始化為0和空指針這些。
	v.resize(15, 1);
	v.resize(3);//不縮容,也是采用惰性刪除的方式,將size調(diào)整為3就可以了,顯示數(shù)組內(nèi)容的時候按照size大小顯示就可以了。
}

2.reserve在g++和vs上的擴容機制

1.
在vs上擴容機制采用1.5倍的大小,g++上采用2倍的大小,對于空間的擴容,如果開大了會造成空間浪費,開小了不夠用,又會導致頻繁擴容帶來性能的損耗,而2倍的大小可以說是剛剛好,至于微軟的工程師為什么選擇1.5來進行擴容,是由于內(nèi)存的某種對其因素導致。

void test_vector_expand()//擴容機制大概是1.5倍進行擴容
{
	size_t sz;
	vector<int> v;

	//v.reserve(100);//已知開辟空間大小時,我們應該調(diào)用reserve來提前預留空間,進行擴容。

	sz = v.capacity();
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

3.reserve異地擴容和shrink_to_fit異地縮容的設(shè)計理念

1.
對于reserve的設(shè)計理念就是不去縮容,就算手動調(diào)用reserve進行縮容,編譯器也不會理你,空間的大小始終都不會變,capacity的值一直是不動的,這樣的設(shè)計理念本質(zhì)上就是用空間來換時間,因為異地縮容需要開空間和拷貝數(shù)據(jù),比較浪費時間。

2.
相反shrink_to_fit就是縮容函數(shù),強制性的將capacity的大小降低到適配size大小的值,它的設(shè)計理念就是以空間來換時間,但日常人們所使用的手機或者PC空間實際上是足夠的,不夠的是時間,所以這種函數(shù)還是不要使用的為好,除非說你后面肯定不會插入數(shù)據(jù)了,不再進行任何modify操作,那你可以試著將空間還給操作系統(tǒng),減少空間的使用率。

void test_vector7()
{
	vector<int> v;
	v.reserve(10);
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	
	//C++不會太推薦使用malloc來進行空間的初始化了,因為很有可能存在自定義類型對象沒有初始化的問題,如果用new會自動調(diào)用構(gòu)造。

	//設(shè)計理念就是不去縮容,因為異地縮容的代價很大,所以就算你用reserve或是resize調(diào)整大小以改變capacity,但編譯器不會管你。
	// 因為它的設(shè)計理念不允許它這么做,而遇到shrink_to_fit就沒轍了,因為他是縮容函數(shù)?。?!
	//---不動空間,不去縮容,以空間換時間的設(shè)計理念,因為縮容雖然空間資源多了,但是時間就長了,為了提高時間,就用空間換。
	//shrink_to_fit就是反面的函數(shù),進行了縮容。
	v.reserve(3);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//設(shè)計理念:以時間換空間,一般縮容都是異地縮容,代價不小,一般不要輕易使用。通常情況下,我們是不缺空間的,缺的是時間。
	v.shrink_to_fit();//縮容函數(shù),代價很大,通常的縮容的方式,就是找一塊新的較小的空間,然后將原有數(shù)據(jù)拷貝進去
	

	v.resize(3);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.clear();//clear都是不動空間的
}

4.vector和malloc分別實現(xiàn)動態(tài)開辟的二維數(shù)組

楊輝三角

1.
對于C語言實現(xiàn)的話,需要一個返回值和兩個輸出型參數(shù)來返回到后臺接口里面,第一個參數(shù)代表二維數(shù)組的大小,這道題我們知道返回的二維數(shù)組的大小,但其他題是有可能不知道的,而leetcode的后臺測試用例是統(tǒng)一設(shè)計的,為了兼容其他不知道返回數(shù)組大小的題目,這里統(tǒng)一使用了輸出型參數(shù)來控制。第二個參數(shù)的原因也是如此。

2.
二維數(shù)組、二維數(shù)組里面的元素、需要返回二維數(shù)組里面的一維數(shù)組的元素個數(shù),這些數(shù)組都需要malloc出來。

//后臺實現(xiàn)的地方:int returnSize=0;int returnColumnSizes[];
//grenerate(num,&returnSize,&returnColumnSizes);//函數(shù)調(diào)用
int** generate(int numRows, int* returnSize, int** returnColumnSizes) 
{
    int** p = (int**)malloc(numRows * sizeof(int*));
    *returnSize = numRows;
    *returnColumnSizes = (int*)malloc(sizeof(int) * numRows);
    for (int i = 0; i < numRows; i++)
    {
        p[i] = (int*)malloc(sizeof(int) * (i + 1));//給每一個二維數(shù)組的元素動態(tài)開辟一個空間
        (*returnColumnSizes)[i] = i + 1;
        p[i][0] = p[i][i] = 1;
        //for(int j = i; j < i + 1; j++)//條件控制有問題
        //for (int j = 0; j < i + 1 ; j++)
        for (int j = 1; j < i ; j++)
        {
            if (p[i][j]!=1)
            {
                p[i][j]=p[i-1][j-1]+p[i-1][j];
            }
        }
    }
    return p;
}

3.
對于vector來講的話,動態(tài)開辟就不需要我們自己做,通過resize就可以控制容器的空間大小,不用malloc動態(tài)開辟了,所以對于動態(tài)開辟的二維數(shù)組來講,vector實際上要簡便許多。

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> vv;
        vv.resize(numRows);
        //第二個參數(shù)不傳就是匿名對象,會自動調(diào)用容器中元素的構(gòu)造函數(shù)。內(nèi)置類型或自定義類型的構(gòu)造。
        for(size_t i=0; i<vv.size(); i++)
        {
            vv[i].resize(i+1, 0);//給每一個vector<int>容器預留好空間并進行初始化
            vv[i][0] = vv[i][vv[i].size() - 1] = 1;
        }
        for(int i=0; i<vv.size(); i++)
        {
            for(int j=0; j<vv[i].size(); j++)
            {
                if(vv[i][j]==0)
                {
                    vv[i][j]=vv[i-1][j]+vv[i-1][j-1];
                }
            }
        }
        return vv;

    }
};

三、vector的元素訪問操作

1.operator[]和at對于越界訪問的檢查機制(一段經(jīng)典的代碼錯誤)

1.
下面所展示的代碼是比較經(jīng)典的錯誤,就是我們用reserve擴容之后,就利用[]和下標來進行容器元素的訪問,擴容之后空間的使用權(quán)確實屬于我們,但是operator[]的越界訪問檢查機制,導致了我們程序的崩潰,assert(pos<size),所以對于元素的訪問,是要用resize來進行size的調(diào)整的,而reserve的主要作用是用來提前預留空間,在空間不夠使用的情況下進行調(diào)用,所以這里使用的情景有些不搭。

在這里插入圖片描述

2.
對于at的使用,所采用的越界訪問檢查機制是拋異常,catch捕獲異常之后,我們可以將異常信息打印出來,可以看到異常信息是無效的vector下標,指的也是所傳下標是無用的,實際就是下標位置超過了size。

在這里插入圖片描述

void test_vector4()
{
	vector<int> v;
	v.reserve(10);
	//這是一段經(jīng)典的錯誤代碼。reserve改變的是capacity主要解決的是插入數(shù)據(jù)時涉及到的擴容問題。
	//resize改變的是size,平常對于vector的容量增加,還是resize多一點,resize可以直接包攬reserve的活,并且除此之外還能初始化空間。
	for (size_t i = 0; i < 10; i++)
	{
		//v[i] = i;
		//對于[]的使用實際會有一個assert的越界斷言的檢查。assert(i<v.size()),你的下標不能超過size。
		//雖然reserve的確把空間開辟好了,你也能用這個空間,但是[]他有size和下標的越界檢查,所以你的程序就會報錯。
		//reserve=開空間+初始化(有默認值)
		v.at(i) = i;//拋異常

		//斷言報錯真正的問題是在于,release版本下面,斷言就失效了,斷言在release版本下面是不起作用的。
	}
}
int main()
{
	//test_vector1();
	//test_vector2();
	//test_vector_expand();
	try
	{
		//test_vector6();
	}
	catch (const exception& e)
	{//在這個地方捕獲異常然后進行打印
		cout << e.what() << endl;//報錯valid vector subscript,無效的vector下標
	}
	//test_vector4();
	//test_vector5();
	//test_vector6();
	test_vector7();

	//string算是STL的啟蒙,string的源碼我們就不看了
	return 0;
}

四、vector的修改操作

1.assign和迭代器的配合使用

1.
assign有兩種使用方式,一種是用n個value來進行容器元素的覆蓋,一種是用迭代器區(qū)間的元素來進行容器元素的覆蓋,這里的迭代器采用模板形式,因為迭代器類型不僅僅可能是vector類型,也有可能是其他容器類型,所以這里采用模板泛型的方式。

在這里插入圖片描述

2.
而且迭代器使用起來實際是非常方便的,由于vector的底層是連續(xù)的順序表,所以我們可以通過指針±整數(shù)的方式來控制迭代器賦值的區(qū)間,所以采用迭代器作為參數(shù)是非常靈活的。

void test_vector5()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);

	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	//void assign(size_type n, const value_type & val);前后類型分別為size_t和模板參數(shù)T的類型typedef,那就是int類型
	v.assign(10, 1);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	
	vector<int> v1;
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	//template <class InputIterator> void assign(InputIterator first, InputIterator last);
	v.assign(v1.begin(), v1.end());
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	string str("hello world");
	v.assign(str.begin(), str.end());//assign里面的迭代器類型是不確定的,既有可能是他自己的iterator也有可能是其他容器的迭代器類型。
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	v.assign(++str.begin(), --str.end());//你可以控制迭代器的區(qū)間,指定assign的容器元素內(nèi)容的長度。
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

}

2.insert和find的配合使用

1.
對于順序表這種結(jié)構(gòu)來說,頭插和頭刪的效率是非常低的,所以vector只提供了push_back和pop_back,而難免遇到頭插和頭刪的情況時,可以偶爾使用insert和erase來進行頭插和頭刪,并且insert和erase的參數(shù)都使用了迭代器類型作為參數(shù),因為迭代器更具有普適性。

2.
如果要在vector的某個位置進行插入時,肯定是需要使用find接口的,但其實vector的默認成員函數(shù)并沒有find接口,這是為什么呢?因為大多數(shù)的容器都會用到查找接口,也就是find,所以C++直接將這個接口放到算法庫里面去了,實現(xiàn)一個函數(shù)模板,這個函數(shù)的實現(xiàn)實際也比較簡單,只要遍歷一遍迭代器然后返回對應位置的迭代器即可,所以這個函數(shù)不單獨作為某個類的成員函數(shù),而是直接放到了算法庫里面去。

在這里插入圖片描述

void test_vector6()//測試insert和find
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);

	v.insert(v.begin(), 4);
	v.insert(v.begin() + 2, 4);
	//vector的迭代器能夠直接+2,源自于vector的底層是連續(xù)的空間,迭代器也就是連續(xù)的,而list的底層不是連續(xù)空間,而是一個個的節(jié)點,
	//所以迭代器就不能++來進行使用了

	//如果要在vector里面的數(shù)字3位置插入一個元素的話:std::find,find的實現(xiàn)就是遍歷一遍迭代器,找到了就返回對應位置的迭代器。
	//而vector、list、deque等容器都會用到find,所以find直接實現(xiàn)一個模板即可。
	vector<int>::iterator it = std::find(v.begin(), v.end(), 3);
	//string沒有實現(xiàn)find的原因是string不僅僅要找某一個字符,而且還要找一個字串,所以算法庫的find就不怎么適用,string就自己造輪子
	v.insert(it, 30);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

3.類外、類內(nèi)、算法庫的3個swap

1.
vector類內(nèi)的swap用于兩個對象的交換,在swap實現(xiàn)里面再調(diào)用std的swap進行內(nèi)置類型的交換,但C++用心良苦,如果你不小心使用的格式是std里面的swap格式的話,也沒有關(guān)系,因為類外面有一個匹配vector的swap,所以會優(yōu)先調(diào)用類外的swap,C++極力不想讓你調(diào)用算法庫的swap,就是因為如果交換的類型是自定義類型的情況下,算法庫的swap會進行三次深拷貝,代價極大,所以為了極力防止你調(diào)用算法庫的swap,C++不僅在類內(nèi)定義了swap,在類外也定義了已經(jīng)實例化好的swap,調(diào)用時會優(yōu)先調(diào)用最匹配的swap。

void test_vector8()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	vector<int> v1;
	v1.swap(v);
	swap(v1, v);//一不小心這樣用呢?那也不會去調(diào)用算法庫里面的三次深拷貝的swap
	//這里會優(yōu)先匹配vector的類外成員函數(shù),既然有vector作為類型實例化出來的swap函數(shù)模板,就沒有必要調(diào)用算法庫里面的模板進行實例化
	//template <class T, class Alloc>
	//void swap(vector<T, Alloc>&x, vector<T, Alloc>&y);
}

五、看源碼時需要注意的問題

1.
看源碼框架的方法:將類成員變量先抽出來,看一看成員函數(shù)的聲明具體都實現(xiàn)了什么功能,如果想要看實現(xiàn),那就去.c文件抽出來具體函數(shù)去看

2.
看某些書籍時的道理和看源碼是一樣的,要進行抽絲剝繭,不要想著第一遍就把看到的所有東西都弄回,如果你覺得這本書或源碼非常不錯,你可以多次反復的去看,要循序漸進的去學,一段時間之后,你的知識儲備上來之后,可能再去看書籍或者源碼又有新的不同的感受,所以不要想著一遍就把所有的東西都搞明白,第一遍弄懂個70%-80%就很不錯,如果你想學扎實一點,那就增加遍數(shù)。

到此這篇關(guān)于C++ vector的基本使用的文章就介紹到這了,更多相關(guān)C++ vector使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言之格式化屏幕輸出詳解

    C語言之格式化屏幕輸出詳解

    這篇文章主要介紹了C語言之格式化屏幕輸出的相關(guān)資料,需要的朋友可以參考下,小編覺得這篇文章寫的還不錯,希望能夠給你帶來幫助
    2021-11-11
  • C++實現(xiàn):螺旋矩陣的實例代碼

    C++實現(xiàn):螺旋矩陣的實例代碼

    螺旋矩陣是指一個呈螺旋狀的矩陣,它的數(shù)字由第一行開 始到右邊不斷變大,向下變大, 向左變大,向上變大,如此循環(huán)。
    2013-03-03
  • 使用VS2022開發(fā)在線遠程編譯部署的C++程序(圖文詳解)

    使用VS2022開發(fā)在線遠程編譯部署的C++程序(圖文詳解)

    這篇文章主要介紹了使用VS2022開發(fā)可以在線遠程編譯部署的C++程序,本文分步驟通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • c++中處理相關(guān)數(shù)學函數(shù)

    c++中處理相關(guān)數(shù)學函數(shù)

    數(shù)學庫函數(shù)聲明在 math.h 中,主要有:
    2013-04-04
  • Qt5.9實現(xiàn)簡單復合圖形

    Qt5.9實現(xiàn)簡單復合圖形

    這篇文章主要為大家詳細介紹了Qt5.9實現(xiàn)簡單復合圖形,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • C++并查集親戚(Relations)算法實例

    C++并查集親戚(Relations)算法實例

    這篇文章主要介紹了C++并查集親戚(Relations)算法,實例分析了并查集親戚算法的原理與實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • C語言堆棧入門指南

    C語言堆棧入門指南

    我身邊的一些編程的朋友以及在網(wǎng)上看帖遇到的朋友中有好多也說不清堆棧,所以我想有必要給大家分享一下我對堆棧的看法,有說的不對的地方請朋友們不吝賜教,這對于大家學習會有很大幫助
    2014-01-01
  • Unreal學習之簡單三角形的繪制詳解

    Unreal學習之簡單三角形的繪制詳解

    之所以寫這個繪制簡單三角形的實例其實是想知道如何在Unreal中通過代碼繪制自定義Mesh,如果你會繪制一個三角形,那么自然就會繪制復雜的Mesh了。所以這是很多圖形工作者的第一課,快跟隨小編一起學習起來吧
    2023-02-02
  • 深入淺析C/C++?的條件編譯

    深入淺析C/C++?的條件編譯

    條件編譯是指預處理的時候根據(jù)條件編譯的指令有條件的選擇源程序中的一部分代碼送給編譯器進行編譯,進行有選擇性的操作,防止宏替換的內(nèi)容重復包含,這篇文章主要介紹了C/C++?的條件編譯,需要的朋友可以參考下
    2022-04-04
  • 簡要解讀C++的動態(tài)和靜態(tài)關(guān)聯(lián)以及虛析構(gòu)函數(shù)

    簡要解讀C++的動態(tài)和靜態(tài)關(guān)聯(lián)以及虛析構(gòu)函數(shù)

    這篇文章主要介紹了簡要解讀C++的動態(tài)和靜態(tài)關(guān)聯(lián)以及虛析構(gòu)函數(shù),析構(gòu)函數(shù)在C++編程中平時并不是太常用,需要的朋友可以參考下
    2015-09-09

最新評論