【C/C++】詳解關聯容器map的使用

🔗?運行環境:Matlab

🚩?撰寫作者:左手の明天

🥇?精選專欄:《python》

🔥??推薦專欄:《算法研究》

🔐####?防偽水印——左手の明天?####🔐

💗 大家好🤗🤗🤗,我是左手の明天!好久不見💗

💗今天分享C/C++——關聯容器map的使用💗

📆? 最近更新:2024 年 05 月 26 日,左手の明天的第?331?篇原創博客

📚?更新于專欄:C/C++入門與進階

🔐####?防偽水印——左手の明天?####🔐


一、引言

關聯容器map是STL(Standard Template Library,標準模板庫)中的一個重要組件,它提供了一對一的數據處理能力。在map中,每個元素都是一個關鍵字-值(key-value)對,其中關鍵字起到索引的作用,而值則表示與索引相關聯的數據。這種特性使得map在處理一對一數據時,能夠在編程上提供快速通道。

map內部自建一棵紅黑樹(一種非嚴格意義上的平衡二叉樹),這顆樹具有對數據自動排序的功能,因此map內部的所有數據都是有序的。這種有序性為數據的查找、插入和刪除等操作提供了便利。

在map中,關鍵字是唯一的,每個關鍵字在map中只能出現一次。而值是可以修改的,可以通過關鍵字來訪問和修改與之對應的值。此外,map還支持下標訪問符,通過在[]中放入關鍵字,可以找到與該關鍵字對應的值。

總的來說,關聯容器map是一個功能強大的數據結構,它能夠在處理一對一數據時提供高效的數據處理能力,并在編程中提供便捷的操作方式。


二、Map的構造函數

map的構造函數有多種形式,包括匿名對象構造、有名構造、多參數構造函數的隱式類型轉換等。在插入數據時,可以使用insert函數插入pair數據或value_type數據,也可以使用數組方式插入數據。需要注意的是,當使用insert函數插入數據時,如果map中已存在相同的關鍵字,則插入操作不會生效;而使用數組方式插入數據時,如果關鍵字已存在,則會覆蓋以前該關鍵字對應的值。

std::map在C++標準庫中有多個構造函數,允許你以不同的方式初始化map對象。以下是一些常見的std::map構造函數及其用法:

2.1 默認構造函數

默認構造函數創建一個空的map

std::map<int, std::string> myMap;

2.2 復制構造函數

復制構造函數允許你從一個已存在的map對象創建一個新的map對象。

std::map<int, std::string> myMap1;
myMap1[1] = "one";
myMap1[2] = "two";std::map<int, std::string> myMap2(myMap1); // 使用myMap1初始化myMap2

2.3 初始化列表構造函數

使用初始化列表可以直接在構造函數中初始化map的元素。

std::map<int, std::string> myMap = {{1, "one"},{2, "two"},{3, "three"}
};

或者C++11及以后的語法:

std::map<int, std::string> myMap{{1, "one"},{2, "two"},{3, "three"}
};

2.4 迭代器范圍的構造函數

你可以使用一對迭代器來從一個已存在的容器(如數組、另一個mapvector等)初始化map

std::pair<int, std::string> array[] = {{1, "one"},{2, "two"},{3, "three"}
};std::map<int, std::string> myMap(array, array + sizeof(array) / sizeof(array[0]));

2.5 分配器構造函數

分配器構造函數允許你使用一個自定義的分配器來管理map的內存。這在需要控制內存分配和釋放時特別有用。

std::allocator<std::pair<const int, std::string>> alloc;
std::map<int, std::string> myMap(alloc);

在實際使用中,你通常會使用默認構造函數或初始化列表構造函數來創建和初始化map對象。例如,當你需要快速創建一個具有固定鍵值對的map時,初始化列表構造函數非常方便。

記住,由于map是有序的,所以當你使用初始化列表或迭代器范圍構造函數時,鍵值對的順序將影響最終map中元素的順序。如果你使用默認的比較函數(std::less<Key>),元素將按照鍵的升序排列。如果你提供了自定義的比較函數,元素將根據該比較函數的邏輯排序。


三、Map的基本操作函數

C++ Maps是一種關聯式容器,包含“關鍵字/值”對,如下表:

操作函數含義
begin()返回指向map頭部的迭代器
clear()刪除所有元素
count()返回指定元素出現的次數
empty()如果map為空則返回true
end()返回指向map末尾的迭代器
equal_range()返回特殊條目的迭代器對
erase()刪除一個元素
find()查找一個元素
get_allocator()返回map的配置器
insert()插入元素
key_comp()返回比較元素key的函數

lower_bound()

返回鍵值>=給定元素的第一個位置
max_size()返回可以容納的最大元素個數
rbegin()返回一個指向map尾部的逆向迭代器
rend()返回一個指向map頭部的逆向迭代器
size()返回map中元素的個數

swap()

交換兩個map

value_comp()返回比較元素value的函數
upper_bound()返回鍵值>給定元素的第一個位置

四、Map的實現

Map是存儲鍵值對的數據結構,它提供了一種方便的方法來訪問和操作這些鍵值對。在C語言中,可以使用哈希表來實現Map。Map提供了以下基本操作:

  1. 插入:將一個新的鍵值對插入到Map中。
  2. 查找:根據鍵查找對應的值。
  3. 刪除:刪除指定的鍵值對。
  4. 更新:修改指定鍵的值。
  5. 大小:返回Map中存儲的鍵值對的數量。
  6. 遍歷:遍歷Map中的所有鍵值對。

在C++中,std::map是一個關聯容器,它存儲的元素都是鍵值對(key-value),并且根據鍵的值自動排序。每個鍵在map中只能出現一次,鍵不能修改,但對應的值可以修改。map的底層結構通常是用紅黑樹實現的,因此map中的元素總是有序的。

下面是使用std::map的基本步驟:

4.1?包含頭文件

首先,你需要包含<map>頭文件來使用std::map

#include <map>

4.2?定義和創建map對象

你可以使用std::map模板來定義和創建map對象。你需要指定鍵和值的類型。

std::map<int, std::string> myMap;  // 定義一個map,鍵是int類型,值是std::string類型

4.3?插入元素

你可以使用insert()函數來插入元素。通常,你可以使用std::make_pair來創建一個鍵值對,并將其插入到map中。

myMap.insert(std::make_pair(1, "one"));
myMap.insert(std::make_pair(2, "two"));

或者,你可以直接使用[]運算符來插入或修改元素(如果鍵已存在,則修改對應的值;如果鍵不存在,則插入新的鍵值對)。

myMap[3] = "three"; // 插入鍵為3,值為"three"的鍵值對

4.4 訪問元素

你可以使用[]運算符或at()函數來訪問元素。如果鍵不存在于map中,at()會拋出異常,而[]會創建一個新的元素。

std::string value = myMap[1]; // 訪問鍵為1的元素的值
std::string value2 = myMap.at(2); // 另一種訪問元素的方式

4.5?遍歷map

你可以使用迭代器來遍歷map中的所有元素。

for (std::map<int, std::string>::iterator it = myMap.begin(); it != myMap.end(); ++it) {std::cout << "Key: " << it->first << ", Value: " << it->second << std::endl;
}

或者使用基于范圍的for循環(C++11及以后版本):

for (const auto& kv : myMap) {std::cout << "Key: " << kv.first << ", Value: " << kv.second << std::endl;
}

4.6?刪除元素

你可以使用erase()函數來刪除元素。

myMap.erase(1); // 刪除鍵為1的元素

4.7 查找元素

你可以使用find()函數來檢查元素是否存在。find()函數返回一個迭代器指向鍵值為key的元素,如果沒找到就返回指向map尾部的迭代器。

auto it = myMap.find(1);
if (it != myMap.end()) {std::cout << "Element found with key 1." << std::endl;
} 
else {std::cout << "Element not found." << std::endl;
}

這些是std::map的基本用法。在實際編程中,你可能還需要了解更多關于map的高級用法,比如自定義比較函數、使用emplace()函數插入元素等。你可以查閱C++標準庫文檔或相關教程來獲取更多信息。

4.8 map中swap的用法:

Map中的swap不是一個容器中的元素交換,而是兩個容器交換;

#include <map>
#include <iostream>using namespace std;int main( )
{map <int, int> m1, m2, m3;map <int, int>::iterator m1_Iter;m1.insert ( pair <int, int> ( 1, 10 ) );m1.insert ( pair <int, int> ( 2, 20 ) );m1.insert ( pair <int, int> ( 3, 30 ) );m2.insert ( pair <int, int> ( 10, 100 ) );m2.insert ( pair <int, int> ( 20, 200 ) );m3.insert ( pair <int, int> ( 30, 300 ) );cout << "The original map m1 is:";for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )cout << " " << m1_Iter->second;cout << "." << endl;// This is the member function version of swap//m2 is said to be the argument map; m1 the target mapm1.swap( m2 );cout << "After swapping with m2, map m1 is:";for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )cout << " " << m1_Iter -> second;cout << "." << endl;cout << "After swapping with m2, map m2 is:";for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ )cout << " " << m1_Iter -> second;cout << "." << endl;// This is the specialized template version of swapswap( m1, m3 );cout << "After swapping with m3, map m1 is:";for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )cout << " " << m1_Iter -> second;cout << "." << endl;
}

4.9 map的sort問題:

Map中的元素是自動按key升序排序,所以不能對map用sort函數:

#include <map>
#include <iostream>using namespace std;int main( )
{map <int, int> m1;map <int, int>::iterator m1_Iter;m1.insert ( pair <int, int> ( 1, 20 ) );m1.insert ( pair <int, int> ( 4, 40 ) );m1.insert ( pair <int, int> ( 3, 60 ) );m1.insert ( pair <int, int> ( 2, 50 ) );m1.insert ( pair <int, int> ( 6, 40 ) );m1.insert ( pair <int, int> ( 7, 30 ) );cout << "The original map m1 is:"<<endl;for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )cout << m1_Iter->first<<" "<<m1_Iter->second<<endl;
}

The original map m1 is:

1 20

2 50

3 60

4 40

6 40

7 30


五、Map定義自定義比較函數

std::map中定義自定義比較函數是通過向std::map模板的第三個參數傳遞一個比較對象來實現的。這個比較對象通常是一個函數對象(也稱為仿函數)或者Lambda表達式,它需要重載operator()來定義兩個元素之間的比較邏輯。

下面是使用自定義比較函數的std::map的幾種方式:

5.1 使用函數對象(仿函數)

首先,定義一個比較函數對象:

struct MyComparator {bool operator()(const int& a, const int& b) const {// 定義比較邏輯,這里假設我們要按照降序排列return a > b;}
};

然后,使用這個比較函數對象來創建std::map

std::map<int, std::string, MyComparator> myMap;

5.2 使用Lambda表達式(C++11及以后)

在C++11及更高版本中,你可以使用Lambda表達式作為比較函數:

auto comp = [](const int& a, const int& b) {// 定義比較邏輯return a > b;
};std::map<int, std::string, decltype(comp)> myMap(comp);

注意這里使用了decltype(comp)來自動推斷比較函數的類型。

5.3 使用標準庫函數對象

有時,你可能不需要完全自定義比較邏輯,而是想要對map中的鍵進行某種轉換后再比較。在這種情況下,你可以使用標準庫提供的函數對象適配器,如std::greater<>std::less<>,配合自定義的鍵轉換函數。但是,這通常是通過自定義比較函數對象來實現的,其中內部使用這個轉換函數。

示例:降序排列的std::map

假設想要一個按照鍵的降序排列的std::map

#include <iostream>
#include <map>
#include <string>int main() {// 使用自定義比較函數對象創建降序排列的mapstd::map<int, std::string, std::greater<int>> myMap;myMap[3] = "three";myMap[1] = "one";myMap[2] = "two";// 遍歷map,顯示鍵值對for (const auto& kv : myMap) {std::cout << "Key: " << kv.first << ", Value: " << kv.second << std::endl;}return 0;
}

在這個例子中,使用了std::greater<int>作為比較函數對象,它會使std::map按照鍵的降序排列。

記住,std::map的默認比較函數是std::less<Key>,它會產生升序排列的map。通過提供自定義的比較函數對象,你可以改變元素的排序方式。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/16134.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/16134.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/16134.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mpv常用快捷鍵

1 mpv mpv是Linux下的一個開源視頻播放器&#xff0c;使用Manjaro的話安裝方式如下&#xff1a; paru -S mpv2 常用快捷鍵 q&#xff1a;推出w/e&#xff1a;視頻縮放r/t&#xff1a;調整字幕位置u&#xff1a;開啟/關閉ass/ssa字幕覆蓋i&#xff1a;顯示當前播放的視頻信息…

Oracle 并行和 session 數量的

這也就是為什么我們指定parallel為4&#xff0c;而實際并行度為8的原因。 insert create index&#xff0c;發現并行數都是加倍的 Indexes seem always created with parallel degree 1 during import as seen from a sqlfile. The sql file shows content like: CREATE INDE…

求平方數 1 到 N 之間所有正整數的平方數

概念&#xff1a; 平方數的概念&#xff1a; 平方數是指一個數的平方等于另一個數的數&#xff0c;具有正平方數和負平方數&#xff0c;其性質和運用在多領域中具有重要意義&#xff0c;如幾何、自然科學、計算機科學和物理學。平方數的計算和運用在多領域中常見&#xff0c;例…

滑不動窗口的秘密—— “滑動窗口“算法 (Java版)

本篇會加入個人的所謂魚式瘋言 ??????魚式瘋言:??????此瘋言非彼瘋言 而是理解過并總結出來通俗易懂的大白話, 小編會盡可能的在每個概念后插入魚式瘋言,幫助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能說的不是那么嚴謹.但小編初心是能讓更多人能接…

《python編程從入門到實踐》day39

# 昨日知識點回顧 創建主頁、繼承模版、顯示特定主題頁面 # view.py from django.shortcuts import render# 導入所需數據相關聯的模型 from .models import Topic# Create your views here. def index(request):"""學習筆記的主頁"""#…

Java進階學習筆記13——抽象類

認識抽象類&#xff1a; 當我們在做子類共性功能抽取的時候&#xff0c;有些方法在父類中并沒有具體的體現&#xff0c;這個時候就需要抽象類了。在Java中&#xff0c;一個沒有方法體的方法應該定義為抽象方法&#xff0c;而類中如果有抽象方法&#xff0c;該類就定義為抽象類…

ISCC2024個人挑戰賽WP-迷失之門

&#xff08;非官方解&#xff0c;以下內容均互聯網收集的信息和個人思路&#xff0c;僅供學習參考&#xff09; 迷失之門 方法一&#xff1a; IDA看一下 check函數邏輯 進入到check2函數 R鍵將ascii碼轉字符&#xff0c;寫出逆向腳本 #include <stdio.h> #include &l…

嵌入式0基礎開始學習 Ⅱ 數據結構(7)小結練習

1,如果使用比較高效的算法判斷單鏈表有沒有環的算法中&#xff0c;至少需要幾個指針&#xff1f; A,1 B,2 C,3 D,4 2&#xff0c;以鏈接方式存儲的線性表(X1,X2,...,Xn),當訪問第i個元素的時間復雜度為? A,o(1) B,o(n) C,o(logn) Do(n) 3,下列鏈表中&…

Linux C++ Socket 套接字、select、poll、epoll 實例

文章目錄 1. 概述2. TCP 網絡編程實例2.1 服務器端2.2 客戶端2.3 運行截圖 3. I/O 模型3.1 阻塞式I/O模型3.2 非阻塞I/O模型3.3 I/O 復用模型3.4 信號驅動式I/O3.5 異步I/O模型 4. I/O復用之 select4.1 select 函數描述4.2 服務端代碼4.3 客戶端代碼4.4 運行截圖 5. I/O復用之 …

RocketMq局部順序消息

package com.ldj.rocketmq.producer;import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message;import java.nio.charset.StandardCharsets;/*** User: ldj* Date: 2024/5/26* Time: 15:09* Description: 局部順序消…

【Linux】$()中的內容與不加$()時有什么區別

$()中的內容與不加$()有什么區別&#xff0c;例如$(/usr/local/hadoop/bin/hadoop classpath)與/usr/local/hadoop/bin/hadoop classpath兩者有何區別&#xff1f;&#xff1f;&#xff1f; 關于這個問題&#xff0c;筆者建議可以參考如下文章&#xff1a; Linux—shell中$((…

css卡片翻轉 父元素翻轉子元素不翻轉效果

css卡片翻轉 父元素翻轉子元素不翻轉效果 vue <div class"moduleBox"><div class"headTitle"><span class"headName">大額案例</span></div><div class"moduleItem"><span class"module…

three.js判斷物體在人的前面,還是后面

three.js判斷物體在人的前面&#xff0c;還是后面 const player new THREE.Vectors(10, 0, 5); const mesh new THREE.Vectors(15, 0, 6);上面&#xff0c;兩個變量分別表示&#xff0c;玩家的位置&#xff0c;物體的位置。 從這發現&#xff0c;當玩家和物體的角度關系 小…

spring boot 整合j2cache 項目啟動警告 Redis mode [null] not defined. Using ‘single‘

好 之前的文章 spring boot 整合j2cache 基礎操作 在spring boot環境中整合了 j2cache 我們 項目啟動時 日志會有一個關鍵信息 Redis的模式 沒有定義 默認使用 single Redis 的這個模式有四種 大家可以自己去網上找一下 做個了解 不用很糾結 我們直接在 j2cache.properties …

一文讀懂Apollo客戶端配置加載流程

本文基于 apollo-client 2.1.0 版本源碼進行分析 Apollo 是攜程開源的配置中心&#xff0c;能夠集中化管理應用不同環境、不同集群的配置&#xff0c;配置修改后能夠實時推送到應用端&#xff0c;并且具備規范的權限、流程治理等特性。 Apollo支持4個維度管理Key-Value格式的配…

Elasticsearch智能數據分析平臺項目

Elasticsearch智能數據分析平臺項目是一個功能強大且靈活的數據分析工具,旨在幫助企業快速、準確地分析和挖掘數據中的價值。以下是關于該項目的一些關鍵特點和功能: 數據搜索: Elasticsearch作為全球下載量最大的搜索引擎,支持從關鍵字搜索到向量搜索等多樣化搜索方式,讓…

比勤奮更重要的是系統思考的能力

不要在接近你問題癥狀的地方尋找解決辦法&#xff0c;要追溯過去&#xff0c;查找問題的根源。通常&#xff0c;最有效的活動是最微妙的。有時最好按兵不動&#xff0c;使系統自我修正&#xff0c;或讓系統引導行動。有時會發現&#xff0c;最好的解決辦法出現在完全出乎預料的…

HTML藍色愛心

目錄 寫在前面 HTML入門 完整代碼 代碼分析 運行結果 系列推薦 寫在后面 寫在前面 最近好冷吖&#xff0c;小編給大家準備了一個超級炫酷的愛心&#xff0c;一起來看看吧&#xff01; HTML入門 HTML全稱為HyperText Markup Language&#xff0c;是一種標記語言&#…

C++-指針

在C中&#xff0c;指針是至關重要的組成部分。它是C語言最強大的功能之一&#xff0c;也是最棘手的功能之一。 指針具有強大的能力&#xff0c;其本質是協助程序員完成內存的直接操縱。 指針&#xff1a;特定類型數據在內存中的存儲地址&#xff0c;即內存地址。 指針變量的定…

2024.5組隊學習——MetaGPT(0.8.1)智能體理論與實戰(下):多智能體開發

傳送門&#xff1a; 《2024.5組隊學習——MetaGPT&#xff08;0.8.1&#xff09;智能體理論與實戰&#xff08;上&#xff09;&#xff1a;MetaGPT安裝、單智能體開發》《2024.5組隊學習——MetaGPT&#xff08;0.8.1&#xff09;智能體理論與實戰&#xff08;中&#xff09;&…