C++關聯容器知識總結


  C++的容器類型可以分為順序容器和關聯容器兩大類。順序容器的知識可以參看我上篇的隨筆《C++順序容器知識總結》。關聯容器支持通過鍵值來高效的查找和讀取元素,這是它和順序容器最大的區別。兩種基本的關聯容器類型是map和set。map的元素以鍵-值對的形式組織:鍵用作元素在map中的索引,而值則表示所存儲和讀取的數據。set僅包含一個鍵,並有效的支持關於某個鍵是否存在的查詢。下表是關聯容器的類型:

map                      關聯數組;元素通過鍵來存儲和讀取
set                      大小可變的集合,支持通過鍵實現快速讀取
multimap                 支持同一個鍵多次出現的map類型
multiset                 支持同一個鍵多次出現的set類型

 

一.pair類型

  在開始介紹關聯容器之前,我們需要了解一種與之相關的標准庫類型——pair類型,該類型定義在頭文件utilty中。下表是pair類型提供的操作。

pair<T1,T2>    p1;                     創建一個空的pair對象,它的兩個元素分別是T1和T2類型,采用值初始化
pair<T1,T2>    p1(v1,v2);              創建一個pair對象,它的兩個元素分別是T1和T2類型,其中first成員初始化為v2,second成員初始化為v2。
make_pair(v1,v2)                       以v1,v2值創建一個新的pair對象,其元素類型分別是v1,v2類型
p1<p2                                  兩個pair對象之間的小於運算,遵循字典順序
p1==p2                                 如果兩個pair對象的first和second值依次相等,則它們相等
p.first                                返回p中名為first的數據成員
p.second                               返回p中名為second的數據成員

  可以看到,和容器一樣,pair也是一種模板類型。它的數據成員是公有的,分別命名為first和second,只需點操作就可以訪問其成員。其定義初始化的操作也很簡單,除了構造函數外,pair還提供了一個make_pair函數來創建pair對象,並賦值給已存在的pair對象。

  

pair<string,string>    next_auth;
string    first,last;
while(cin>>first>>last)
    next_auth=make_pair(first,last);
//上面的賦值操作等效於下面這條語句
next_auth=pair<string,string>(first,last);

二.map類型

  map是鍵-值對的集合。map類型可以理解為關聯數組:可以使用鍵作為下標來獲取一個值,正如內置數組類型一樣。map和set等關聯容器共享大部分順序容器的操作。關聯容器不提供front、push_front、pop_front、back、push_back和pop_back操作。

1.map對象的定義

  在使用map對象之前,需要在頭文件中包含map頭。其定義示例如下:

#include<map>
map<string,int>  word_count;    

  此外,map還共有3種構造函數用於定義和初始化。

map<k,v>    m;                 創建一個名為m的空map對象,其鍵和值類型分別為k和v類型
map<k,v>    m(m2);             創建一個m2的副本m,m和m2必須要有相同的鍵和值類型
map<k,v>    m(b,e);            創建map類型的對象m,存儲迭代器b和e標記范圍內所有元素的副本。元素的類型必須能轉換位pair<const k,v>

  

2.map定義的類型

  由於map對象的元素是鍵-值對,即每個元素包含兩個部分:鍵以及由鍵關聯的值。vaule_type是存儲元素的鍵以及值得pair類型,而且鍵位const。下表為map類定義的類型。

map<K,V>::key_type               在map容器中,用作索引的鍵的類型
map<K,V>::mapped_type            在map容器中,鍵所關聯的值的類型
map<K,V>::value_type             一個pair類型。它的first元素具有const map<K,V>::key_type 類型,而second元素具有map<K,V>::mapped_type類型

  注意對map迭代器進行解引用將產生的是pair類型的對象,它的first成員存放的是鍵,為const,second成員存放的是值。

3.map中添加元素

  給map添加元素有兩種方式:一是使用insert成員實現。二是先用下標獲取元素,讓然后給獲取的元素賦值。

  map使用下標和vector類似,返回的都是下標關聯的值,但是map的下標是鍵而不是遞增的數字。下面的程序很好的說明了這個特點。

map<string,int>    word_count;
word_count["Anna"]=1;

  首先在word_count中查找鍵為Anna的元素,沒有找到。接着將一個新的鍵-值對插入到word_count容器中,鍵為Anna,值初始化為0;最后會把值1賦值給鍵為Anna的元素。我們可以看到,用下標訪問map中不存在的元素,會導致在map容器中添加一個新元素,它的鍵即為該下標值。map的下標運算和vector下標運算相同:返回鍵相關聯的值。運用map容器的這些特點,可以使編程編的很簡練。如下面記錄每個單詞出現次數的例子:

map<string,int>    word_count;
string    word;
//統計word_count中某個單詞出現的次數
while(cin>>word)
    ++word_count;

  map容器的insert使用的是pair類型的參數。如下表為map容器提供的insert操作。

  

m.insert(e)              e是一個用在m上的vaule_type類型的值。如果鍵e.first不在m中,則插入一個鍵為e.first值為e.seconde的元素。如果該鍵在m中已存在。則m保持不變。
                         該函數返回一個pair類型的對象,包含指向鍵為e.first的元素的map迭代器,以及一個bool類型的對象,表示是否插入成功。
m.insert(beg,end)        beg和end是標記元素范圍的迭代器,其中的元素必須為m.value_type類型的鍵-值對。
                         對於該范圍內的素有元素,如果它的鍵在m中不存在,則將該鍵及其關聯的值插入m。返回void    
m.insert(iter,e)         e是一個用在vaule_type類型的值。如果鍵不在m中,則創建新元素,並以迭代器iter為起點搜索新元素存儲的位置。
                         返回一個迭代器,指向m中具有給定鍵的元素。

  如下:

//方法一
word_count.insert(map<string,int>::value_type("Anna",1));

//方法二,使用make_pair
word_count.inser(make_pair("Anna",1));

//方法三,使用typedef
typedef  map<string,int>::value_type  valType;
word_count.insert(valType("Anna",1));

 

4.map中元素的查找與讀取

  map中下標讀取元素的缺點是當不存在該元素時會自動添加,有時這是我們不希望看到的。所以map提供了另外兩個操作:count和find,用於檢查某個鍵是否存在而不會插入該鍵。

m.count(k)               返回m中k出現次數
m.find(k)                如果m容器中存在按k索引的元素,則返回指向該元素的迭代器。如果不存在,則返回超出末端迭代器

  count成員的返回值只能是0或1,因為map值允許一個鍵對應一個實例。如果返回值為非0,則可以用下標操作來獲取該鍵所關聯的值。

int occurs=0;
if(word_count.count("foobar"))
    occurs=word_count["foobar"];

  find操作凡湖指向元素的迭代器,如果元素不存在,則返回end迭代器。

int  occurs=0;
map<string,int>::iterator  it=word_count.find("foobar");
if(it!=word_count.end())
    occurs=it->second;

5.map中刪除元素

  從map容器中刪除元素用erase操作,它有三種變化形式,如下:

m.erase(k)                刪除m中鍵為k的元素。返回size_type類型的值,表示刪除的元素個數
m.srase(p)                從m中刪除迭代器p指向的元素。p必須指向m中確實存在的元素,而且不能等於m.end()。返回void型
m.erase(b,e)              從m中刪除一段范圍內的元素,該范圍由迭代器對b和e標記。b和e必須標記m中的一段有效范圍:即b和e都必須指向m中的元素或最后元素的下一個位置
                          而且,b要么在e的錢main,要么和e相等。返回void

6.map對象的迭代遍歷

  map和其他容器一樣也提供begin和end運算。

map<string,int>::const_iterator   map_it=word_count.begin();

while(map_it!=word_count.end()){
    cout<<map_it->first<<"occurs"
            <<map_it->second<<"time"<<endl;
     ++map_it;
}

三.set類型

  set只是單純的鍵的集合。當只想知道一個值是否存在時,使用set容器是最合適的。set容器支持大多數map的操作,包括構造函數、insert、count、find、erase操作。但是不包括下標操作,沒有定義mapped_type類型。在set容器中value_type不是pair類型,而是與key_type相同的類型。與map一樣,set容器中存儲的鍵也是唯一的。

1.set的定義與使用

  使用set之前必須包含set頭文件,set支持的操作基本與map提供的相同。

vector<int > ivec;
for(vector<int>::size_type  i=0;i!=10;++i){
    ivec.push_back(i);
    ivec.push_back(i);
}

//用ivec初始化set
set<int>  iset(ivec.begin(),ivec.end());
cout<<ivec.size()<<endl;        //輸出20
cout<<iset.size()<<end;         //輸出10
    

 

2.在set中添加元素

  

//方法一,直接插入
set<string>  set1;
set1.insert("the");    

//方法二,使用迭代器
set<string>  set2;
set2.insert(ivec.begin(),ivec.end());

3.從set中獲取元素

  set沒有下標操作,為了通過鍵從set中獲取元素,可使用find運算。如果僅是判斷某個元素是否存在,也可使用count操作,返回值只能是1或0。

 

參考文獻

C++ PRIMER》 中文版


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM