现在的位置: 首页 > 综合 > 正文

CMap分析

2018年02月16日 ⁄ 综合 ⁄ 共 3835字 ⁄ 字号 评论关闭

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_pHashTableCAssoc指针一维数组

    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";
 }

抱歉!评论已关闭.