程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 使用 <map> 庫創建關聯容器

使用 <map> 庫創建關聯容器

編輯:關於VC++

摘要:當索引是整型,那麼將值與之關聯並不難,但如果數據的關聯值對是其它數據類型怎麼辦呢?<map>庫具備一個關聯容器,使用它可以很方便地關聯所有類型的數據對。本文將討論 <map> 庫的使用方法和技巧。

關系數據庫,科學計算應用以及基於Web的系統常常需要類似 vector 的容器,其索引可以是如何數據類型,不一定是整數。這樣的容器叫關聯容器,或者 map。例如,目錄服務應用可以將私人姓名作為索引來存儲,電話號碼作為其關聯的值:

directory["Harry"]=8225687;// 插入 "Harry" 並與他的電話號碼關聯
iterator it=directory.find("Harry");// 獲取 Harry 的電話號碼

其它關聯容器的應用還包括將 URLs 映射到 IP 的 DNS 服務器,字典,庫存清單,工資表等等。那麼如何突破整型索引的局限,實現用其它數據類型作為索引的關聯容器呢?答案是:使用 <map> 庫創建和處理關聯容器。

Pair 和 Map

最近的一篇文章中,我介紹了 tuple 的概念,它是不同類型元素的集合。在這篇文章中,有一個內容沒有提到,那就是 C++98 標准庫已經具備一個特殊的 tuple 類型——pair。它將鍵值(也就是第一個元素)與某個值(第二個值)關聯。例如:

#include <utility> //definition of pair
#include <string>
pair <string, string> prof_and_course("Jones", "Syntax");
pair <int, string> symbolic_const (0, "false");

標准庫還定義了一個輔助函數,方便 pair 類型的創建:

string prof;
string course;
make_pair(prof,course);//returns pair <string,string>

第一步:構造和初始化一個 map 對象

假設你正在開發一個地址簿程序,地址簿包含姓名和 e-mail 地址。類模板 map 在 <map> 中定義i,它是一個使用類型對的關聯容器,第一個元素是索引,第二個元素是關聯的值。使用方法如下:

#include <map>
map <string, string> addresses;

為了添加元素,使用下標算符:

addresses["Paul W."]="[email protected]";

這裡,串“Paul W.”是索引或鍵值,“[email protected]”是其關聯的值。如果該 map 已經包含了此鍵值,那麼當前所關聯的值不會改變: 

addresses["Paul W."]=
"[email protected]"; // 不起作用

第二步:搜索

在不插入元素的情況下,如果你想檢查某個元素是否存在,可以使用 find()成員函數。find()有兩個重載的版本:

iterator find(const key_type& k);
const_iterator find(const key_type& k) const;

通常,用 typedef 可以使代碼更可讀一些:

typedef map <string, string>::const_iterator CIT;
CIT cit=addresses.find("Paul W.");
if (cit==addresses.end())
  cout << "sorry, no such key" << endl;
else
  cout << cit->first << ''\t'' << cit->second << endl;

表達式中 cit->first 和 cit->second 分別返回鍵值及其關聯的值。

第三步:元素遍歷

現在讓我們看一個更現實的情況。假設你正在經營一家旅行社,每一個代理做一單業務都可以獲得獎金。這些代理的信息存儲在某個文件中,其格式如下:

Bob 35
Bob 90
Jane 80.25
Sue 100
Jane 65.5

你的應用程序必須匯總所有代理的獎金並將每個代理的獎金總數顯示出來.首先,創建一個 map,然後讀取該數據文件:

map <string, double> bonuses;
string agent;
double bonus=0;
ifstream bonusfile("bonuses.dat");
if(!bonusfile)
{
  // 報告出錯信息並終止程序
}
while (bonusfile >> agent >> bonus)
{
  bonuses[agent]+=bonus;// 累加每個代理的獎金
}

不管理相不相信,就這麼簡單!且讓我們來分析一下該循環。打開數據文件之後,while 循環讀取每個值對,並將其存入 agent 和 bouns 對象。接著,它將 agent 和 bouns 插入到該 map。此處的關鍵技巧是:如果鍵值(agent)已經存在,那麼 += 操作符便將最新讀取的 bouns 累加到存儲在 map 中當前的 bouns 中。因為表達式:

map[key]

返回與鍵值關聯的值。當重載的 += 操作符被調用時,該值便被累加到新讀取的 bouns 中。最後累加的和覆蓋 map 中舊的關聯值。記住:當你使用下標算符機制時,純粹的賦值操作並不會改寫現有的值,只有重載的 += 才這麼做。

幸運的是,map 並不包含一個必須要初始化的鍵值,表達式:

map[key]

返回默認的初始化 T,而 T 在上述例子中是 double 類型。默認的初始值為 0。至此,map 包含代理及其獎金匯總值對。下面的循環用來顯示這些值對,輸出如圖一所示:

for(CIT p=bonuses.begin(); p!=bonuses.end(); ++p)
{
   cout << p->first <<''\t'' << p->second <<endl;
}

圖一 代理獎金匯總數

散列的關聯容器

標准庫目前還不提供散列關聯容器。這種容器可以大大改進性能,因為它們使用散列算法從原來的字符串索引派生短鍵值。但是,許多 IDEs 提供非標准散列容器擴展。值得慶幸的是,新的 C++0X 標准彌補了這一點,在 C++ 中添加了一組散列容器和與之相關的算法。

作者簡介

Danny Kalev 是一名通過認證的系統分析師,專攻 C++ 和形式語言理論的軟件工程師。1997 年到 2000 年期間,他是 C++ 標准委員會成員。最近他以優異成績完成了他在普通語言學研究方面的碩士論文。 業余時間他喜歡聽古典音樂,閱讀維多利亞時期的文學作品,研究 Hittite、Basque 和 Irish Gaelic 這樣的自然語言。其它興趣包括考古和地理。Danny 時常到一些 C++ 論壇並定期為不同的 C++ 網站和雜志撰寫文章。他還在教育機構講授程序設計語言和應用語言課程。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved