最近在mfc中用到字典,自己不會在網上查了資料。簡單總結一下:
一,CMap是什麼?
映射(Map),又稱爲字典(Dictionary),是由關鍵字(Key)及其對應的元素值(Value)所組成的元素單
元(Element)的表單式集合。CMap是一個mfc的模板類,可以建立一個從任意類型的變量到另外一個任意類型的
變量的映射(map),用的是哈希表作存儲,因此速度較快。對於要求查找速度快一般用數組,對於增加/刪除操作
方便的都用鏈表,但要是兩者綜合一下,最好還是用合希表。
二,要注意的幾個地方:
1.如何聲明CMap
許多人對Cmap的聲明模式CMap<KEY,ARG_KEY,VALUE,ARG_VALUE>感到迷惑,爲什麼不用CMap<KEY,VALUE>
呢?實際上,CMap中的的數據最終會是CPair,而CPair內部是(KEY,VALUE)。因此,CMap其實存儲的是KEY
,而非ARG_KEY。然而,如果你查看MFC的源代碼,幾乎CMap所有的內部參數傳遞都是訪問ARG_KEY和ARG_VALUE,因此,使用KEY&來代替ARG_KEY似乎是正確的,除了在這些情況下:
1 應用簡單的數據類型,如int ,char用值傳遞與參數傳遞沒有什麼不同
2 如果用CString作爲KEY,你應該用LPCTSTR做ARG_KEY而非CString&。
2.有哪些與Map相關的典型操:
1 向Map中插入具有給定關鍵字的元素單元。
2 在Map中查找具有給定關鍵字的元素單元。
3 在Map中刪除具有給定關鍵字的元素單元。
4 枚舉(遍歷)Map中的所有元素單元。
三,簡單的例子:
例子一: 我們來看一個CMap的用法,下面示例代碼:
CMap<int,int&,CPoint,CPoint&> myMap;
//初始化哈希表,並指定其大小(取奇數)。MyMap.InitHashTable(257);
//向myMap中添加元素單元。
for (int i=0;i < 200;i++)
myMap.SetAt( i, CPoint(i, i) );
// 刪除實際值爲偶數的關鍵字所對應的的元素單元。
POSITION pos = myMap.GetStartPosition();
int nKey;
CPoint pt;
while (pos != NULL)
{
myMap.GetNextAssoc( pos, nKey, pt );
if ((nKey%2) == 0)
myMap.RemoveKey( nKey );
}
#ifdef _DEBUG
afxDump.SetDepth( 1 );
afxDump << "myMap: " << &myMap << "/n";CMap<int,int&,CPoint,CPoint&> myMap;
//初始化哈希表,並指定其大小(取奇數)。MyMap.InitHashTable(257);
//向myMap中添加元素單元。
for (int i=0;i < 200;i++)
myMap.SetAt( i, CPoint(i, i) );
// 刪除實際值爲偶數的關鍵字所對應的的元素單元。
POSITION pos = myMap.GetStartPosition();
int nKey;
CPoint pt;
while (pos != NULL)
{
myMap.GetNextAssoc( pos, nKey, pt );
if ((nKey%2) == 0)
myMap.RemoveKey( nKey );
}
#ifdef _DEBUG
afxDump.SetDepth( 1 );
afxDump << "myMap: " << &myMap << "/n";
CMap是個很不錯的數據結構,尤其在你建立一個字典的時候。比如idcountry的含義是"中國",這就是一個元組
,也就是一個Pair,Key是"idcountry",而Value是"中國"。
例子二:
1、定義一個CMAP,向這個CMAP中增加數據項(鍵-值對)。
CMap<CString, LPCTSTR, CString, LPCTSTR>m_ItemMap;
CString strKey = _T(""), str = _T("");
int i;
for(i = 0; i < 5; i++)
{
strKey.Format("%d", i); //這個是鍵
str.Format("A%d", i); //鍵對應的值
m_ItemMap.SetAt(strKey, str);
}
2、遍歷正個CMAP的常用方法。
POSITION pos = m_ItemMap.GetStartPosition();
while(pos)
{
m_ItemMap.GetNextAssoc(pos, strKey, str);
cout<< strKey<< ":"<< str<< endl;
}
3、在CMAP中查找相應的數據項。
CString pReset;
if(m_ItemMap.Lookup("1", pReset))
{
cout<<pReset<<endl;
}
cmap用法,很詳細(轉)
一、 Map的基本知識
MFC中的提供了基於模板的CMap類。利用CMap模板類,可以處理特定的數據類型,例如用戶自定義的類或結構體等。同時,MFC也提供了基於指定 數據類型的非模板類,其中包括:
類名 | 關鍵字類型 | 元素值類型 |
CMapWordToPtr | WORDS | Void pointers |
CMapPtrToWord | Void | pointers WORDS |
CMapPtrToPtr | Void pointers | Void pointers |
CMapWordToOb | WORDS | Objects |
CMapStringToOb | Strings | Objects |
CMapStringToPtr | Strings | Void pointers |
CMapStringToString | Strings | String |
二、 Map的工作原理
在MFC的CMap及其相關的Map類中,只要對Map進行正確設置,Lookup函數通常能夠一次到位的查找到任意元素,而很少需要進行兩次或者三 次以上的查找比對。
struct CAssoc { CAssoc* pNext; UINT nHashValue; CString key; CString value; }; |
nHashTableSize是哈希表中元素的數目(默認情況下,哈希表的大 小爲17)。
如果在哈希表中的索引值爲i的位置已經容納了一個CAssoc指針,那麼MFC將建立一個單獨的CAssoc結構體的鏈表(List),鏈表中的第一 個CAssoc結構體的地址被存儲到哈希表中,而將第二個CAssoc結構體的地址存儲到前一個CAssoc結構體的pNext域,以此類推。
但是,正如我們先前所討論的那樣,只要正確設置Map,鏈表中的元素一般就不會超過三個,這就意味着,查找通常可 以在三次元素比對操作之內完成。
三、 優化查找效率
微軟推薦將哈希表的大小設置爲Map中所存儲元素數目的 110% ~120%,以使得Map的應用性能在內存消耗和查找效率之間取得相對平衡。
在MFC中,指定哈希表大小,可調用InitHashTable()函數:
map.InitHashTable(1200);
從統計學上考慮,用奇數作爲哈希表的大小也將有助於減少衝突的發生。因此,初始化一個存儲1000個元素的哈希表的InitHashTable() 函數可以如下形式使用:
map.InitHashTable(1201);
同時,在InitHashTable()函數的調用時機上,應該注意的是,該函數應當在map包含有任何元素之前使。如果map中已經包含了一個或者 更多的元素,那麼,重新改變map的大小,將會引發斷言(Assertion)錯誤。
儘管MFC中所使用的哈希算法能夠適應於大多數場合,但如果您真的有所需要,或者,只要你願意,用戶也可以使用自己的算法來取代原有的算法。對於一個 輸入的關鍵字的值,要計算出它的哈希值,MFC通常調用一個全局模板函數HashKey(),對於大多數數據類型而言,HashKey()函數是以下面的 方式實現的:
AFX_INLINE UINT AFXAPI HashKey(ARG_KEY key) { //一般情況的默認算法。 return ((UINT)(void*)(DWORD)key) >> 4; } 但對於字符串而言,其具體的實現方式如下: UINT AFXAPI HashKey(LPCWSTR key) // Unicode 編碼字符串 { UINT nHash = 0; while (*key) nHash = (nHash<<5) + nHash + *key++; return nHash; } UINT AFXAPI HashKey(LPCSTR key) // ANSI編碼字符串 { UINT nHash = 0; while (*key) nHash = (nHash<<5) + nHash + *key++; return nHash; } |
要實現對應於特定數據類型的用戶自定義哈希算法,您可以使用上述的字符串版本的HashKey()函數作爲參考,寫一個類似的特定類型的 HashKey()函數。
四、 使用MFC中的CMap類
構造函數:
CMap | 構造一個關鍵字和元素值映射的集合類。 |
操作:
Lookup | 通過給定的關鍵字查找相應的元素值。 |
SetAt | 向Map中插入一個元素單元;若存在匹配鍵字,則替代之。 |
operator [] | 向Map中插入一個元素 -SetAt的子操作 |
RemoveKey | 移除由關鍵字標示的元素單元 |
RemoveAll | 移除Map中的所有元素單元 |
GetStartPosition | 返回第一個元素單元的位置 |
GetNextAssoc | 讀取下一個元素單元 |
GetHashTableSize | 返回哈希表的大小(元素單元的數目) |
InitHashTable | 初始化哈希表,並指定它的大小 |
狀態:
GetCount | 返回Map中元素的數目 |
IsEmpty | 檢查Map是否爲空(無元素單元) |
應用實例如下:
MyMap.InitHashTable(257); |
2、選擇適當大小的奇數-- 或者,有可能的話,使用素數的效果會更好一些--來作爲哈希表的初始值。
3、然後,向myMap中添加元素單元。
4、使用myMap進行數據映射、查找、遍歷等操作。
5、調用myMap.RemoveAll()函數移除所有元素,釋放myMap佔用的內存空間。
CMap對應IMPLEMENT_SERIAL,從而支持用戶對其元素進行串行化(Serialization)以及傾注(Dumping)操作。在 對CMap的獨立元素進行傾注操作時,應該注意的是,你必須將傾注環境(Dump Context)的深度設置爲1或者更大的數字。
- 外文名
- CArray
- 屬 性
- 計算機科學領域術語