CMap分析

来源:互联网 发布:移动工作站 知乎 编辑:程序博客网 时间:2024/05/07 21:09

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数据成员

// CPairstruct 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 iterationpublic: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 valuesreturn (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 AssociationpAssoc = NewAssoc(key);//保存计算得到的哈希值pAssoc->nHashValue = nHashValue;//'pAssoc->value' is a constructed object, nothing more// put into hash tablepAssoc->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 existsCAssoc* 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 maprValue = 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"; }


原创粉丝点击