目录

CMap

CMap 类别

详情

语法 描述
CMap::GetStartPosition 传回第一个元素的位置。
CMap::GetNextAssoc 取得下一个反覆运算的元素。
CMap::Lookup 查阅对应至指定索引键的值。
CMap::RemoveKey 移除由键指定的元素。
CMap::SetAt 将元素插入到映射中;如果找到匹配的键,则替换现有元素。

举例如下:

1、定义一个CMAP,向这个CMAP中增加数据项(键-值对)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

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的常用方法。

1
2
3
4
5
6
7

    POSITION pos = m_ItemMap.GetStartPosition();
    while(pos)
    {
        m_ItemMap.GetNextAssoc(pos, strKey, str);
        cout<< strKey<< ":"<< str<< endl;
    }

3、在CMAP中查找相应的数据项。

1
2
3
4
5
6

    CString pReset;
    if(m_ItemMap.Lookup("1", pReset))
    {
        cout<<pReset<<endl;
    }

完整例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Point
{
public:
    Point()
    {
        m_x = 0;
        m_y = 0;
    }
    Point(int x, int y)
    {
        m_x = x;
        m_y = y;
    }
public:
    int m_x;
    int m_y;
};
typedef CMap<const char*, const char*, Point, Point&>     CMapPnt; //请在使用之前定义
int main()
{
    Point elem1(1, 100), elem2(2, 200), elem3(3, 300), point;
    CMapPnt mp;
    // insert 3 elements into map,          #1
    mp.SetAt("1st", elem1);
    mp.SetAt("2nd", elem2);
    mp.SetAt("3th", elem3);
   
    // search a point named "2nd" from map                  #2
    mp.Lookup("2nd", point);
    printf("2nd: m_x: %d, m_y: %d\n", point.m_x, point.m_y);
    // insert a new pair into map      #3
    Point elem4(4, 400);
    mp["4th"] = elem4;
    cout<<"count: "<<mp.GetCount()<<endl;
    // traverse the entire map                    #4
    size_t index = 0;
    const char* pszKey;
    POSITION ps = mp.GetStartPosition();
    while( ps )
    {  
        mp.GetNextAssoc(ps, pszKey, point);
        printf("index: %d, m_x: %d, m_y: %d\n", ++index, point.m_x, point.m_y);
    }
    return 0;
}

代码中,我已经给出了一些注释,我同样建议读者们,用英文在代码中注释,这样的好处实在是太多了。尤其在代码需要在不同编码的操作系统上调试的时候。

对于CMap这个类,我不得不着重啰嗦一下的是:遍历操作以及取下标【】操作,当然还有那个令很多人困惑不已的ARG_KEY到底应该如何选择的问题。

遍历,看注释#4,至于POSITION的含义,请在本空间,查看其它文章。先使用GetStartPosition()函数获得表头的位置,然后,我们可以使用GetNextAssoc函数来遍历。GetNextAssoc(POSITION& rNextPosition, KEY& rKey, VALUE& rValue)函数的参数值得说明一下,大家看到,3个参数都是引用,而第一个是rNextPosition,顾名思义,在函数返回之后,它将会指像下一个元组,当然这是在表还未遍历完的时候,否则,它将被置为空(NULL)。

【】,利用下标取元素的这个操作符,在CMap中被重载,用来返回指定Key值数据的引用,不过在注释#3处,对于先取"4th"这个Point的引用然后赋值的用法,看起来,似乎有点聪明过了头,因为在这之前,我们还没有插入"4th"所对应的元组,但是,程序却能正常的运行!为什么?其实,这样的用法是十分正确的,因为CMap毕竟不是数组,它是没有边界的,当CMap在获得一个它无法查询到的Key值的时候,它会将这个Key以及一个空的数据类型追加到Hash表中去,从而保证了上面的程序可以无误的运行。

我们已经说过,ARG_KEY是作为类型参数传入CMap的,但并不是任何类型都可以作为ARG_KEY传入的。为什么?看样子,这次不得不简单的说说Hash表的散列函数了。每个Hash表,总会使用一些散列函数,用来查找Key所对应的Value,理想状态下,我们当然希望Hash表,就是一个数组,虽然这不可能,不过这样理解,可以帮助我们更好的理解Hash表的物理结构,就让我们暂时把它看成一个数组吧。数组总是使用下标来直接获取元素的存储地址,而下标,显然应该是个非负整数,从而Hash表,也应该具备这样的特性,至少必须存在某种算法可以使传入的Key可以直接的转化为一个非负的整数,这也就是ARG_KEY的选择标准。从而对象、引用无论如何都不应该作为ARG_KEY成为CMap的类型参数,而int、unsigned int、指针以及地址就成为了ARG_KEY的常用类型参数,其实也就是那些类似于整型的数据类型。常常看到一些人在用CMap的时候,试图使用CString作为CMap中ARG_KEY的类型参数,这是应该被纠正的方向性错误,但有些人似乎会理直气壮的反驳我,因为他们发现类型参数KEY是可以使用CString的,这很奇怪吗?我说过KEY不能使用CString吗?之所以KEY可以使用CString而ARG_KEY却用的是LPCTSTR,那是因为CString重载了operator==(const char*)这个判等操作符,当CMap从Hash表中获得KEY之后,它会将ARG_KEY与KEY直接相比较。真正存于CMap内部的是KEY,也就是CString。这也就是为什么,我们经常会看到CMap被实化成CMap<CString, LPCTSTR/相当于const char,非Unicode情况下*/, CString,CString&>这样的一个四不像实化类的原因,至于CMap的效率优化问题,我们会在以后的文章中继续与大家探讨。

CMap的确是个很不错的数据结构,尤其在你建立一个字典的时候。比如idealsoft的含义是"曳光科技",这就是一个元组,也就是一个Pair,Key是"idealsoft",而Value是"曳光科技"。