哈希表实战:从原理到手写实现

一、先解答上次的思考题

数组 [5,2,8,1,3] 建成大顶堆后,依次取出堆顶结果:8 5 3 2 1


二、今天学习目标

  1. 什么是哈希表、哈希函数、哈希冲突
  2. 解决冲突:链地址法(拉链法)
  3. 手写实现一个简易哈希表
  4. 支持:插入、查找、删除操作

三、什么是哈希表?

哈希表(Hash Table)也叫散列表 ,核心思想:用 key 直接计算出存储位置,实现近乎 O (1) 的查找。

  • 数组:下标是数字,查找 O (1)
  • 哈希表:key 可以是数字 / 字符串,通过哈希函数转成数组下标

关键概念

  1. 哈希函数 :把 key 转成数组下标最简单:index = key % 表长度
  2. 哈希冲突:两个不同 key 算出同一个 index
  3. 冲突解决 :最常用 链地址法(同一位置挂一条链表)

四、结构设计(链地址法)

  • 数组作为哈希桶
  • 每个桶是一个链表,存放冲突的元素
cpp 复制代码
哈希表结构示意:
[0] → (key,val) → NULL
[1] → NULL
[2] → (key,val) → (key,val) → NULL
...

五、完整可运行代码(简易哈希表)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 哈希表大小
#define SIZE 10

// 链表节点
struct Node {
    int key;
    int val;
    struct Node* next;
};

// 哈希表:数组存链表头
struct Node* hashTable[SIZE];

// 初始化哈希表
void initHashTable() {
    for (int i = 0; i < SIZE; i++)
        hashTable[i] = NULL;
}

// 哈希函数
int hashFunc(int key) {
    return key % SIZE;
}

// 插入 key-value
void insert(int key, int val) {
    int index = hashFunc(key);
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->key = key;
    newNode->val = val;
    newNode->next = NULL;

    // 头插法
    newNode->next = hashTable[index];
    hashTable[index] = newNode;
}

// 查找:根据 key 找 val,找到返回1,否则0
int find(int key, int* resVal) {
    int index = hashFunc(key);
    struct Node* cur = hashTable[index];
    while (cur != NULL) {
        if (cur->key == key) {
            *resVal = cur->val;
            return 1;
        }
        cur = cur->next;
    }
    return 0;
}

// 删除 key
void delete(int key) {
    int index = hashFunc(key);
    struct Node* cur = hashTable[index];
    struct Node* pre = NULL;

    while (cur != NULL && cur->key != key) {
        pre = cur;
        cur = cur->next;
    }
    if (cur == NULL) return;

    if (pre == NULL)
        hashTable[index] = cur->next;
    else
        pre->next = cur->next;

    free(cur);
}

// 打印哈希表
void printHashTable() {
    for (int i = 0; i < SIZE; i++) {
        printf("[%d] ", i);
        struct Node* cur = hashTable[i];
        while (cur != NULL) {
            printf("→ (%d:%d) ", cur->key, cur->val);
            cur = cur->next;
        }
        printf("\n");
    }
}

// ==================== 主函数测试 ====================
int main() {
    initHashTable();

    insert(1, 100);
    insert(2, 200);
    insert(11, 1100);  // 11%10=1,与1冲突
    insert(21, 2100);  // 21%10=1,继续冲突

    printf("哈希表内容:\n");
    printHashTable();

    int val;
    if (find(11, &val))
        printf("\n找到 key=11,val=%d\n", val);

    delete(11);
    printf("\n删除 key=11 后:\n");
    printHashTable();

    return 0;
}

六、运行结果

cpp 复制代码
哈希表内容:
[0]
[1] → (21:2100) → (11:1100) → (1:100)
[2] → (2:200)
[3]
[4]
[5]
[6]
[7]
[8]
[9]

找到 key=11,val=1100

删除 key=11 后:
[0]
[1] → (21:2100) → (1:100)
[2] → (2:200)
[3]
[4]
[5]
[6]
[7]
[8]
[9]

七、哈希表总结

  • 查找 / 插入 / 删除平均复杂度:O(1)
  • 冲突最坏情况退化为链表:O(n)
  • 工程常用:unordered_map、Redis 哈希、数据库索引

八、今日小练习

  1. 插入 key:5,15,25,7
  2. 打印哈希表,观察冲突位置
  3. 查找 key=15,删除 key=5
相关推荐
超级码力6665 小时前
【Latex文件架构】Latex文件架构模板
算法·数学建模·信息可视化
穿条秋裤到处跑6 小时前
每日一道leetcode(2026.04.29):二维网格图中探测环
算法·leetcode·职场和发展
Merlos_wind6 小时前
HashMap详解
算法·哈希算法·散列表
汉克老师7 小时前
GESP2025年3月认证C++五级( 第三部分编程题(1、平均分配))
c++·算法·贪心算法·排序·gesp5级·gesp五级
Yzzz-F9 小时前
Problem - 2205D - Codeforces
算法
智者知已应修善业10 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
Halo_tjn10 小时前
Java Set集合相关知识点
java·开发语言·算法
生成论实验室10 小时前
《事件关系阴阳博弈动力学:识势应势之道》第四篇:降U动力学——认知确定度的自驱演化
人工智能·科技·神经网络·算法·架构
AI科技星11 小时前
全域数学·72分册:场计算机卷【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算
科研前沿11 小时前
镜像孪生VS视频孪生核心技术产品核心优势
大数据·人工智能·算法·重构·空间计算