自定义哈希函数类型

以往在定义哈希的时候都是用两个参数模板,但是今天遇到的三个参数模板的,这里扩展一下。

在 C++ 中,std::unordered_map 的第三个模板参数是哈希函数类型,用于计算键(Key)的哈希值。你看到的 PageIdHash 就是专门为 PageId 类型定制的哈希函数,这是处理自定义类型作为键时的常见做法。

一、std::unordered_map 的模板参数

unordered_map 的完整模板定义如下:

template<
    class Key,                          // 键类型
    class T,                            // 值类型
    class Hash = std::hash<Key>,        // 哈希函数类型(默认使用 std::hash)
    class KeyEqual = std::equal_to<Key>,// 键比较函数类型(默认使用 std::equal_to)
    class Allocator = std::allocator< std::pair<const Key, T> >// 内存分配器(很少修改)
> class unordered_map;

关键参数说明

  1. Key:键的类型(如 PageId)。
  2. T:值的类型(如 frame_id_t)。
  3. Hash:计算键哈希值的函数类型,默认是 std::hash<Key>

二、为什么需要自定义哈希函数?

当键类型是自定义类型(如 PageId 类)时,C++ 标准库不知道如何计算其哈希值,因此需要手动提供:

  1. PageId 是自定义类型,没有默认的哈希函数。
  2. PageIdHash 是专门为 PageId 定制的哈希函数类型。

三、PageIdHash 的实现示例

struct PageId {
    int file_id;  // 文件ID
    int page_num; // 页号
    
    // 判断两个 PageId 是否相等(必须重载)
    bool operator==(const PageId& other) const {
        return file_id == other.file_id && page_num == other.page_num;
    }
};

// 自定义哈希函数
struct PageIdHash {
    // 计算 PageId 的哈希值
    std::size_t operator()(const PageId& p) const {
        // 使用标准库的哈希函数组合多个成员
        return std::hash<int>()(p.file_id) ^ (std::hash<int>()(p.page_num) << 1);
    }
};

// 使用自定义哈希函数的 unordered_map
std::unordered_map<PageId, frame_id_t, PageIdHash> page_table_;

四、为什么 std::string 不需要自定义哈希?

  • 内置类型(如 intstd::string)已有默认的 std::hash 实现。
  • 示例
    // 无需第三个参数,因为 std::string 有默认哈希
    std::unordered_map<std::string, int> name_to_age;
    

五、总结

  1. 三个模板参数的含义

    • PageId:键类型(数据页ID)。
    • frame_id_t:值类型(帧号)。
    • PageIdHash:自定义哈希函数,用于计算 PageId 的哈希值。
  2. 何时需要第三个参数?

    • 当键类型是自定义类型(如类、结构体)时,必须自定义哈希函数。
    • 当键类型是内置类型(如 intstd::string)时,可省略第三个参数。
  3. 配套要求

    • 自定义哈希函数时,通常还需要为键类型重载 operator==(用于判断两个键是否相等)。
posted @ 2025-06-20 17:50  韩熙隐ario  阅读(32)  评论(0)    收藏  举报