13.5 wxHashMap

wxHashMap类是一个简单的,类型安全的并且效率很不错的哈希映射类,它的接口是标准的STL容器接口的一个子集.实际上,它是在标准的std:: map和非标准的std::hash_map之后才可以设计的.通过用于创建哈希表的宏,你可以选择下面的几种类型及其组合作为哈希表的键类型或者数据类型:int,wxString或void*(任意类型).

有三个用来定义哈希映射类的宏.要定义一个名字为CLASSNAME,键类型为wxString,值类型为VALUE_T类型的哈希表,你可以使用下面的语法:

WX_DECLARE_STRING_HASH_MAP(VALUE_T, CLASSNAME);

要定义一个名字为CLASSNAME,键类型为void*,值类型为VALUE_T类型的哈希表,使用下面的定义:

WX_DECLARE_VOIDPTR_HASH_MAP(VALUE_T, CLASSNAME);

要定义一个名称为CLASSNAME,键类型和值类型任意类型的哈希表,使用下面的定义:

WX_DECLARE_HASH_MAP(KEY_T, VALUE_T, HASH_T, KEY_EQ_T, CLASSNAME);

HASH_T和KEY_EQ_T是用来作为哈希算法和比较算法的函数. wxWidgets提供了三种预定义的哈希算法: wxIntegerHash用来作为整数的哈希算法(int, long, short和它们的无符号变体都可以), wxStringHash用来作为字符串的哈希算法(wxString, wxChar, char都可以), wxPointerHash用来作为任何指针类型的哈希算法.类似的也有三个预定义的比较函数: wxIntegerEqual, wxStringEqual和wxPointerEqual.

下面的代码演示了wxHashMap的使用方法:

// 我们要存放在哈希表中的类
class Customer
{
    public:
        int CustID;
        wxString CustName;
};
// 定义和实现我们自定义的哈希表.
WX_DECLARE_HASH_MAP(int, Customer*, wxIntegerHash,
                    wxIntegerEqual, CustomerHash);
void HashTest()
{
    // 定义一个自定义哈希表的实例
    CustomerHash MyHash;
    bool IsEmpty = MyHash.empty(); // will be true
    // 创建几个对象
    Customer* CustA = new Customer;
    CustA->CustID = 10;
    CustA->CustName = wxT("Bob");
    Customer* CustB = new Customer;
    CustB->CustID = 20;
    CustB->CustName = wxT("Sally");
    Customer* CustC = new Customer;
    CustC->CustID = 5;
    CustC->CustName = wxT("Dmitri");
    // 将对象增加到哈希表
    MyHash[CustA->CustID] = CustA;
    MyHash[CustB->CustID] = CustB;
    MyHash[CustC->CustID] = CustC;
    int Size = MyHash.size(); // will be 3
    // count函数返回0或1, 含义为:20这个关键值在哈希表中吗?
    int Present = MyHash.count(20); //将返回1
    // 我们哈希表的自定义节点类型
    CustomerHash::iterator i = MyHash.begin();
    // 遍历哈希表
    while (i != MyHash.end())    {
        // first函数返回键值,second返回数据
        int CustID = i->first;
        Customer* Cust = i->second;
        // 作一些处理
        // 然后处理下一个数据
        i++;
    }
    // 将键值为10的数据移出哈希表
    MyHash.erase(10);
    // 移出不会导致数据自动释放
    delete CustA;
    // 返回指定键值的一个节点
    CustomerHash::iterator i2 = MyHash.find(21);
    // 判断是否找到节点
    bool NotFound = (i2 == MyHash.end()); // 将返回True
    // 这次将返回有效的节点
    i2 = MyHash.find(20);
    // 直接移除节点
    MyHash.erase(i2);
    delete CustB;
    // 副作用: 下面语句导致哈希表中插入一个键值为30,值为NULL的节点.
    Customer* Cust = MyHash[30]; // Cust将等于NULL
    // 清除哈希表中的节点
    MyHash.clear();
    delete CustC;
}