1.CMap定义
template< class KEY, class ARG_KEY, class VALUE, class ARG_VALUE >class CMap : public CObject
参数说明
KEY
key的类型。其类型可以是用户自定义的类
ARG _ KEY
KEY的数据类型。通常是KEY的引用
VALUE
值类型。可以是用户自定义的类
ARG _ VALUE
VALUE的数据类型。通过是VALUE的引用。
2.CMap数据结构
CMap数据结构见下图

数据类型及CMap数据成员
// CPair
struct CPair
{
const KEY key; //Key是类型
VALUE value;
protected:
//ARG_KEY 是Key的值类型 若Key是CString 则AGR_KEY可以是const char *
//ARG_KEY指定的key作为哈希函数的参数
CPair( ARG_KEY keyval ) : key( keyval ) {}
}
//CAssoc 链表节点
class CAssoc : public CPair
{
friend class CMap<KEY,ARG_KEY,VALUE,ARG_VALUE>;
CAssoc* pNext; //指向下一个链表节点
UINT nHashValue; //哈希值 // needed for efficient iteration
public:
CAssoc( ARG_KEY key ) : CPair( key ) {}
}; 如果hash地址冲突,则插入的元素保存在pNext中。
CAssoc** m_pHashTable; //以链表节点代指哈希名 m_pHashTable为CAssoc指针一维数组
UINT m_nHashTableSize; //哈希表容量
INT_PTR m_nCount; //哈希表中元素个数
3.初始化
template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
void CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::InitHashTable(
UINT nHashSize, BOOL bAllocNow)
{
//......
//......
if (bAllocNow)
{
m_pHashTable = new CAssoc* [nHashSize]; //nHashSize哈希表容器大小
ENSURE(m_pHashTable != NULL);
memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize); //hash表初始化为0
}
m_nHashTableSize = nHashSize;
}
4.哈希函数
ARG_KEY用于计算哈希地址
template<class ARG_KEY>
AFX_INLINE UINT AFXAPI HashKey(ARG_KEY key)
{
// default identity hash - works for most primitive values
return (DWORD)(((DWORD_PTR)key)>>4);
}
template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key);
template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key);
template<> UINT AFXAPI HashKey<LPCWSTR> (LPCWSTR key)
{
ENSURE_ARG(AfxIsValidString(key));
UINT nHash = 0;
while (*key)
nHash = (nHash<<5) + nHash + *key++;
return nHash;
}
template<> UINT AFXAPI HashKey<LPCSTR> (LPCSTR key)
{
ENSURE_ARG(AfxIsValidString(key));
UINT nHash = 0;
while (*key)
nHash = (nHash<<5) + nHash + *key++;
return nHash;
} 如果Key为用户自定义类类型,则必须要提供Hask函数。
5.插入一个元素
template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
VALUE& CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::operator[](ARG_KEY key)
{
ASSERT_VALID(this);
UINT nHashBucket, nHashValue;
CAssoc* pAssoc;
//GetAssocAt 找出key对应的CAssoc节点
//key传入变量
//nHashBucket为传出变量。它为key对应的桶号 即pHashTable数组的索引
//nHashValue为传出变量。它为key对应的值
if ((pAssoc = GetAssocAt(key, nHashBucket, nHashValue)) == NULL)
{
//......
// it doesn't exist, add a new Association
pAssoc = NewAssoc(key);
//保存计算得到的哈希值
pAssoc->nHashValue = nHashValue;
//'pAssoc->value' is a constructed object, nothing more
// put into hash table
pAssoc->pNext = m_pHashTable[nHashBucket];
m_pHashTable[nHashBucket] = pAssoc; //创
}
//注意,返回的是值的引用。这样可以方便修改key对应的值
//如果value的类型为CPoint 则map[1]=CPoint(562,963);
//即pAssoc->value=CPoint(562,963);
return pAssoc->value; // return new reference
}
template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
typename CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::CAssoc*
CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::GetAssocAt(ARG_KEY key, UINT& nHashBucket, UINT& nHashValue) const
// find association (or return NULL)
{
nHashValue = HashKey<ARG_KEY>(key); //计算出哈希值
nHashBucket = nHashValue % m_nHashTableSize; //计算出桶号
if (m_pHashTable == NULL)
return NULL;
// see if it exists
CAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHashBucket]; pAssoc != NULL; pAssoc = pAssoc->pNext)
{
//CompareElements比较键值 处理hash地址冲突
if (pAssoc->nHashValue == nHashValue && CompareElements(&pAssoc->key, &key))
return pAssoc;
}
return NULL;
}
6.查找函数
template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>
BOOL CMap<KEY, ARG_KEY, VALUE, ARG_VALUE>::Lookup(ARG_KEY key, VALUE& rValue) const
{
ASSERT_VALID(this);
UINT nHashBucket, nHashValue;
CAssoc* pAssoc = GetAssocAt(key, nHashBucket, nHashValue);
if (pAssoc == NULL)
return FALSE; // not in map
rValue = pAssoc->value;
return TRUE;
}
7.实例
#include "stdafx.h"
void TestCMap1()
{
CMap<int,int,CPoint,CPoint> myMap;
int i;
myMap.InitHashTable( 257 );
// Add 10 elements to the map.
for (i=0;i < 200;i++)
myMap[i] = CPoint(i, i);
// Remove the elements with even key values.
CPoint pt;
for (i=0; myMap.Lookup( i, pt ) ;i+=2)
{
myMap.RemoveKey( i );
}
#ifdef _DEBUG
ASSERT(myMap.GetCount() == 100);
afxDump.SetDepth( 1 );
afxDump << "myMap: " << &myMap << "\n";
#endif
}
void TestCMap2()
{
CMap<CString, LPCTSTR, CString, LPCTSTR> itemMap;
itemMap.InitHashTable(120);
itemMap[L"vk"]=L"vi kong";
}
本文详细介绍了CMap类模板的定义、数据结构、初始化方法、哈希函数、元素插入和查找等功能,并提供了两个实例来演示如何使用CMap。
4898

被折叠的 条评论
为什么被折叠?



