当前位置:首页 > C++目录 > 正文内容

哈希表与哈希函数

亿万年的星光5个月前 (09-13)C++目录475

1. 哈希表(Hash Table)

1.1 基本概念

哈希表是一种通过哈希函数将键(key)映射到表中特定位置来访问记录的数据结构。它提供了平均时间复杂度为O(1)的查找、插入和删除操作。

1.2 核心组成

  1. 键(Key): 用于查找和标识数据的唯一标识符

  2. 值(Value): 与键关联的实际数据

  3. 哈希函数(Hash Function): 将键转换为数组索引的函数

  4. 哈希桶(Buckets): 存储键值对的容器数组

  5. 冲突解决机制: 处理多个键映射到同一索引的情况

1.3 工作原理

键 → 哈希函数 → 哈希值 → 数组索引 → 存储/检索值

1.4 性能特点

  • 平均时间复杂度:

    • 插入: O(1)

    • 查找: O(1)

    • 删除: O(1)

  • 最坏情况时间复杂度: O(n) (当所有键都冲突时)

2. 哈希函数(Hash Function)

2.1 基本概念

哈希函数是将任意大小的数据映射到固定大小值的函数。在哈希表中,它将键转换为数组索引。

2.2 理想哈希函数的特性

  1. 确定性: 相同的键总是产生相同的哈希值

  2. 均匀性: 哈希值应均匀分布在输出空间

  3. 高效性: 计算速度快

  4. 抗碰撞性: 不同键产生相同哈希值的概率低

2.3 常见哈希函数类型

2.3.1 除法哈希法

hash(key) = key % table_size

2.3.2 乘法哈希法

hash(key) = floor(table_size * (key * A - floor(key * A))) 
其中 0 < A < 1

2.3.3 通用哈希法

hash(key) = ((a * key + b) % p) % table_size其中p是大素数,a,b是随机数

2.3.4 字符串哈希函数

// DJB2哈希函数
unsigned long djb2_hash(const char *str) {
    unsigned long hash = 5381;
    int c;
    while ((c = *str++)) {
        hash = ((hash << 5) + hash) + c; // hash * 33 + c
    }
    return hash;
}





2.4 哈希函数设计原则

  1. 考虑键的类型: 整数、字符串、对象等需要不同的处理

  2. 利用键的所有信息: 确保键的每个部分都影响哈希值

  3. 避免规律性: 防止键的模式导致哈希值聚集

  4. 测试均匀性: 实际测试哈希值分布情况


2.5 哈希表与平衡树的比较

特性哈希表平衡树(如红黑树)
平均查找时间O(1)O(log n)
最坏查找时间O(n)O(log n)
范围查询不支持支持
内存使用通常较少通常较多
实现复杂度较简单较复杂



实现方式:

#include <unordered_map> // 哈希表
#include <unordered_set> // 哈希集合

int main() {
    // 哈希表示例
    std::unordered_map<std::string, int> wordCount;
    
    // 插入元素
    wordCount["apple"] = 5;
    wordCount.insert({"banana", 3});
    
    // 查找元素
    if(wordCount.find("apple") != wordCount.end()) {
        std::cout << "apple count: " << wordCount["apple"] << std::endl;
    }
    
    // 哈希集合示例
    std::unordered_set<int> uniqueNumbers;
    uniqueNumbers.insert(1);
    uniqueNumbers.insert(2);
    uniqueNumbers.insert(1); // 重复元素不会被插入
    
    return 0;
}



扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

树的存储与遍历—链式存储

一、定义链式存储是表示树结构最直观、最常用的一种方法。它的核心思想是:用链表中的节点来表示树中的每个元素。每个节点不仅包含数据本身,还包含指向其子节点的指针。二、基本结构对于一个普通的树(不一定是二叉...

【数据结构】栈—括号匹配检验

【数据结构】栈—括号匹配检验

【题目描述】假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,如([ ]())或[  (  [  ] [  ] ) ] 等为正确的匹配,[&nbs...

图的访问与存储—临接矩阵

1. 什么是邻接矩阵?邻接矩阵是图的一种最基础的存储表示方法。它使用一个二维数组(即矩阵)来表示图中各个顶点之间的邻接关系。对于一个有 n 个顶点的图,其邻接矩阵是一个 n x n 的方阵,我们通常称...

NOIP/CSP-J复赛历年考点

2000计算器的改良税收与补贴乘积最大单词接龙模拟、字符串模拟字符串、动态规划广度优先bfs、字符串2001数的计数最大公约数与最小公倍数求先序排列装箱问题模拟模拟、函数二叉树贪心2002级数求和选数...

C++中的溢出

一、编程中的溢出   溢出是C++语言中最常见的漏洞。最常见的溢出包括数组溢出、数溢出、缓冲区溢出、指针溢出以及栈溢出。二、数组溢出    ...

NOIP2013年普及组初赛题目及答案分析

NOIP2013年普及组初赛题目及答案分析

一、单项选择题1. 一个 32 位整型变量占用( A )个字节。 A. 4    B. 8      C. 32     &nbs...