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

一、先解答上次的思考题

数组 [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
相关推荐
旖-旎2 小时前
哈希表(存在重复元素||)(4)
数据结构·c++·算法·leetcode·哈希算法·散列表
Run_Teenage2 小时前
Linux:认识信号,理解信号的产生和处理
linux·运维·算法
無限進步D2 小时前
蓝桥杯赛前刷题
c++·算法·蓝桥杯·竞赛
CoderCodingNo2 小时前
【GESP】C++二级真题 luogu-B4497, [GESP202603 二级] 数数
开发语言·c++·算法
磊 子2 小时前
八大排序之冒泡排序+选择排序
数据结构·算法·排序算法
We་ct2 小时前
LeetCode 50. Pow(x, n):从暴力法到快速幂的优化之路
开发语言·前端·javascript·算法·leetcode·typescript·
潇洒畅想2 小时前
1.1 从∑到∫:用循环理解求和与累积
java·数据结构·python·算法
郝学胜-神的一滴3 小时前
[简化版 GAMES 101] 计算机图形学 04:二维变换上
c++·算法·unity·godot·图形渲染·unreal engine·cesium
ZC跨境爬虫3 小时前
海南大学交友平台开发实战day7(实现核心匹配算法+解决JSON请求报错问题)
前端·python·算法·html·json