1.9 C++學習之list&set&map


3.7 list容器

3.7.1 基本概念

  • 不同於連續的線性空間
  • 節點中維護下一個節點的內存地址
    **功能:**將數據進行鏈式存儲

鏈表(list)是一種物理存儲單元上非連續的存儲結構,數據元素的邏輯順序是通過鏈表中的指針鏈接實現的

鏈表的組成:鏈表由一系列結點組成

結點的組成:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域

STL中的鏈表是一個雙向循環鏈表

在這裏插入圖片描述

  • 上圖沒有體現循環。。。
    由於鏈表的存儲方式並不是連續的內存空間,因此鏈表list中的迭代器只支持前移和後移,屬於雙向迭代器

在這裏插入圖片描述

list的優點:

  • 採用動態存儲分配,不會造成內存浪費和溢出
  • 鏈表執行插入和刪除操作十分方便,修改指針即可,不需要移動大量元素

list的缺點:

  • 鏈表靈活,但是空間(指針域) 和 時間(遍歷)額外耗費較大

List插入操作和刪除操作都不會造成原有list迭代器的失效,這在vector是不成立的(因爲vector可能擴容,從而改變元素的位置,導致指針失效)

3.7.2 構造函數

功能描述:

  • 創建list容器

函數原型:

  • list<T> lst; //list採用採用模板類實現,對象的默認構造形式:
  • list(beg,end); //構造函數將[beg, end)區間中的元素拷貝給本身。
  • list(n,elem); //構造函數將n個elem拷貝給本身。
  • list(const list &lst); //拷貝構造函數。

示例:

#include <list>

void printList(const list<int>& L) {

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void test01()
{
	list<int>L1;  //默認構造
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	printList(L1);

   //區間方式構造
	list<int>L2(L1.begin(),L1.end());
	printList(L2);

  //拷貝構造
	list<int>L3(L2);
	printList(L3);

	list<int>L4(10, 1000);
	printList(L4);
}

int main() {

	test01();

	system("pause");

	return 0;
}
  • 總結:list構造方式同其他STL常用容器

3.7.3 賦值和交換

功能描述:

  • 給list容器進行賦值,以及交換list容器

函數原型:

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

示例:

#include <list>

void printList(const list<int>& L) {

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

//賦值和交換
void test01()
{
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);
	printList(L1);

	//賦值
	list<int>L2;
	L2 = L1; //operator= 賦值
	printList(L2);

	list<int>L3;
	L3.assign(L2.begin(), L2.end());
	printList(L3);

	list<int>L4;
	L4.assign(10, 100);
	printList(L4);

}

//交換
void test02()
{

	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	list<int>L2;
	L2.assign(10, 100);

	cout << "交換前: " << endl;
	printList(L1);
	printList(L2);

	cout << endl;

	L1.swap(L2);

	cout << "交換後: " << endl;
	printList(L1);
	printList(L2);

}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

3.7.4 大小操作

功能描述:

  • 對list容器的大小進行操作

函數原型:

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

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

  • resize(num); //重新指定容器的長度爲num,若容器變長,則以默認值填充新位置。

    ​ //如果容器變短,則末尾超出容器長度的元素被刪除。

  • resize(num, elem); //重新指定容器的長度爲num,若容器變長,則以elem值填充新位置。

      	 	 	​					    //如果容器變短,則末尾超出容器長度的元素被刪除。
    

示例:

#include <list>

void printList(const list<int>& L) {

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

//大小操作
void test01()
{
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	if (L1.empty())
	{
		cout << "L1爲空" << endl;
	}
	else
	{
		cout << "L1不爲空" << endl;
		cout << "L1的大小爲: " << L1.size() << endl;
	}

	//重新指定大小
	L1.resize(10);
	printList(L1);

	L1.resize(2);
	printList(L1);
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 判斷是否爲空 — empty
  • 返回元素個數 — size
  • 重新指定個數 — resize

3.7.5 插入和刪除

功能描述:

  • 對list容器進行數據的插入和刪除

函數原型:

  • push_back(elem);//在容器尾部加入一個元素
  • pop_back();//刪除容器中最後一個元素
  • push_front(elem);//在容器開頭插入一個元素
  • pop_front();//從容器開頭移除第一個元素
  • insert(pos,elem);//在pos位置插elem元素的拷貝,返回新數據的位置。
  • insert(pos,n,elem);//在pos位置插入n個elem數據,無返回值。
  • insert(pos,beg,end);//在pos位置插入[beg,end)區間的數據,無返回值。
  • clear();//移除容器的所有數據
  • erase(beg,end);//刪除[beg,end)區間的數據,返回下一個數據的位置。
  • erase(pos);//刪除pos位置的數據,返回下一個數據的位置。
  • remove(elem);//刪除容器中所有與elem值相等的元素。

示例:

#include <list>

void printList(const list<int>& L) {

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

//插入和刪除
void test01()
{
	list<int> L;
	//尾插
	L.push_back(10);
	L.push_back(20);
	L.push_back(30);
	//頭插
	L.push_front(100);
	L.push_front(200);
	L.push_front(300);

	printList(L);

	//尾刪
	L.pop_back();
	printList(L);

	//頭刪
	L.pop_front();
	printList(L);

	//插入
	list<int>::iterator it = L.begin();
	L.insert(++it, 1000); //第一個位置後插入,不是頭插,偏移了一次
	printList(L);

	//刪除
	it = L.begin();
	L.erase(++it);
	printList(L);

	//移除
	L.push_back(10000);
	L.push_back(10000);
	L.push_back(10000);
	printList(L);
	L.remove(10000);
	printList(L);
    
    //清空
	L.clear();
	printList(L);
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 尾插 — push_back
  • 尾刪 — pop_back
  • 頭插 — push_front
  • 頭刪 — pop_front
  • 插入 — insert
  • 刪除 — erase
  • 移除 — remove
  • 清空 — clear
  • 迭代器可移動

在這裏插入圖片描述

3.7.6 數據存取

功能描述:

  • 對list容器中數據進行存取

函數原型:

  • front(); //返回第一個元素。
  • back(); //返回最後一個元素。

示例:

#include <list>

//數據存取
void test01()
{
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	
	//cout << L1.at(0) << endl;//錯誤 不支持at訪問數據
	//cout << L1[0] << endl; //錯誤  不支持[]方式訪問數據
	cout << "第一個元素爲: " << L1.front() << endl;
	cout << "最後一個元素爲: " << L1.back() << endl;

	//list容器的迭代器是雙向迭代器,不支持隨機訪問
	list<int>::iterator it = L1.begin();
	//it = it + 1;    錯誤,因爲不可以跳躍訪問,即使是+1,類比始作俑者的邏輯
	//但是若干次it++,it--可以
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • list容器中不可以通過[]或者at方式訪問數據
  • 返回第一個元素 — front
  • 返回最後一個元素 — back
  • it++:說明可以向後訪問,it–同理
  • it =it +1不報錯,說明支持隨機訪問,類比始作俑者的邏輯

在這裏插入圖片描述

在這裏插入圖片描述

3.7.7 反轉和排序

功能描述:

  • 將容器中的元素反轉,以及將容器中的數據進行排序

函數原型:

  • reverse(); //反轉鏈表
  • sort(); //鏈表排序

示例:

void printList(const list<int>& L) {

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

//降序
bool myCompare(int val1 , int val2)
{
	return val1 > val2;
}

//反轉和排序
void test01()
{
	list<int> L;
	L.push_back(90);
	L.push_back(30);
	L.push_back(20);
	L.push_back(70);
	printList(L);

	//反轉容器的元素
	L.reverse();
	printList(L);

	//排序
	L.sort(); //默認的排序規則 從小到大
	printList(L);

	L.sort(myCompare); //指定規則,從大到小
	printList(L);
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 反轉 — reverse
  • 排序 — sort (成員函數)

在這裏插入圖片描述

3.7.8 排序案例

案例描述:將Person自定義數據類型進行排序,Person中屬性有姓名、年齡、身高

排序規則:按照年齡進行升序,如果年齡相同按照身高進行降序

示例:

#include <list>
#include <string>
class Person {
public:
	Person(string name, int age , int height) {
		m_Name = name;
		m_Age = age;
		m_Height = height;
	}

public:
	string m_Name;  //姓名
	int m_Age;      //年齡
	int m_Height;   //身高
};

//指定排序規則
bool ComparePerson(Person& p1, Person& p2) {
 //年齡相同,按身高降序
	if (p1.m_Age == p2.m_Age) {
		return p1.m_Height  > p2.m_Height;
	}
	else
	{   //按年齡升序
		return  p1.m_Age < p2.m_Age;
	}

}

void test01() {

	list<Person> L;

	Person p1("劉備", 35 , 175);
	Person p2("曹操", 45 , 180);
	Person p3("孫權", 40 , 170);
	Person p4("趙雲", 25 , 190);
	Person p5("張飛", 35 , 160);
	Person p6("關羽", 35 , 200);

	L.push_back(p1);
	L.push_back(p2);
	L.push_back(p3);
	L.push_back(p4);
	L.push_back(p5);
	L.push_back(p6);

	for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
		cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age 
              << " 身高: " << it->m_Height << endl;
	}

	cout << "---------------------------------" << endl;
	L.sort(ComparePerson); //排序

	for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
		cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age 
              << " 身高: " << it->m_Height << endl;
	}
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 對於自定義數據類型,必須要指定排序規則,否則編譯器不知道如何進行排序

  • 高級排序只是在排序規則上再進行一次邏輯規則制定,並不複雜

3.8 set/ multiset 容器

3.8.1 基本概念

簡介:

  • 所有元素都會在插入時自動被排序

本質:

  • set/multiset屬於關聯式容器,底層結構是用二叉樹實現。

set和multiset區別

  • set不允許容器中有重複的元素
  • multiset允許容器中有重複的元素

3.8.2 構造和賦值

功能描述:創建set容器以及賦值

構造:

  • set<T> st; //默認構造函數:
  • set(const set &st); //拷貝構造函數

賦值:

  • set& operator=(const set &st); //重載等號操作符

示例:

#include <set>

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

//構造和賦值
void test01()
{
	set<int> s1;

  //插入數據只有insert方式
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	printSet(s1);

	//拷貝構造
	set<int>s2(s1);
	printSet(s2);

	//賦值
	set<int>s3;
	s3 = s2;
	printSet(s3);
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • set容器插入數據時用insert
  • set容器插入數據的數據會自動排序

3.8.3 大小和交換

功能描述:

  • 統計set容器大小以及交換set容器

函數原型:

  • size(); //返回容器中元素的數目
  • empty(); //判斷容器是否爲空
  • swap(st); //交換兩個容器

示例:

#include <set>

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

//大小
void test01()
{

	set<int> s1;
	
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);

	if (s1.empty())
	{
		cout << "s1爲空" << endl;
	}
	else
	{
		cout << "s1不爲空" << endl;
		cout << "s1的大小爲: " << s1.size() << endl;
	}

}

//交換
void test02()
{
	set<int> s1;

	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);

	set<int> s2;

	s2.insert(100);
	s2.insert(300);
	s2.insert(200);
	s2.insert(400);

	cout << "交換前" << endl;
	printSet(s1);
	printSet(s2);
	cout << endl;

	cout << "交換後" << endl;
	s1.swap(s2);
	printSet(s1);
	printSet(s2);
}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

總結:

  • 統計大小 — size
  • 判斷是否爲空 — empty
  • 交換容器 — swap
  • 不支持resize方法

3.8.4 插入和刪除

功能描述:

  • set容器進行插入數據和刪除數據

函數原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //刪除pos迭代器所指的元素,返回下一個元素的迭代器。
  • erase(beg, end); //刪除區間[beg,end)的所有元素 ,返回下一個元素的迭代器。
  • erase(elem); //刪除容器中值爲elem的元素。

示例:

#include <set>

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

//插入和刪除
void test01()
{
	set<int> s1;
	//插入
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	printSet(s1);

	//刪除
	s1.erase(s1.begin());
	printSet(s1);

	s1.erase(30);
	printSet(s1);

	//清空
	//s1.erase(s1.begin(), s1.end());
	s1.clear();
	printSet(s1);
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 插入 — insert
  • 刪除 — erase
  • 清空 — clear

3.8.5 查找和統計

功能描述:

  • 對set容器進行查找數據以及統計數據

函數原型:

  • find(key); //查找key是否存在,若存在,返回該鍵的元素的迭代器;若不存在,返回set.end();
  • count(key); //統計key的元素個數

示例:

#include <set>

//查找和統計
void test01()
{
	set<int> s1;
	//插入
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	
	//查找
	set<int>::iterator pos = s1.find(30);

	if (pos != s1.end())
	{
		cout << "找到了元素 : " << *pos << endl;
	}
	else
	{
		cout << "未找到元素" << endl;
	}

	//統計
	int num = s1.count(30);
	cout << "num = " << num << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 查找 — find (返回的是迭代器)
  • 統計 — count (對於set,結果爲0或者1)

3.8.6 set和multiset區別

學習目標:

  • 掌握set和multiset的區別

區別:

  • set不可以插入重複數據,而multiset可以
  • set插入數據的同時會返回插入結果,表示插入是否成功
  • multiset不會檢測數據,因此可以插入重複數據

在這裏插入圖片描述

  • 上圖爲底層,_Pairib爲set的insert方法的返回值,從pair的組成可見可通過pair.second = bool來判斷是否插入成功
  • pair.first返回的是迭代器,即插入的位置
 pair<set<int>::iterator, bool>  ret = s.insert(10); 
	if (ret.second) {
		cout << "第二次插入成功!" << endl;
	}
	else {
		cout << "第二次插入失敗!" << endl;
	}

示例:

#include <set>

//set和multiset區別
void test01()
{
	set<int> s;
	pair<set<int>::iterator, bool>  ret = s.insert(10); //插入位置——插入成功否
	if (ret.second) {
		cout << "第一次插入成功!" << endl;
	}
	else {
		cout << "第一次插入失敗!" << endl;
	}

	ret = s.insert(10);
	if (ret.second) {
		cout << "第二次插入成功!" << endl;
	}
	else {
		cout << "第二次插入失敗!" << endl;
	}
    
	//multiset
	multiset<int> ms;
	ms.insert(10); //返回迭代器,即插入的位置
	ms.insert(10);

	for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 如果不允許插入重複數據可以利用set
  • 如果需要插入重複數據利用multiset

3.8.7 pair對組創建

功能描述:

  • 成對出現的數據,利用對組可以返回兩個數據

兩種創建方式:

  • pair<type, type> p ( value1, value2 );
  • pair<type, type> p = make_pair( value1, value2 );

示例:

#include <string>

//對組創建
void test01()
{
//不需要頭文件
	pair<string, int> p(string("Tom"), 20);
	cout << "姓名: " <<  p.first << " 年齡: " << p.second << endl;

	pair<string, int> p2 = make_pair("Jerry", 10);
	cout << "姓名: " << p2.first << " 年齡: " << p2.second << endl;
}

int main() {

	test01();
	system("pause");
	return 0;
}

3.8.8 set容器排序

學習目標:

  • set容器默認排序規則爲從小到大,掌握如何改變排序規則

主要技術點:

  • 利用仿函數(本質是類),可以改變排序規則

示例一 set存放內置數據類型

#include <set>

class MyCompare 
{
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};
void test01() 
{    
	set<int> s1;
	s1.insert(10);
	s1.insert(40);
	s1.insert(20);
	s1.insert(30);
	s1.insert(50);

	//默認從小到大
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	//插入前指定排序規則
	set<int,MyCompare> s2;
	s2.insert(10);
	s2.insert(40);
	s2.insert(20);
	s2.insert(30);
	s2.insert(50);

	for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:利用仿函數可以指定set容器的排序規則

示例二 set存放自定義數據類型

#include <set>
#include <string>

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;

};
class comparePerson
{
public:
	bool operator()(const Person& p1, const Person &p2)
	{
		//按照年齡進行排序  降序
		return p1.m_Age > p2.m_Age;
	}
};

void test01()
{
	set<Person, comparePerson> s;

	Person p1("劉備", 23);
	Person p2("關羽", 27);
	Person p3("張飛", 25);
	Person p4("趙雲", 21);

	s.insert(p1);
	s.insert(p2);
	s.insert(p3);
	s.insert(p4);

	for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << "姓名: " << it->m_Name << " 年齡: " << it->m_Age << endl;
	}
}
int main() {

	test01();

	system("pause");

	return 0;
}
  • 總結:對於自定義數據類型,set必須指定排序規則纔可以插入數據

3.9 map/ multimap容器

3.9.1 map基本概念

簡介:

  • map中所有元素都是pair
  • pair中第一個元素爲key(鍵值),起到索引作用,第二個元素爲value(實值)
  • 所有元素都會根據元素的鍵值自動排序

本質:

  • map/multimap屬於關聯式容器,底層結構是用二叉樹實現。

優點:

  • 可以根據key值快速找到value值

map和multimap區別

  • map不允許容器中有重複key值元素
  • multimap允許容器中有重複key值元素

3.9.2 構造和賦值

功能描述:

  • 對map容器進行構造和賦值操作

函數原型:

構造:

  • map<T1, T2> mp; //map默認構造函數:
  • map(const map &mp); //拷貝構造函數

賦值:

  • map& operator=(const map &mp); //重載等號操作符

示例:

#include <map>

void printMap(map<int,int>&m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

void test01()
{
	map<int,int>m; //默認構造
	m.insert(pair<int, int>(1, 10)); //匿名對組
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));
	printMap(m);

	map<int, int>m2(m); //拷貝構造
	printMap(m2);

	map<int, int>m3;
	m3 = m2; //賦值
	printMap(m3);
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:map中所有元素都是成對出現,插入數據時候要使用對組

3.9.3 大小和交換

功能描述:

  • 統計map容器大小以及交換map容器

函數原型:

  • size(); //返回容器中元素的數目
  • empty(); //判斷容器是否爲空
  • swap(st); //交換兩個集合容器

示例:

#include <map>

void printMap(map<int,int>&m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

void test01()
{
	map<int, int>m;
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));

	if (m.empty())
	{
		cout << "m爲空" << endl;
	}
	else
	{
		cout << "m不爲空" << endl;
		cout << "m的大小爲: " << m.size() << endl;
	}
}


//交換
void test02()
{
	map<int, int>m;
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));

	map<int, int>m2;
	m2.insert(pair<int, int>(4, 100));
	m2.insert(pair<int, int>(5, 200));
	m2.insert(pair<int, int>(6, 300));

	cout << "交換前" << endl;  
	printMap(m);
	printMap(m2);

	cout << "交換後" << endl;
	m.swap(m2);
	printMap(m);
	printMap(m2);
}

int main() {

	test01();

	test02();

	system("pause");

	return 0;
}

總結:

  • 統計大小 — size
  • 判斷是否爲空 — empty
  • 交換容器 — swap

3.9.4 插入和刪除

功能描述:

  • map容器進行插入數據和刪除數據

函數原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //刪除pos迭代器所指的元素,返回下一個元素的迭代器。
  • erase(beg, end); //刪除區間[beg,end)的所有元素 ,返回下一個元素的迭代器。
  • erase(key); //刪除容器中值爲key的元素。

在這裏插入圖片描述

示例:

#include <map>

void printMap(map<int,int>&m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

void test01()
{
	//插入
	map<int, int> m;
	//第一種插入方式
	m.insert(pair<int, int>(1, 10));
	//第二種插入方式
	m.insert(make_pair(2, 20));
	//第三種插入方式
	m.insert(map<int, int>::value_type(3, 30));
	//第四種插入方式
	m[4] = 40; 
	printMap(m);

	//刪除
	m.erase(m.begin());
	printMap(m);

	m.erase(3);  //按key刪除
	printMap(m);

	//清空
	m.erase(m.begin(),m.end());
	m.clear();
	printMap(m);
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • map插入方式很多,記住其一即可
  • 插入 — insert
  • 刪除 — erase
  • 清空 — clear

在這裏插入圖片描述

  • 如上圖所示,明明是想查看m[5]的值,但map中沒有,此時會自動創建(5,0)的鍵值對,不符合預期邏輯

3.9.5 查找和統計

功能描述:

  • 對map容器進行查找數據以及統計數據

函數原型:

  • find(key); //查找key是否存在,若存在,返回該鍵的元素的迭代器;若不存在,返回set.end();
  • count(key); //統計key的元素個數

示例:

#include <map>

//查找和統計
void test01()
{
	map<int, int>m; 
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));

	//查找
	map<int, int>::iterator pos = m.find(3);

	if (pos != m.end())
	{
		cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl;
	}
	else
	{
		cout << "未找到元素" << endl;
	}

	//統計
	int num = m.count(3);
	cout << "num = " << num << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

總結:

  • 查找 — find (返回的是迭代器)

  • 統計 — count (對於map,結果爲0或者1)

  • 先進去的對組會讓後進去的對組插入不到map中(注意不是覆蓋)

3.9.6 map容器排序

學習目標:

  • map容器默認排序規則爲 按照key值進行 從小到大排序,掌握如何改變排序規則

主要技術點:

  • 利用仿函數,可以改變排序規則

示例:

#include <map>

class MyCompare {
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};

void test01() 
{
	//默認從小到大排序
	//利用仿函數實現從大到小排序
	map<int, int, MyCompare> m;

	m.insert(make_pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(make_pair(3, 30));
	m.insert(make_pair(4, 40));
	m.insert(make_pair(5, 50));

	for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
		cout << "key:" << it->first << " value:" << it->second << endl;
	}
}
int main() {

	test01();
	system("pause");
	return 0;
}

總結:

  • 利用仿函數可以指定map容器的排序規則
  • 對於自定義數據類型,map必須要指定排序規則,同set容器

3.10 案例-員工分組

3.10.1 案例描述

  • 公司今天招聘了10個員工(ABCDEFGHIJ),10名員工進入公司之後,需要指派員工在那個部門工作
  • 員工信息有: 姓名 工資組成;部門分爲:策劃、美術、研發
  • 隨機給10名員工分配部門和工資
  • 通過multimap進行信息的插入 key(部門編號) value(員工)
  • 分部門顯示員工信息

3.10.2 實現步驟

  1. 創建10名員工,放到vector中
  2. 遍歷vector容器,取出每個員工,進行隨機分組
  3. 分組後,將員工部門編號作爲key,具體員工作爲value,放入到multimap容器中
  4. 分部門顯示員工信息

案例代碼:

#include<iostream>
using namespace std;
#include <vector>
#include <string>
#include <map>
#include <ctime>

/*
- 公司今天招聘了10個員工(ABCDEFGHIJ),10名員工進入公司之後,需要指派員工在那個部門工作
- 員工信息有: 姓名  工資組成;部門分爲:策劃、美術、研發
- 隨機給10名員工分配部門和工資
- 通過multimap進行信息的插入  key(部門編號) value(員工)
- 分部門顯示員工信息
*/

#define CEHUA  0
#define MEISHU 1
#define YANFA  2

class Worker
{
public:
	string m_Name;
	int m_Salary;
};

void createWorker(vector<Worker>&v)
{
	string nameSeed = "ABCDEFGHIJ";
	for (int i = 0; i < 10; i++)
	{
		Worker worker;
		worker.m_Name = "員工";
		worker.m_Name += nameSeed[i];

		worker.m_Salary = rand() % 10000 + 10000; // 10000 ~ 19999
		//將員工放入到容器中
		v.push_back(worker);
	}
}

//員工分組
void setGroup(vector<Worker>&v,multimap<int,Worker>&m)
{
	for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++)
	{
		//產生隨機部門編號
		int deptId = rand() % 3; // 0 1 2 

		//將員工插入到分組中
		//key部門編號,value具體員工
		m.insert(make_pair(deptId, *it));
	}
}

void showWorkerByGourp(multimap<int,Worker>&m)
{
	// 0  A  B  C   1  D  E   2  F G ...
	cout << "策劃部門:" << endl;

	multimap<int,Worker>::iterator pos = m.find(CEHUA);
	int count = m.count(CEHUA); // 統計具體人數
	int index = 0;
	for (; pos != m.end() && index < count; pos++ , index++)
	{ 
		cout << "姓名: " << pos->second.m_Name << " 工資: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "美術部門: " << endl;
	pos = m.find(MEISHU);
	count = m.count(MEISHU); // 統計具體人數
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "姓名: " << pos->second.m_Name << " 工資: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "研發部門: " << endl;
	pos = m.find(YANFA);
	count = m.count(YANFA); // 統計具體人數
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "姓名: " << pos->second.m_Name << " 工資: " << pos->second.m_Salary << endl;
	}

}

int main() {

	srand((unsigned int)time(NULL));

	//1、創建員工
	vector<Worker>vWorker;
	createWorker(vWorker);

	//2、員工分組
	multimap<int, Worker>mWorker;
	setGroup(vWorker, mWorker);


	//3、分組顯示員工
	showWorkerByGourp(mWorker);

	////測試
	//for (vector<Worker>::iterator it = vWorker.begin(); it != vWorker.end(); it++)
	//{
	//	cout << "姓名: " << it->m_Name << " 工資: " << it->m_Salary << endl;
	//}

	system("pause");

	return 0;
}

總結:

  • 當數據以鍵值對形式存在,可以考慮用map 或 multimap
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章