map和set的概念及使用

1.什麼是關聯式容器?

  • 關聯式容器也是用來存儲數據的,與序列式容器不同的是,其裏面存儲的是<key, value>結構的鍵值對,在數據檢索時比序列式容器效率更高

2.什麼是鍵值對?

  • 用來表示具有一一對應關係的一種結構,該結構中一般只包含兩個成員變量key和value,key代表鍵值,value表示與key對應的信息
SGI-STL中對鍵值對的定義
template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;
	T1 first;
	T2 second;
	pair()
	: first(T1())
	, second(T2())
	{}
	pair(const T1& a, const T2& b)
	: first(a)
	, second(b)
	{}
};

3.樹型結構的關聯式

樹型結構的關聯式容器主要有四種:map、set、multimap、multiset四種容器的共同點是:使用平衡搜索樹(即紅黑樹)作爲其底層結果,容器中的元素是一個有序的序列。

3.1 set

3.1.1 set的介紹

  1. set是按照一定次序存儲元素的容器
  2. 在set中,元素的value也標識它(value就是key,類型爲T),並且每個value必須是唯一的。set中的元素不能在容器中修改,但是可以從容器中插入或刪除它們
  3. 在內部,set中的元素總是按照其內部比較對象(類型比較)所指示的特定嚴格弱排序準則進行排序。
  4. set容器通過key訪問單個元素的速度通常比unordered_set容器慢,但它們允許根據順序對子集進行直接迭代
  5. set在底層是用二叉搜索樹(紅黑樹)實現的。

3.1.2 set的使用

1.set的模板參數使用

在這裏插入圖片描述

T: set中存放元素的類型,實際在底層存儲<value, value>的鍵值對。
Compare:set中元素默認按照小於來比較
Alloc:set中元素空間的管理方式,使用STL提供的空間配置器管理

2.set的構造
函數聲明 功能介紹
set (const Compare& comp = Compare(), const Allocator& = Allocator() ); 構造空的set
set (InputIterator first, InputIterator last, const Compare& comp = Compare(), const Allocator& = Allocator() ); 用[first, last)區間中的元素構造set
set ( const set<Key,Compare,Allocator>& x); set的拷貝構造
3.set的迭代器
函數聲明 功能介紹
iterator begin() 返回set中起始位置元素的迭代器
iterator end() 返回set中最後一個元素後面的迭代器
const_iterator cbegin() const 返回set中起始位置元素的const迭代器
const_iterator cend() const 返回set中最後一個元素後面的const迭代器
reverse_iterator rbegin() 返回set第一個元素的反向迭代器,即end
reverse_iterator rend() 返回set最後一個元素下一個位置的反向迭代器,即rbegin
const_reverse_iterator crbegin() const 返回set第一個元素的反向const迭代器,即cend
const_reverse_iterator crend() const 返回set最後一個元素下一個位置的反向const迭代器,即crbegin
4.set的容量
函數聲明 功能介紹
bool empty ( ) const 檢測set是否爲空,空返回true,否則返回true
size_type size() const 返回set中有效元素的個數
5.set的操作修改
函數聲明 功能介紹
pair<iterator,bool> insert ( const value_type& x ) 在set中插入元素x,實際插入的是<x, x>構成的鍵值對,如果插入成功,返回<該元素在set中的位置,true>,如果插入失敗,說明x在set中已經存在,返回<x在set中的位置,false>
void erase ( iterator position ) 刪除set中position位置上的元素
size_type erase ( const key_type& x ) 刪除set中值爲x的元素,返回刪除的元素的個數
void erase ( iterator first, iterator last ) 刪除set中[first, last)區間中的元素
void swap ( set<Key,Compare,Allocator>& st ); 交換set中的元素
void clear ( ) 將set中的元素清空
iterator find ( const key_type& x ) const 返回set中值爲x的元素的位置
size_type count ( const key_type& x ) const 返回set中值爲x的元素的個數
6.set的使用
#include<iostream>
#include <set>
using namespace std;
void TestSet()
{
	// 用數組array中的元素構造set
	int array[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0,3,3,3,3,3,3 };
	set<int> s(array, array + sizeof(array) / sizeof(array[0]));
	cout << s.size() << endl;

	// 正向打印set中的元素,從打印結果中可以看出:set可去重
	for (auto& e : s)
		cout << e << " ";
	cout << endl;

	// 使用迭代器逆向打印set中的元素
	for (auto it = s.rbegin(); it != s.rend(); ++it)
		cout << *it << " ";
	cout << endl;

	// set中值爲3的元素出現了幾次
	cout << s.count(3) << endl;
	s.insert(11);
	s.erase(3);
	set<int>::reverse_iterator rit = s.rbegin();
	while (rit != s.rend()){
		cout << *rit<<" ";
		rit++;
	}
}
int main()
{
	TestSet();
	system("pause");
	return 0;
}

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

3.2 map:

3.2.1 map的介紹

  • map是關聯容器,它按照特定的次序(按照key來比較)存儲由鍵值key和值value組合而成的元素。
  • 在map中,鍵值key通常用於排序和惟一地標識元素,而值value中存儲與此鍵值key關聯的內容。鍵值 key和值value的類型可能不同,並且在map的內部,key與value通過成員類型value_type綁定在一起,爲其取別名稱爲pair: typedef pair value_type;
  • 在內部,map中的元素總是按照鍵值key進行比較排序的。
  • map中通過鍵值訪問單個元素的速度通常比unordered_map容器慢,但map允許根據順序對元素進行 直接迭代(即對map中的元素進行迭代時,可以得到一個有序的序列)。
  • map支持下標訪問符,即在[]中放入key,就可以找到與key對應的value。
  • map通常被實現爲二叉搜索樹(更準確的說:平衡二叉搜索樹(紅黑樹))

3.2.2 map的使用

1. map的模板參數說明

在這裏插入圖片描述

key: 鍵值對中key的類型
T: 鍵值對中value的類型
Compare: 比較器的類型,map中的元素是按照key來比較的,缺省情況下按照小於來比較,一般情況下(內置類型元素)該參數不需要傳遞,如果無法比較時(自定義類型),需要用戶自己顯式傳遞比較規則(一般情況下按照函數指針或者仿函數來傳遞)
Alloc:通過空間配置器來申請底層空間,不需要用戶傳遞,除非用戶不想使用標準庫提供的空間配置器
注意:在使用map時,需要包含頭文件。

2. map的構造
函數聲明 功能介紹
map() 構造一個空的map
3. map的迭代器
函數聲明 功能介紹
begin()和end() begin:首元素的位置,end最後一個元素的下一個位置
cbegin()和cend() 與begin和end意義相同,但cbegin和cend所指向的元素不能修改
rbegin()和rend() 反向迭代器,rbegin在end位置,rend在begin位置,其++和–操作與begin和end操作移動相反
crbegin()和crend() 與rbegin和rend位置相同,操作相同,但crbegin和crend所指向的元素不能修改
4. map的容量和元素訪問
函數聲明 功能簡介
bool empty ( ) const 檢測map中的元素是否爲空,是返回true,否則返回false
size_type size() const 返回map中有效元素的個數
mapped_type& operator[] (const key_type& k) 返回去key對應的value

注意:在元素訪問時,有一個與operator[]類似的操作at()(該函數不常用)函數,都是通過key找到與key對應的value然後返回其引用,不同的是:當key不存在時,operator[]用默認value與key構造鍵值對然後插入,返回該默認value,at()函數直接拋異常。

5. map中元素的修改
函數聲明 功能簡介
pair<iterator,bool> insert ( const value_type& x ) 在map中插入鍵值對x,注意x是一個鍵值對,返回值也是鍵值對:iterator代表新插入元素的位置,bool代表釋放插入成功
void erase ( iterator position ) 刪除position位置上的元素
size_type erase ( const key_type& x ) 刪除鍵值爲x的元素
void erase ( iterator first, iterator last ) 刪除[first, last)區間中的元素
void swap ( map<Key,T,Compare,Allocator>& mp ) 交換兩個map中的元素
void clear ( ) 將map中的元素清空
iterator find ( const key_type& x ) 在map中插入key爲x的元素,找到返回該元素的位置的迭代器,否則返回end
const_iterator find ( const key_type& x ) const 在map中插入key爲x的元素,找到返回該元素的位置的const迭代器,否則返回cend
size_type count ( const key_type& x ) const 返回key爲x的鍵值在map中的個數,注意map中key是唯一的,因此該函數的返回值要麼爲0,要麼爲1,因此也可以用該函數來檢測一個key是否在map中
#include <string>
#include <map>
void TestMap()
{
    map<string, string> m;
 
    // 向map中插入元素的方式:
    // 將鍵值對<"peach","桃子">插入map中,用pair直接來構造鍵值對
    m.insert(pair<string, string>("peach", "桃子"));
 
    // 將鍵值對<"peach","桃子">插入map中,用make_pair函數來構造鍵值對
    m.insert(make_pair("banan", "香蕉"));
    
    // 借用operator[]向map中插入元素
    /*
    operator[]的原理是:
      用<key, T()>構造一個鍵值對,然後調用insert()函數將該鍵值對插入到map中
      如果key已經存在,插入失敗,insert函數返回該key所在位置的迭代器
      如果key不存在,插入成功,insert函數返回新插入元素所在位置的迭代器
      operator[]函數最後將insert返回值鍵值對中的value返回
	*/
    // 將<"apple", "">插入map中,插入成功,返回value的引用,將“蘋果”賦值給該引用結果,
    m["apple"] = "蘋果";
 
    // key不存在時拋異常
    //m.at("waterme") = "水蜜桃";
    cout << m.size() << endl;
 
    // 用迭代器去遍歷map中的元素,可以得到一個按照key排序的序列
    for (auto& e : m)
        cout << e.first << "--->" << e.second << endl;
    cout << endl;
 
    // map中的鍵值對key一定是唯一的,如果key存在將插入失敗
    auto ret = m.insert(make_pair("peach", "桃色"));
    if (ret.second)
        cout << "<peach, 桃色>不在map中, 已經插入" << endl;
    else
        cout << "鍵值爲peach的元素已經存在:" << ret.first->first << "--->" << 
ret.first->second <<" 插入失敗"<< endl;
 
    // 刪除key爲"apple"的元素
    m.erase("apple");
 
    if (1 == m.count("apple"))
        cout << "apple還在" << endl;
    else
        cout << "apple被吃了" << endl;
}

在這裏插入圖片描述

3.3 multiset

3.3.1 multiset的介紹

  1. multiset是按照特定順序存儲元素的容器,其中元素是可以重複的
  2. 在multiset中,元素的value也會識別它(因爲multiset中本身存儲的就是<value, value>組成的鍵值對,因此value本身就是key,key就是value,類型爲T). multiset元素的值不能在容器中進行修改(因爲元素總是const的),但可以從容器中插入或刪除
  3. 在內部,multiset中的元素總是按照其內部比較規則(類型比較)所指示的特定嚴格弱排序準則進行排序。
  4. multiset容器通過key訪問單個元素的速度通常unordered_multiset容器慢,但當使用迭代器遍歷時會得到一個有序序列。
  5. multiset底層結構爲二叉搜索樹(紅黑樹)。

注意:

  • multiset中再底層中存儲的是<value, value>的鍵值對
  • mtltiset的插入接口中只需要插入即可
  • 與set的區別是,multiset中的元素可以重複,set是中value是唯一的
  • 使用迭代器對multiset中的元素進行遍歷,可以得到有序的序列
  • multiset中的元素不能修改
  • 在multiset中找某個元素,時間複雜度爲O(log N)
  • multiset的作用:可以對元素進行排序

3.3.2 multiset的使用

multiset的接口與set接口基本一致。

#include <set>
void TestSet()
{
     int array[] = { 2, 1, 3,2,1,3, 9, 6, 0, 5, 8, 4, 7 };
    
     // 注意:multiset在底層實際存儲的是<int, int>的鍵值對
     multiset<int> s(array, array + sizeof(array)/sizeof(array[0]));
     for (auto& e : s)
         cout << e << " ";
     cout << endl;
     return 0;
}

在這裏插入圖片描述

3.4 multimap

3.4.1 multimap的介紹

  1. Multimaps是關聯式容器,它按照特定的順序,存儲由key和value映射成的鍵值對<key, value>,其中多個鍵值對之間的key是可以重複的。
  2. 在multimap中,通常按照key排序和惟一地標識元素,而映射的value存儲與key關聯的內容。key和value的類型可能不同,通過multimap內部的成員類型value_type組合在一起,value_type是組合key和value的鍵值對:
    cpp typedef pair<const Key, T> value_type;
  3. 在內部,multimap中的元素總是通過其內部比較對象,按照指定的特定嚴格弱排序標準對key進行排序的。
  4. multimap通過key訪問單個元素的速度通常比unordered_multimap容器慢,但是使用迭代器直接遍歷multimap中的元素可以得到關於key有序的序列。
  5. multimap在底層用二叉搜索樹(紅黑樹)來實現。

multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重複的。

3.4.2 multimap的使用

multimap中的接口可以參考map,功能都是類似的。
注意:

  1. multimap中的key是可以重複的。
  2. multimap中的元素默認將key按照小於來比較
  3. multimap中沒有重載operator[]操作。
  4. 使用時與map包含的頭文件相同
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章