面試官總喜歡問的幾個C++容器,你掌握了幾個?

零、前言

C++面試中經常會被問到容器的使用,面試官會從它們的使用場景、效率、使用方法、各個容器之間的區別等多方面進行考察,C++中的容器都是使用模板封裝的,底層設計又設計到算法的使用,從容器的使用問起,能夠迅速擴展開話題,並能夠試探出應聘者的水平到底有多深!

剛參加工作的面試者,可能只需要掌握怎麼使用就行了,有一定工作經驗的不僅要掌握怎麼使用,還要掌握容器的區別和實現原理,更要掌握它們的使用場景,根據它們的各自特點,讓它們在特定的場景中發揮自己的長處!

一、vector

1、vector概述

vector屬於序列式容器,實現了對數組的封裝,因此它的內存空間也是連續存儲的, 支持下標訪問,可以通過[]和at()來進行隨機訪問vector中的元素,由於空間是連續存儲的,vector的訪問速度極快;但是對插入支持不是很友好,在尾部插入速度很快,在頭部插入元素速度很慢,需要移動所有的數據。

2、vector優缺點

優點:
1)使用連續的存儲空間,訪問速度快。
2) 支持隨機訪問,可以通過[ ]操作符和at()方法訪問數據。
3)可以不指定內存大小即可實現對像數組一樣的操作,實際內部實現vector是預先分配了一塊固定大小的內存,當超過該內存塊時,vector會重新找一塊更大的內存,並把當前的釋放掉。
(之前寫過兩篇文章對vector內存進行過剖析,感興趣可以看看:
文章1:https://blog.csdn.net/toby54king/article/details/86737201,
文章2:https://blog.csdn.net/toby54king/article/details/88543270)
4)可以快速的在尾部進行插入和刪除,即通過push_back() 和pop_back()方法。

缺點:
1)vector內部進行插入刪除操作效率低。
2) 只能在vector的尾部進行push和pop。
3) 添加數據佔用內存超過vector預先分配的大小時,需要重新分配、拷貝與釋放。

3、vector代碼示例

// TestVector.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

// 打印函數
void MyPrintf(int &elem)
{
	cout << elem << ", ";
}

// 修改元素函數
void MyAdd(int &elem)
{
	elem = elem + 10;
}

int main()
{
	cout << "------------------------C++序列化容器vector的使用--------------------" << endl;
	// 1、增加元素
	cout << "-----------------------vector增加元素--------------------" << endl;
	vector<int> myVector;
	for (int i=0; i<10; i++)
	{
		//myVector.push_back(i);
		myVector.emplace_back(i); // C++11
	}
	for_each(myVector.begin(),myVector.end(), MyPrintf);
	cout << endl;

	// 2、排序元素
	cout << "-----------------------vector排序元素--------------------" << endl;
	sort(myVector.begin(), myVector.end(), greater<int>());
	for_each(myVector.begin(), myVector.end(), MyPrintf);
	cout << endl;

	// 3、修改元素
	cout << "-----------------------vector修改元素--------------------" << endl;
	for_each(myVector.begin(), myVector.end(), MyAdd);
	for_each(myVector.begin(), myVector.end(), MyPrintf);
	cout << endl;

	// 4、查找元素
	cout << "-----------------------vector查找元素--------------------" << endl;
	vector<int>::iterator index;
	index = find(myVector.begin(), myVector.end(), 10); // 查找元素10
	// 注意:元素的索引從0開始的
	cout << "元素10的索引index是: " << (index - myVector.begin()) << endl;
	index = find_if(myVector.begin(), myVector.end(), bind2nd(less<int>(),15));
	cout << "第一個小於15的元素索引index是: " << (index - myVector.begin()) << endl;

	// 5、刪除元素
	cout << "-----------------------vector刪除元素--------------------" << endl;
	while (!myVector.empty())
	{
		int backNum = myVector.back();
		cout << backNum << ", ";
		myVector.pop_back();
	}
	cout << endl;
	
    std::cout << "Hello World!\n";
	getchar();
}

運行結果:
在這裏插入圖片描述

二、list

1、list概述

list屬於序列式容器,實現了對雙向鏈表的封裝,因此它的內存空間是不連續的,不支持下標訪問,list對於隨機訪問速度慢,可能要遍歷整個鏈表纔行,但是插入速度很快,不需要拷貝和移動數據,只需要改變指針的指向就可以了。

2、list優缺點

優點:
1)不使用連續存儲空間來完成動態操作。
2)內部進行插入和刪除操作非常方便。
3)可以在兩端進行插入和刪除操作。
4])不需要預先分配內存空間。

缺點:
1)不能進行內部的隨機訪問,因爲不支持下標索引。
2)比verctor佔用內存多,因爲要存儲其前驅和後繼節點的信息。

3、list代碼示例

// Testlist.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include <iostream>
#include <list>
#include <algorithm>
#include <functional>

using namespace std;

// 打印函數
void MyPrintf(int &elem)
{
	cout << elem << ", ";
}

// 修改元素函數
void MyAdd(int &elem)
{
	elem = elem + 10;
}

int main()
{
	cout << "------------------------C++序列化容器list的使用--------------------" << endl;
	// 1、增加元素
	cout << "-----------------------list增加元素--------------------" << endl;
	list<int> myList;
	for (int i = 0; i < 10; i++)
	{
		//myList.push_back(i);
		myList.emplace_back(i); // C++11
	}
	for_each(myList.begin(), myList.end(), MyPrintf);
	cout << endl;

	// 2、排序元素
	cout << "-----------------------list排序元素--------------------" << endl;
	myList.sort(greater<int>());
	for_each(myList.begin(), myList.end(), MyPrintf);
	cout << endl;

	// 3、修改元素
	cout << "-----------------------list修改元素--------------------" << endl;
	for_each(myList.begin(), myList.end(), MyAdd);
	for_each(myList.begin(), myList.end(), MyPrintf);
	cout << endl;
	// list反序排列
	cout << "-----------------------list反序排列元素--------------------" << endl;
	myList.reverse();
	for_each(myList.begin(), myList.end(), MyPrintf);
	cout << endl;

	// 4、查找元素
	cout << "-----------------------list查找元素--------------------" << endl;
	list<int>::iterator index;
	index = find(myList.begin(), myList.end(), 10); // 查找元素10
	if (index != myList.end())
	{
		cout << "找到元素10了,刪除該元素" << endl;
		myList.remove(10);
	}
	for_each(myList.begin(), myList.end(), MyPrintf);
	cout << endl;
	index = find_if(myList.begin(), myList.end(), bind2nd(greater<int>(), 15));
	if (index != myList.end())
	{
		cout << "第一個大於15的元素找到了" << endl;
	}

	// 5、刪除元素
	cout << "-----------------------list刪除元素--------------------" << endl;
	myList.remove_if(bind2nd(equal_to<int>(), 15)); // 刪除等於15的元素
	cout << "-----------------------list刪除等於15的元素後--------------------" << endl;
	for_each(myList.begin(), myList.end(), MyPrintf);
	cout << endl;
	cout << "刪除所有的元素" << endl;
	while (!myList.empty())
	{
		int backNum = myList.back();
		cout << backNum << ", ";
		myList.pop_back();
	}
	cout << endl;

	std::cout << "Hello World!\n";
	getchar();
}

運行結果:
在這裏插入圖片描述

三、map

1、map概述

map是採用紅黑樹實現的key-value一對一映射的關聯容器,紅黑樹能夠自動對數據進行排序,因此map內部所有的數據都是有序的;作爲鍵值key的元素不允許重複,比較函數只對元素的鍵值進行比較,元素的各項數據可以通過鍵值進行查找、重新賦值等操作;可以使用鍵值key作爲下標來獲取對應的值;map默認的排序準則是從小到大。

2、map優缺點

優點:
1)map的數據結構採用紅黑樹自身是有序的,插入數據時會自動排序。
2)內部結構採用紅黑樹,紅黑樹的時間複雜度是在log(n),時間複雜度低,效率高。
3)索引方便,可以通過下標key方便的進行存取。

缺點:
1)map內部採用紅黑數實現,需要額外空間保存節點,會佔用多餘的空間,典型的以“空間換時間”。
2)通過key值索引時,如果key值不存在,map會直接插入一個key-value鍵值對。

3、map代碼示例

// Testmap.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

// 打印函數
void MyPrintf(pair<int, double> mpair)
{
	cout << "( " << mpair.first << "," << mpair.second << ") " << endl;
}

// 以value值進行排序
bool CompVector(pair<int, double> mpair1, pair<int, double> mpair2)
{
	return mpair1.second > mpair2.second;
}

int main()
{
	cout << "------------------------C++關聯容器map的使用--------------------" << endl;
	// 1、增加元素
	cout << "-----------------------map增加元素--------------------" << endl;
	map<int, double> myMap;
	for (int i = 0; i < 10; i++)
	{
		double fNum = i + 0.5;
		myMap.insert(pair<int, double>(i,fNum));
	}
	for_each(myMap.begin(), myMap.end(), MyPrintf);
	cout << endl;


	// 2、排序元素
	cout << "------map排序元素,map沒有提供直接排序的函數,需要藉助vector排序-------" << endl;
	vector<pair<int, double> >mapVector(myMap.begin(), myMap.end());
	sort(mapVector.begin(), mapVector.end(), CompVector);
	for_each(mapVector.begin(), mapVector.end(), MyPrintf);
	cout << endl;

	// 3、修改元素
	cout << "-----------------------map修改元素--------------------" << endl;
	for (int i = 0; i < 10; i++)
	{
		double fNum = i + 10.1;
		myMap[i]=fNum;
	}
	for_each(myMap.begin(), myMap.end(), MyPrintf);
	cout << endl;

	// 4、查找元素
	cout << "-----------------------map查找元素--------------------" << endl;
	map<int,double>::iterator iterFind;
	iterFind = myMap.find(1); // key值爲1的元素
	if (iterFind != myMap.end())
	{
		cout << "找到了key值爲1的元素: " << iterFind->second << endl;;
	}
	
	// 隨機查找元素功能的函數lower_bound和upper_bound
	iterFind = myMap.lower_bound(3); // 從鍵值key的最小開始,注意下標從0開始,即正序
	cout << "lower_bound(3): " << "(" << iterFind->first << ", " << iterFind->second << ")" << endl;
	iterFind = myMap.upper_bound(4);// 從鍵值key的最大開始,注意下標從最大開始,即倒序
	cout << "upper_bound(4): " << "(" << iterFind->first << ", " << iterFind->second << ")" << endl;

	// 5、刪除元素
	cout << "-----------------------map刪除元素--------------------" << endl;
	// 刪除第一個元素
	cout << "-----------------------刪除map第一個元素--------------------" << endl;
	myMap.erase(myMap.begin());
	for_each(myMap.begin(), myMap.end(), MyPrintf);
	// 刪除所有的元素
	cout << "-----------------------刪除map中所有的元素--------------------" << endl;
	myMap.erase(myMap.begin(),myMap.end());
	if (myMap.empty())
	{
		cout << "map中所有的元素都已經刪除!" << endl;
	}

	std::cout << "Hello World!\n";
	getchar();
}

運行結果:
在這裏插入圖片描述

四、set

1、set概述

set屬於關聯型容器,能夠按順序存儲一組值,該集合是一個有序的鏈表,元素以升序的順序存儲,集合中的每一個值都不允許重複,其內部實現與map一樣,可以認爲是一種key-value都一樣的特殊map。

2、set優缺點

優點:
1)set會自動排序功能。
2)內存採用紅黑樹,查詢效率高。

缺點:
1)不能直接修改 set 容器中元素的值,修改set容器中的某個值,需要先刪除該元素,再插入新元素。
2)需要額外空間保存節點,會佔用多餘的空間。

3、set代碼示例

// TestSet.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

// 打印函數
void MyPrintf(int elem)
{
	cout << elem << ", ";
}

int main()
{
	cout << "------------------------C++關聯容器set的使用--------------------" << endl;
	// 1、增加元素
	cout << "-----------------------set增加元素--------------------" << endl;
	set<int> myset;
	for (int i = 0; i < 10; i++)
	{
		myset.insert(i);
	}
	for_each(myset.begin(), myset.end(), MyPrintf);
	cout << endl;


	// 2、排序元素
	cout << "------set排序元素,set沒有提供直接排序的函數,需要藉助vector排序-------" << endl;
	vector<int> setVector(myset.begin(), myset.end());
	sort(setVector.begin(), setVector.end(), greater<int>());
	for_each(setVector.begin(), setVector.end(), MyPrintf);
	cout << endl;

	// 3、查找元素
	cout << "-----------------------set查找元素--------------------" << endl;
	set<int>::iterator iterFind;
	iterFind = myset.find(1); // key值爲1的元素
	if (iterFind != myset.end())
	{
		cout << "找到了key值爲1的元素: " << *iterFind<< endl;;
	}

	// 隨機查找元素功能的函數lower_bound和upper_bound
	iterFind = myset.lower_bound(3); // 從鍵值key的最小開始,注意下標從0開始,即正序
	cout << "lower_bound(3): " << *iterFind << endl;
	iterFind = myset.upper_bound(4);// 從鍵值key的最大開始,注意下標從最大開始,即倒序
	cout << "upper_bound(4): " << *iterFind<< endl;

	// 4、刪除元素
	cout << "-----------------------set刪除元素--------------------" << endl;
	// 刪除第一個元素
	cout << "-----------------------刪除set第一個元素--------------------" << endl;
	myset.erase(myset.begin());
	for_each(myset.begin(), myset.end(), MyPrintf);
	cout << endl;
	// 刪除所有的元素
	cout << "-----------------------刪除set中所有的元素--------------------" << endl;
	myset.erase(myset.begin(), myset.end());
	if (myset.empty())
	{
		cout << "set中所有的元素都已經刪除!" << endl;
	}

	std::cout << "Hello World!\n";
	getchar();
}

運行結果:
在這裏插入圖片描述

五、deque

1、deque概述

deque屬於序列式容器,採用動態數組來管理序列中的元素,提供了對序列隨機訪問的功能,可以在序列的兩端進行快速的插入和刪除,並可以根據需要調整自身的大小,是典型的雙端隊列。

2、deque優缺點

優點:
1)支持隨機訪問,可以通過[ ]操作符和at()方法訪問數據。
2)可以在兩端方便的進行插入和刪除操作。
3)容器deque的迭代指針屬於智能型指針。
3)容器deque的迭代器屬於隨機存取迭代器。

缺點:
1)佔用內存多,要通過迭代器來維護內存的整體連續,實際內部並不是連續的。
2)在中間進行插入和刪除時比較慢。

3、deque代碼示例

#// TestDeque.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include <iostream>
#include <deque>
#include <algorithm>
#include <functional>

using namespace std;

// 打印函數
void MyPrintf(int &elem)
{
	cout << elem << ", ";
}

// 修改元素函數
void MyAdd(int &elem)
{
	elem = elem + 10;
}

int main()
{
	cout << "------------------------C++序列化容器deque的使用--------------------" << endl;
	// 1、增加元素
	cout << "-----------------------deque增加元素--------------------" << endl;
	deque<int> myDeque;
	for (int i = 0; i < 10; i++)
	{
		//myDeque.push_back(i);
		//myDeque.push_front(i);
		//myDeque.emplace_front(i); // C++11 頭部增加元素
		myDeque.emplace_back(i); // C++11 尾部增加元素
	}
	for_each(myDeque.begin(), myDeque.end(), MyPrintf);
	cout << endl;

	// 2、排序元素
	cout << "-----------------------deque排序元素--------------------" << endl;
	sort(myDeque.begin(), myDeque.end(), greater<int>());
	for_each(myDeque.begin(), myDeque.end(), MyPrintf);
	cout << endl;

	// 3、修改元素
	cout << "-----------------------deque修改元素--------------------" << endl;
	for_each(myDeque.begin(), myDeque.end(), MyAdd);
	for_each(myDeque.begin(), myDeque.end(), MyPrintf);
	cout << endl;
	cout << "-----------------------打印myDeque2中的元素-----------------------" << endl;
	deque<int> myDeque2;
	myDeque2.assign(myDeque.rbegin(),myDeque.rend());
	for_each(myDeque.begin(), myDeque.end(), MyPrintf);
	cout << endl;

	// 4、查找元素
	cout << "-----------------------deque查找元素--------------------" << endl;
	deque<int>::iterator index;
	index = find(myDeque.begin(), myDeque.end(), 10); // 查找元素10
	// 注意:元素的索引從0開始的
	cout << "元素10的索引index是: " << (index - myDeque.begin()) << endl;
	index = find_if(myDeque.begin(), myDeque.end(), bind2nd(less<int>(), 15));
	cout << "第一個小於15的元素索引index是: " << (index - myDeque.begin()) << endl;

	// 5、刪除元素
	cout << "-----------------------deque刪除元素--------------------" << endl;
	while (!myDeque.empty())
	{
		int backNum = myDeque.back();
		cout << backNum << ", ";
		myDeque.pop_back();
	}
	cout << endl;

	std::cout << "Hello World!\n";
	getchar();
}

運行結果:
在這裏插入圖片描述

六、各個容器的使用場景

1、容器使用場景

vector:當需要高效的隨機存取數據時,而不在乎插入和刪除的效率,可以使用vector。
list:當需要大量的插入和刪除數據時,而不關心隨機存取,可以使用list。
map:當需要以鍵值對的方式存儲數據時,可以使用map。
set:當需要存儲不重複的數據時,可以使用set。
deque:當需要隨機存取數據時,還關心兩端數據的插入和刪除,可以使用deque。

2、C++官方網址

C++的容器使用類模板實現,各個容器提供的方法也非常多,限於篇幅不可能一一列舉出來,文中只是列舉了部分使用方法,具體每個容器的使用方法可以根據官方提供的網址查看,官方網址:http://www.cplusplus.com/reference/vector/vector/?kw=vector

能力有限,如有錯誤,多多指教,覺得有用,點贊鼓勵一下吧。。。

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