红黑树实现——STL中的map
生活随笔
收集整理的這篇文章主要介紹了
红黑树实现——STL中的map
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
From: http://blog.csdn.net/zhongjiekangping/article/details/6934571
紅黑樹實(shí)現(xiàn)——STL中的map
[ 2009-07-24 13:55:31 | 作者: dklkt ] 字號: 大 | 中 | 小 [轉(zhuǎn)載]STL中map實(shí)現(xiàn)技術(shù)來源: http://blog.csdn.net/Fandywang_jlu/archive/2008/03/23/2208363.aspx
紅黑樹是一種自平衡二叉查找樹,是在計算機(jī)科學(xué)中用到的一種數(shù)據(jù)結(jié)構(gòu),典型的用途是實(shí)現(xiàn)關(guān)聯(lián)數(shù)組。它是在1972年由Rudolf?Bayer發(fā)明的,他稱之為"對稱二叉B樹",它現(xiàn)代的名字是在?Leo?J.?Guibas?和?Robert?Sedgewick?于1978年寫的一篇論文中獲得的。它是復(fù)雜的,但它的操作有著良好的最壞情況運(yùn)行時間,并且在實(shí)踐中是高效的:?它可以在O(log?n)時間內(nèi)做查找,插入和刪除,這里的n?是樹中元素的數(shù)目。
紅黑樹是一種很有意思的平衡檢索樹。它的統(tǒng)計性能要好于平衡二叉樹(有些書籍根據(jù)作者姓名,Adelson-Velskii和Landis,將其稱為?AVL-樹),因此,紅黑樹在很多地方都有應(yīng)用。在C++?STL中,很多部分(目前包括set,?multiset,?map,?multimap)應(yīng)用了紅黑樹的變體(SGI?STL中的紅黑樹有一些變化,這些修改提供了更好的性能,以及對set操作的支持)。
背景和術(shù)語
紅黑樹是一種特定類型的二叉樹,它是在計算機(jī)科學(xué)中用來組織數(shù)據(jù)比如數(shù)字的塊的一種結(jié)構(gòu)。所有數(shù)據(jù)塊都存儲在節(jié)點(diǎn)中。這些節(jié)點(diǎn)中的某一個節(jié)點(diǎn)總是擔(dān)當(dāng)啟始位置的功能,它不是任何節(jié)點(diǎn)的兒子;我們稱之為根節(jié)點(diǎn)或根。它有最多兩個"兒子",都是它連接到的其他節(jié)點(diǎn)。所有這些兒子都可以有自己的兒子,以此類推。這樣根節(jié)點(diǎn)就有了把它連接到在樹中任何其他節(jié)點(diǎn)的路徑。
如果一個節(jié)點(diǎn)沒有兒子,我們稱之為葉子節(jié)點(diǎn),因?yàn)樵谥庇X上它是在樹的邊緣上。子樹是從特定節(jié)點(diǎn)可以延伸到的樹的某一部分,其自身被當(dāng)作一個樹。在紅黑樹中,葉子被假定為?null?或空。
由于紅黑樹也是二叉查找樹,它們當(dāng)中每一個節(jié)點(diǎn)都的比較值都必須大于或等于在它的左子樹中的所有節(jié)點(diǎn),并且小于或等于在它的右子樹中的所有節(jié)點(diǎn)。這確保紅黑樹運(yùn)作時能夠快速的在樹中查找給定的值。
用途和好處
紅黑樹和AVL樹一樣都對插入時間、刪除時間和查找時間提供了最好可能的最壞情況擔(dān)保。這不只是使它們在時間敏感的應(yīng)用如即時應(yīng)用(real?time?application)中有價值,而且使它們有在提供最壞情況擔(dān)保的其他數(shù)據(jù)結(jié)構(gòu)中作為建造板塊的價值;例如,在計算幾何中使用的很多數(shù)據(jù)結(jié)構(gòu)都可以基于紅黑樹。
紅黑樹在函數(shù)式編程中也特別有用,在這里它們是最常用的持久數(shù)據(jù)結(jié)構(gòu)之一,它們用來構(gòu)造關(guān)聯(lián)數(shù)組和集合,在突變之后它們能保持為以前的版本。除了O(log?n)的時間之外,紅黑樹的持久版本對每次插入或刪除需要O(log?n)的空間。
紅黑樹是?2-3-4樹的一種等同。換句話說,對于每個?2-3-4?樹,都存在至少一個數(shù)據(jù)元素是同樣次序的紅黑樹。在?2-3-4?樹上的插入和刪除操作也等同于在紅黑樹中顏色翻轉(zhuǎn)和旋轉(zhuǎn)。這使得?2-3-4?樹成為理解紅黑樹背后的邏輯的重要工具,這也是很多介紹算法的教科書在紅黑樹之前介紹?2-3-4?樹的原因,盡管?2-3-4?樹在實(shí)踐中不經(jīng)常使用。
屬性
紅黑樹是每個節(jié)點(diǎn)都有顏色特性的二叉查找樹,顏色的值是紅色或黑色之一。除了二叉查找樹帶有的一般要求,我們對任何有效的紅黑樹加以如下增補(bǔ)要求:
1.節(jié)點(diǎn)是紅色或黑色。
2.根是黑色。
3.所有葉子(外部節(jié)點(diǎn))都是黑色。
4.每個紅色節(jié)點(diǎn)的兩個子節(jié)點(diǎn)都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續(xù)的紅色節(jié)點(diǎn))
5.從每個葉子到根的所有路徑都包含相同數(shù)目的黑色節(jié)點(diǎn)。
這些約束強(qiáng)制了紅黑樹的關(guān)鍵屬性:?從根到葉子的最長的可能路徑不多于最短的可能路徑的兩倍長。結(jié)果是這個樹大致上是平衡的。因?yàn)椴僮鞅热绮迦?、刪除和查找某個值都要求與樹的高度成比例的最壞情況時間,這個在高度上的理論上限允許紅黑樹在最壞情況下都是高效的,而不同于普通的二叉查找樹。
要知道為什么這些特性確保了這個結(jié)果,注意到屬性4導(dǎo)致了路徑不能有兩個毗連的紅色節(jié)點(diǎn)就足夠了。最短的可能路徑都是黑色節(jié)點(diǎn),最長的可能路徑有交替的紅色和黑色節(jié)點(diǎn)。因?yàn)楦鶕?jù)屬性5所有最長的路徑都有相同數(shù)目的黑色節(jié)點(diǎn),這就表明了沒有路徑能多于任何其他路徑的兩倍長。
在很多樹數(shù)據(jù)結(jié)構(gòu)的表示中,一個節(jié)點(diǎn)有可能只有一個兒子,而葉子節(jié)點(diǎn)包含數(shù)據(jù)。用這種范例表示紅黑樹是可能的,但是這會改變一些屬性并使算法復(fù)雜。為此,本文中我們使用?"nil?葉子"?或"空(null)葉子",如上圖所示,它不包含數(shù)據(jù)而只充當(dāng)樹在此結(jié)束的指示。這些節(jié)點(diǎn)在繪圖中經(jīng)常被省略,導(dǎo)致了這些樹好像同上述原則相矛盾,而實(shí)際上不是這樣。與此有關(guān)的結(jié)論是所有節(jié)點(diǎn)都有兩個兒子,盡管其中的一個或兩個可能是空葉子。
操作
在紅黑樹上只讀操作不需要對用于二叉查找樹的操作做出修改,因?yàn)樗捕娌檎覙?。但?#xff0c;在插入和刪除之后,紅黑屬性可能變得違規(guī)?;謴?fù)紅黑屬性需要少量(O(log?n))的顏色變更(這在實(shí)踐中是非??焖俚?并且不超過三次樹旋轉(zhuǎn)(對于插入是兩次)。這允許插入和刪除保持為?O(log?n)?次,但是它導(dǎo)致了非常復(fù)雜的操作。
STL中的另一個類hash?map是通過使用hash表來構(gòu)造map的
參考: http://baike.baidu.com/view/133754.htm
對于STL中的具體實(shí)現(xiàn)可以參考《STL?源碼剖析》
208頁?5.2?RB-tree(紅黑樹)
237頁?5.4?map
=========================================================
[轉(zhuǎn)載]STL?map常用操作簡介?
來源: http://www.cnblogs.com/TianFang/archive/2006/12/30/607859.html
1。目錄?
map簡介?
map的功能?
使用map?
在map中插入元素?
查找并獲取map中的元素?
從map中刪除元素?
2。map簡介?
map是一類關(guān)聯(lián)式容器。它的特點(diǎn)是增加和刪除節(jié)點(diǎn)對迭代器的影響很小,除了那個操作節(jié)點(diǎn),對其他的節(jié)點(diǎn)都沒有什么影響。對于迭代器來說,可以修改實(shí)值,而不能修改key。?
3。map的功能?
自動建立Key?-?value的對應(yīng)。key?和?value可以是任意你需要的類型。?
根據(jù)key值快速查找記錄,查找的復(fù)雜度基本是Log(N),如果有1000個記錄,最多查找10次,1,000,000個記錄,最多查找20次。?
快速插入Key?-?Value?記錄。?
快速刪除記錄?
根據(jù)Key?修改value記錄。?
遍歷所有記錄。?
4。使用map?
使用map得包含map類所在的頭文件
#include?<map>?//注意,STL頭文件沒有擴(kuò)展名.h?
map對象是模板類,需要關(guān)鍵字和存儲對象兩個模板參數(shù):
std:map<int,?string>?personnel;
這樣就定義了一個用int作為索引,并擁有相關(guān)聯(lián)的指向string的指針.?
為了使用方便,可以對模板類進(jìn)行一下類型定義,?
typedef?map<int,?CString>?UDT_MAP_INT_CSTRING;?
UDT_MAP_INT_CSTRING?enumMap;?
5。在map中插入元素?
改變map中的條目非常簡單,因?yàn)閙ap類已經(jīng)對[]操作符進(jìn)行了重載?
enumMap[1]?=?"One";
enumMap[2]?=?"Two";
.....?
這樣非常直觀,但存在一個性能的問題。插入2時,先在enumMap中查找主鍵為2的項(xiàng),沒發(fā)現(xiàn),然后將一個新的對象插入enumMap,鍵是2,值是一個空字符串,插入完成后,將字符串賦為"Two";?該方法會將每個值都賦為缺省值,然后再賦為顯示的值,如果元素是類對象,則開銷比較大。我們可以用以下方法來避免開銷:?
enumMap.insert(map<int,?CString>?::?value_type(2,?"Two"))?
6。查找并獲取map中的元素?
下標(biāo)操作符給出了獲得一個值的最簡單方法:?
CString?tmp?=?enumMap[2];?
但是,只有當(dāng)map中有這個鍵的實(shí)例時才對,否則會自動插入一個實(shí)例,值為初始化值。?
我們可以使用Find()和Count()方法來發(fā)現(xiàn)一個鍵是否存在。?
查找map中是否包含某個關(guān)鍵字條目用find()方法,傳入的參數(shù)是要查找的key,在這里需要提到的是begin()和end()兩個成員,分別代表map對象中第一個條目和最后一個條目,這兩個數(shù)據(jù)的類型是iterator.?
int?nFindKey?=?2;????????????//要查找的Key
//定義一個條目變量(實(shí)際是指針)
UDT_MAP_INT_CSTRING::iterator?it=?enumMap.find(nFindKey);?
if(it?==?enumMap.end())?{
????//沒找到
}
else?{
????//找到
}?
通過map對象的方法獲取的iterator數(shù)據(jù)類型是一個std::pair對象,包括兩個數(shù)據(jù)?iterator->first?和?iterator->second?分別代表關(guān)鍵字和存儲的數(shù)據(jù)?
7。從map中刪除元素?
移除某個map中某個條目用erase()?
該成員方法的定義如下?
iterator?erase(iterator?it);?//通過一個條目對象刪除?
iterator?erase(iterator?first,?iterator?last);????????//刪除一個范圍?
size_type?erase(const?Key&?key);?//通過關(guān)鍵字刪除?
clear()就相當(dāng)于?enumMap.erase(enumMap.begin(),?enumMap.end());
=========================================================
[轉(zhuǎn)載]STL中map用法詳解
來源: http://www.kuqin.com/cpluspluslib/20071231/3265.html
Map是STL的一個關(guān)聯(lián)容器,它提供一對一(其中第一個可以稱為關(guān)鍵字,每個關(guān)鍵字只能在map中出現(xiàn)一次,第二個可能稱為該關(guān)鍵字的值)的數(shù)據(jù)處理能力,由于這個特性,它完成有可能在我們處理一對一數(shù)據(jù)的時候,在編程上提供快速通道。這里說下map內(nèi)部數(shù)據(jù)的組織,map內(nèi)部自建一顆紅黑樹(一種非嚴(yán)格意義上的平衡二叉樹),這顆樹具有對數(shù)據(jù)自動排序的功能,所以在map內(nèi)部所有的數(shù)據(jù)都是有序的,后邊我們會見識到有序的好處。
下面舉例說明什么是一對一的數(shù)據(jù)映射。比如一個班級中,每個學(xué)生的學(xué)號跟他的姓名就存在著一一映射的關(guān)系,這個模型用map可能輕易描述,很明顯學(xué)號用int描述,姓名用字符串描述(本篇文章中不用char?*來描述字符串,而是采用STL中string來描述),下面給出map描述代碼:
Map<int,?string>?mapStudent;
1.???????map的構(gòu)造函數(shù)
map共提供了6個構(gòu)造函數(shù),這塊涉及到內(nèi)存分配器這些東西,略過不表,在下面我們將接觸到一些map的構(gòu)造方法,這里要說下的就是,我們通常用如下方法構(gòu)造一個map:
Map<int,?string>?mapStudent;
2.???????數(shù)據(jù)的插入
在構(gòu)造map容器后,我們就可以往里面插入數(shù)據(jù)了。這里講三種插入數(shù)據(jù)的方法:
第一種:用insert函數(shù)插入pair數(shù)據(jù),下面舉例說明(以下代碼雖然是隨手寫的,應(yīng)該可以在VC和GCC下編譯通過,大家可以運(yùn)行下看什么效果,在VC下請加入這條語句,屏蔽4786警告??#pragma?warning?(disable:4786)?)
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent.insert(pair<int,?string>(1,?“student_one”));
???????mapStudent.insert(pair<int,?string>(2,?“student_two”));
???????mapStudent.insert(pair<int,?string>(3,?“student_three”));
???????map<int,?string>::iterator??iter;
???????for(iter?=?mapStudent.begin();?iter?!=?mapStudent.end();?iter++)
{
???????Cout<<iter->first<<”???”<<iter->second<<end;
}
}
第二種:用insert函數(shù)插入value_type數(shù)據(jù),下面舉例說明
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent.insert(map<int,?string>::value_type?(1,?“student_one”));
???????mapStudent.insert(map<int,?string>::value_type?(2,?“student_two”));
???????mapStudent.insert(map<int,?string>::value_type?(3,?“student_three”));
???????map<int,?string>::iterator??iter;
???????for(iter?=?mapStudent.begin();?iter?!=?mapStudent.end();?iter++)
{
???????Cout<<iter->first<<”???”<<iter->second<<end;
}
}
第三種:用數(shù)組方式插入數(shù)據(jù),下面舉例說明
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent[1]?=??“student_one”;
???????mapStudent[2]?=??“student_two”;
???????mapStudent[3]?=??“student_three”;
???????map<int,?string>::iterator??iter;
???????for(iter?=?mapStudent.begin();?iter?!=?mapStudent.end();?iter++)
{
???????Cout<<iter->first<<”???”<<iter->second<<end;
}
}
以上三種用法,雖然都可以實(shí)現(xiàn)數(shù)據(jù)的插入,但是它們是有區(qū)別的,當(dāng)然了第一種和第二種在效果上是完成一樣的,用insert函數(shù)插入數(shù)據(jù),在數(shù)據(jù)的插入上涉及到集合的唯一性這個概念,即當(dāng)map中有這個關(guān)鍵字時,insert操作是插入數(shù)據(jù)不了的,但是用數(shù)組方式就不同了,它可以覆蓋以前該關(guān)鍵字對應(yīng)的值,用程序說明
mapStudent.insert(map<int,?string>::value_type?(1,?“student_one”));
mapStudent.insert(map<int,?string>::value_type?(1,?“student_two”));
上面這兩條語句執(zhí)行后,map中1這個關(guān)鍵字對應(yīng)的值是“student_one”,第二條語句并沒有生效,那么這就涉及到我們怎么知道insert語句是否插入成功的問題了,可以用pair來獲得是否插入成功,程序如下
Pair<map<int,?string>::iterator,?bool>?Insert_Pair;
Insert_Pair?=?mapStudent.insert(map<int,?string>::value_type?(1,?“student_one”));
我們通過pair的第二個變量來知道是否插入成功,它的第一個變量返回的是一個map的迭代器,如果插入成功的話Insert_Pair.second應(yīng)該是true的,否則為false。
下面給出完成代碼,演示插入成功與否問題
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
Pair<map<int,?string>::iterator,?bool>?Insert_Pair;
???????Insert_Pair?=?mapStudent.insert(pair<int,?string>(1,?“student_one”));
???????If(Insert_Pair.second?==?true)
???????{
??????????????Cout<<”Insert?Successfully”<<endl;
???????}
???????Else
???????{
??????????????Cout<<”Insert?Failure”<<endl;
???????}
???????Insert_Pair?=?mapStudent.insert(pair<int,?string>(1,?“student_two”));
???????If(Insert_Pair.second?==?true)
???????{
??????????????Cout<<”Insert?Successfully”<<endl;
???????}
???????Else
???????{
??????????????Cout<<”Insert?Failure”<<endl;
???????}
???????map<int,?string>::iterator??iter;
???????for(iter?=?mapStudent.begin();?iter?!=?mapStudent.end();?iter++)
{
???????Cout<<iter->first<<”???”<<iter->second<<end;
}
}
大家可以用如下程序,看下用數(shù)組插入在數(shù)據(jù)覆蓋上的效果
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent[1]?=??“student_one”;
???????mapStudent[1]?=??“student_two”;
???????mapStudent[2]?=??“student_three”;
???????map<int,?string>::iterator??iter;
???????for(iter?=?mapStudent.begin();?iter?!=?mapStudent.end();?iter++)
{
???????Cout<<iter->first<<”???”<<iter->second<<end;
}
}
3.???????map的大小
在往map里面插入了數(shù)據(jù),我們怎么知道當(dāng)前已經(jīng)插入了多少數(shù)據(jù)呢,可以用size函數(shù),用法如下:
Int?nSize?=?mapStudent.size();
4.???????數(shù)據(jù)的遍歷
這里也提供三種方法,對map進(jìn)行遍歷
第一種:應(yīng)用前向迭代器,上面舉例程序中到處都是了,略過不表
第二種:應(yīng)用反相迭代器,下面舉例說明,要體會效果,請自個動手運(yùn)行程序
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent.insert(pair<int,?string>(1,?“student_one”));
???????mapStudent.insert(pair<int,?string>(2,?“student_two”));
???????mapStudent.insert(pair<int,?string>(3,?“student_three”));
???????map<int,?string>::reverse_iterator??iter;
???????for(iter?=?mapStudent.rbegin();?iter?!=?mapStudent.rend();?iter++)
{
???????Cout<<iter->first<<”???”<<iter->second<<end;
}
}
第三種:用數(shù)組方式,程序說明如下
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent.insert(pair<int,?string>(1,?“student_one”));
???????mapStudent.insert(pair<int,?string>(2,?“student_two”));
???????mapStudent.insert(pair<int,?string>(3,?“student_three”));
???????int?nSize?=?mapStudent.size()
//此處有誤,應(yīng)該是?for(int?nIndex?=?1;?nIndex?<=?nSize;?nIndex++)?
//by?rainfish
???????for(int?nIndex?=?0;?nIndex?<?nSize;?nIndex++)
{
???????Cout<<mapStudent[nIndex]<<end;
}
}
5.???????數(shù)據(jù)的查找(包括判定這個關(guān)鍵字是否在map中出現(xiàn))
在這里我們將體會,map在數(shù)據(jù)插入時保證有序的好處。
要判定一個數(shù)據(jù)(關(guān)鍵字)是否在map中出現(xiàn)的方法比較多,這里標(biāo)題雖然是數(shù)據(jù)的查找,在這里將穿插著大量的map基本用法。
這里給出三種數(shù)據(jù)查找方法
第一種:用count函數(shù)來判定關(guān)鍵字是否出現(xiàn),其缺點(diǎn)是無法定位數(shù)據(jù)出現(xiàn)位置,由于map的特性,一對一的映射關(guān)系,就決定了count函數(shù)的返回值只有兩個,要么是0,要么是1,出現(xiàn)的情況,當(dāng)然是返回1了
第二種:用find函數(shù)來定位數(shù)據(jù)出現(xiàn)位置,它返回的一個迭代器,當(dāng)數(shù)據(jù)出現(xiàn)時,它返回數(shù)據(jù)所在位置的迭代器,如果map中沒有要查找的數(shù)據(jù),它返回的迭代器等于end函數(shù)返回的迭代器,程序說明
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent.insert(pair<int,?string>(1,?“student_one”));
???????mapStudent.insert(pair<int,?string>(2,?“student_two”));
???????mapStudent.insert(pair<int,?string>(3,?“student_three”));
???????map<int,?string>::iterator?iter;
???????iter?=?mapStudent.find(1);
if(iter?!=?mapStudent.end())
{
???????Cout<<”Find,?the?value?is?”<<iter->second<<endl;
}
Else
{
???????Cout<<”Do?not?Find”<<endl;
}
}
第三種:這個方法用來判定數(shù)據(jù)是否出現(xiàn),是顯得笨了點(diǎn),但是,我打算在這里講解
Lower_bound函數(shù)用法,這個函數(shù)用來返回要查找關(guān)鍵字的下界(是一個迭代器)
Upper_bound函數(shù)用法,這個函數(shù)用來返回要查找關(guān)鍵字的上界(是一個迭代器)
例如:map中已經(jīng)插入了1,2,3,4的話,如果lower_bound(2)的話,返回的2,而upper-bound(2)的話,返回的就是3
Equal_range函數(shù)返回一個pair,pair里面第一個變量是Lower_bound返回的迭代器,pair里面第二個迭代器是Upper_bound返回的迭代器,如果這兩個迭代器相等的話,則說明map中不出現(xiàn)這個關(guān)鍵字,程序說明
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent[1]?=??“student_one”;
???????mapStudent[3]?=??“student_three”;
???????mapStudent[5]?=??“student_five”;
???????map<int,?string>::iterator??iter;
iter?=?mapStudent.lower_bound(2);
{
???????//返回的是下界3的迭代器
???????Cout<<iter->second<<endl;
}
iter?=?mapStudent.lower_bound(3);
{
???????//返回的是下界3的迭代器
???????Cout<<iter->second<<endl;
}
?
iter?=?mapStudent.upper_bound(2);
{
???????//返回的是上界3的迭代器
???????Cout<<iter->second<<endl;
}
iter?=?mapStudent.upper_bound(3);
{
???????//返回的是上界5的迭代器
???????Cout<<iter->second<<endl;
}
?
Pair<map<int,?string>::iterator,?map<int,?string>::iterator>?mapPair;
mapPair?=?mapStudent.equal_range(2);
if(mapPair.first?==?mapPair.second)
???????{
???????cout<<”Do?not?Find”<<endl;
}
Else
{
Cout<<”Find”<<endl;
}
mapPair?=?mapStudent.equal_range(3);
if(mapPair.first?==?mapPair.second)
???????{
???????cout<<”Do?not?Find”<<endl;
}
Else
{
Cout<<”Find”<<endl;
}
}
6.???????數(shù)據(jù)的清空與判空
清空map中的數(shù)據(jù)可以用clear()函數(shù),判定map中是否有數(shù)據(jù)可以用empty()函數(shù),它返回true則說明是空map
7.???????數(shù)據(jù)的刪除
這里要用到erase函數(shù),它有三個重載了的函數(shù),下面在例子中詳細(xì)說明它們的用法
#include?<map>
#include?<string>
#include?<iostream>
Using?namespace?std;
Int?main()
{
???????Map<int,?string>?mapStudent;
???????mapStudent.insert(pair<int,?string>(1,?“student_one”));
???????mapStudent.insert(pair<int,?string>(2,?“student_two”));
???????mapStudent.insert(pair<int,?string>(3,?“student_three”));
?
//如果你要演示輸出效果,請選擇以下的一種,你看到的效果會比較好
???????//如果要刪除1,用迭代器刪除
???????map<int,?string>::iterator?iter;
???????iter?=?mapStudent.find(1);
???????mapStudent.erase(iter);
?
???????//如果要刪除1,用關(guān)鍵字刪除
???????Int?n?=?mapStudent.erase(1);//如果刪除了會返回1,否則返回0
?
???????//用迭代器,成片的刪除
???????//一下代碼把整個map清空
???????mapStudent.earse(mapStudent.begin(),?mapStudent.end());
???????//成片刪除要注意的是,也是STL的特性,刪除區(qū)間是一個前閉后開的集合
?
???????//自個加上遍歷代碼,打印輸出吧
}
8.???????其他一些函數(shù)用法
這里有swap,key_comp,value_comp,get_allocator等函數(shù),感覺到這些函數(shù)在編程用的不是很多,略過不表,有興趣的話可以自個研究
9.???????排序
這里要講的是一點(diǎn)比較高深的用法了,排序問題,STL中默認(rèn)是采用小于號來排序的,以上代碼在排序上是不存在任何問題的,因?yàn)樯厦娴年P(guān)鍵字是int型,它本身支持小于號運(yùn)算,在一些特殊情況,比如關(guān)鍵字是一個結(jié)構(gòu)體,涉及到排序就會出現(xiàn)問題,因?yàn)樗鼪]有小于號操作,insert等函數(shù)在編譯的時候過不去,下面給出兩個方法解決這個問題
第一種:小于號重載,程序舉例
#include?<map>
#include?<string>
Using?namespace?std;
Typedef?struct?tagStudentInfo
{
???????Int??????nID;
???????String???strName;
}StudentInfo,?*PStudentInfo;??//學(xué)生信息
?
Int?main()
{
????int?nSize;
???????//用學(xué)生信息映射分?jǐn)?shù)
???????map<StudentInfo,?int>mapStudent;
????map<StudentInfo,?int>::iterator?iter;
???????StudentInfo?studentInfo;
???????studentInfo.nID?=?1;
???????studentInfo.strName?=?“student_one”;
???????mapStudent.insert(pair<StudentInfo,?int>(studentInfo,?90));
???????studentInfo.nID?=?2;
???????studentInfo.strName?=?“student_two”;
mapStudent.insert(pair<StudentInfo,?int>(studentInfo,?80));
?
for?(iter=mapStudent.begin();?iter!=mapStudent.end();?iter++)
????cout<<iter->first.nID<<endl<<iter->first.strName<<endl<<iter->second<<endl;
?
}
以上程序是無法編譯通過的,只要重載小于號,就OK了,如下:
Typedef?struct?tagStudentInfo
{
???????Int??????nID;
???????String???strName;
???????Bool?operator?<?(tagStudentInfo?const&?_A)?const
???????{
??????????????//這個函數(shù)指定排序策略,按nID排序,如果nID相等的話,按strName排序
??????????????If(nID?<?_A.nID)??return?true;
??????????????If(nID?==?_A.nID)?return?strName.compare(_A.strName)?<?0;
??????????????Return?false;
???????}
}StudentInfo,?*PStudentInfo;??//學(xué)生信息
第二種:仿函數(shù)的應(yīng)用,這個時候結(jié)構(gòu)體中沒有直接的小于號重載,程序說明
#include?<map>
#include?<string>
Using?namespace?std;
Typedef?struct?tagStudentInfo
{
???????Int??????nID;
???????String???strName;
}StudentInfo,?*PStudentInfo;??//學(xué)生信息
?
Classs?sort
{
???????Public:
???????Bool?operator()?(StudentInfo?const?&_A,?StudentInfo?const?&_B)?const
???????{
??????????????If(_A.nID?<?_B.nID)?return?true;
??????????????If(_A.nID?==?_B.nID)?return?_A.strName.compare(_B.strName)?<?0;
??????????????Return?false;
???????}
};
?
Int?main()
{
???????//用學(xué)生信息映射分?jǐn)?shù)
???????Map<StudentInfo,?int,?sort>mapStudent;
???????StudentInfo?studentInfo;
???????studentInfo.nID?=?1;
???????studentInfo.strName?=?“student_one”;
???????mapStudent.insert(pair<StudentInfo,?int>(studentInfo,?90));
???????studentInfo.nID?=?2;
???????studentInfo.strName?=?“student_two”;
mapStudent.insert(pair<StudentInfo,?int>(studentInfo,?80));
}
10.???另外
由于STL是一個統(tǒng)一的整體,map的很多用法都和STL中其它的東西結(jié)合在一起,比如在排序上,這里默認(rèn)用的是小于號,即less<>,如果要從大到小排序呢,這里涉及到的東西很多,在此無法一一加以說明。
還要說明的是,map中由于它內(nèi)部有序,由紅黑樹保證,因此很多函數(shù)執(zhí)行的時間復(fù)雜度都是log2N的,如果用map函數(shù)可以實(shí)現(xiàn)的功能,而STL??Algorithm也可以完成該功能,建議用map自帶函數(shù),效率高一些。
下面說下,map在空間上的特性,否則,估計你用起來會有時候表現(xiàn)的比較郁悶,由于map的每個數(shù)據(jù)對應(yīng)紅黑樹上的一個節(jié)點(diǎn),這個節(jié)點(diǎn)在不保存你的數(shù)據(jù)時,是占用16個字節(jié)的,一個父節(jié)點(diǎn)指針,左右孩子指針,還有一個枚舉值(標(biāo)示紅黑的,相當(dāng)于平衡二叉樹中的平衡因子),我想大家應(yīng)該知道,這些地方很費(fèi)內(nèi)存了吧,不說了……
============================================================
[轉(zhuǎn)載]MSDN
Standard?C++?Library?Reference??
map::insert,?map::find,?and?map::end??
See?Also??Example?
?Collapse?All?Expand?All????Language?Filter:?All?Language?Filter:?Multiple?Language?Filter:?Visual?Basic?Language?Filter:?C#?Language?Filter:?C++?Language?Filter:?J#?Language?Filter:?JScript??
?Visual?Basic?(Declaration)?
?Visual?Basic?(Usage)?
?C#?
?C++?
?J#?
?JScript?
Illustrates?how?to?use?the?map::insert,?map::find,?and?map::end?Standard?Template?Library?(STL)?functions?in?Visual?C++.
?
iterator?map::end(?);?
iterator?map::find(
???const?Key&?Key
);
pair<iterator,?bool>?
map::insert(
???const?value_type&?x
);
?
Remarks
Note??
The?class/parameter?names?in?the?prototype?do?not?match?the?version?in?the?header?file.?Some?have?been?modified?to?improve?readability.
?
The?end?function?returns?an?iterator?that?points?one?past?the?end?of?a?sequence.?find?returns?an?iterator?that?designates?the?first?element?whose?sort?key?equals?Key.?If?no?such?element?exists,?the?iterator?equals?end.?If?the?key?does?not?already?exist,?insert?will?add?it?to?the?sequence?and?return?pair<iterator,?true>.?If?the?key?already?exists,?insert?does?not?add?it?to?the?sequence?and?returns?pair?<iterator,?false>.?The?following?sample?creates?a?map?of?ints?to?strings.?In?this?case,?the?mapping?is?from?digits?to?their?string?equivalents?(1?->?"One",?2?->?"Two",?and?so?on).?The?program?reads?a?number?from?the?user,?finds?the?word?equivalent?for?each?digit?(using?the?map),?and?prints?the?number?back?as?a?series?of?words.?For?example,?if?the?user?enters?25463,?the?program?responds?with:?Two?Five?Four?Six?Three.?
Example
??Copy?Code view plaincopy to clipboardprint?
??
12
q
?
Sample?Output
??Copy?Code?
Enter?"q"?to?quit,?or?enter?a?Number:?12
One?Two
Enter?"q"?to?quit,?or?enter?a?Number:?q
?
Requirements
Header:?<map>
See?Also
Concepts
Standard?Template?Library?Samples
?To?make?a?suggestion?or?report?a?bug?about?Help?or?another?feature?of?this?product,?go?to?the?feedback?site.?
================================================================
Illustrates?how?to?use?the?map::max_size,?map::clear,?map::erase,?and?map::size?Standard?Template?Library?(STL)?functions?in?Visual?C++.
?
size_type?max_size(?)?const;?
void?clear(?)?const;?
bool?empty(?)?const;?
iterator?erase(
???iterator?First,
???iterator?Last
);
size_type?size(?)?const;
A::reference?operator[](?????????//?A?is?the?allocator
???const?Key&?Key
);?
iterator?map::begin(?);
iterator?map::end(?);
iterator?map::find(
???const?Key&?Key
);
?
Remarks
Note??
The?class/parameter?names?in?the?prototype?do?not?match?the?version?in?the?header?file.?Some?have?been?modified?to?improve?readability.
?
The?following?sample?creates?a?map?of?strings?to?ints?and?fills?it?first?with?a?map?of?month?names?to?month?numbers,?and?then?empties?and?refills?it?with?a?map?of?weekday?names?to?corresponding?ints.?
Example
??Copy?Code? view plaincopy to clipboardprint?
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎
總結(jié)
以上是生活随笔為你收集整理的红黑树实现——STL中的map的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CNKI知网笔记
- 下一篇: 码栈开发手册(一)---编码方式开发(初