You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在静态数组中存储哈希映射?以C语言及伪代码演示

嘿,我来给你捋捋怎么用静态数组实现这种固定大小的哈希映射——毕竟你要的是条目数量有上限的场景,用两个平行数组keys[N]和values[N]完全可行,甚至还挺直观的。下面我用C语言(适配你提到的int类型Key)和伪代码一步步演示,也会给通用版本的思路。

核心思路:平行静态数组的哈希映射

本质上就是用两个长度相同的静态数组分别存键和对应的值,再额外加一个状态数组标记每个位置的状态(空闲/已占用/已删除)——这一步很关键,不然处理哈希冲突或者删除操作时会出问题。整个结构对应的隐式字典就是你说的{keys[i]: values[i]...},但我们要通过哈希函数和冲突处理逻辑来维护这个映射关系。

具体实现(C语言,Key为int类型)

先从最贴合你场景的int Key版本开始:

1. 定义基础数据结构

我们先把类型和常量定下来,状态数组用来追踪每个位置的可用性:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int Key;          // 你的Key类型是int
typedef int Value;        // Value可以换成任意类型,这里先用int演示
#define MAX_CAPACITY 100 // 固定的条目上限,根据你的需求调整

// 标记每个数组位置的状态
typedef enum {
    EMPTY,    // 从未被使用过
    OCCUPIED, // 当前存着有效键值对
    DELETED   // 曾经存过但已删除
} EntryState;

// 静态哈希映射的结构体,把三个数组打包在一起
typedef struct {
    Key keys[MAX_CAPACITY];
    Value values[MAX_CAPACITY];
    EntryState states[MAX_CAPACITY];
} StaticHashMap;

2. 初始化哈希映射

初始化时要把所有位置的状态设为EMPTY,确保一开始是干净的:

void static_hash_map_init(StaticHashMap* map) {
    if (!map) return; // 防止传入空指针
    for (int i = 0; i < MAX_CAPACITY; i++) {
        map->states[i] = EMPTY;
    }
}

3. 哈希函数(核心中的核心)

哈希函数负责把Key转换成数组的索引,对于int类型,简单的取模就够用了:

static int hash_function(Key key) {
    // 用abs处理负Key,保证结果在0到MAX_CAPACITY-1之间
    return abs(key) % MAX_CAPACITY;
}

要是你以后换其他类型的Key(比如字符串),只要换对应的哈希函数就行——比如字符串可以用经典的djb2哈希算法。

4. 插入键值对(处理哈希冲突)

静态数组避免不了哈希冲突(两个不同的Key算出同一个索引),这里用线性探测解决:如果目标位置被占了,就依次往后找下一个空闲/已删除的位置。代码如下:

int static_hash_map_insert(StaticHashMap* map, Key key, Value value) {
    if (!map) return -1; // 非法输入

    int index = hash_function(key);
    int start_index = index;

    // 循环探测,直到找到可用位置或绕回起点(说明满了)
    do {
        if (map->states[index] == EMPTY || map->states[index] == DELETED) {
            // 找到可用位置,存入键值对
            map->keys[index] = key;
            map->values[index] = value;
            map->states[index] = OCCUPIED;
            return 0; // 插入成功
        } else if (map->keys[index] == key) {
            // 键已经存在,直接更新对应的值
            map->values[index] = value;
            return 0;
        }

        // 往后挪一个位置,超出数组就绕回开头
        index = (index + 1) % MAX_CAPACITY;
    } while (index != start_index);

    return -2; // 整个数组都满了,插入失败
}

5. 查找对应的值

查找逻辑和插入对应,同样用线性探测找目标Key:

int static_hash_map_get(StaticHashMap* map, Key key, Value* out_value) {
    if (!map || !out_value) return -1;

    int index = hash_function(key);
    int start_index = index;

    do {
        if (map->states[index] == EMPTY) {
            return -2; // 走到空闲位置,说明Key不存在
        } else if (map->states[index] == OCCUPIED && map->keys[index] == key) {
            *out_value = map->values[index];
            return 0; // 找到目标值
        }

        index = (index + 1) % MAX_CAPACITY;
    } while (index != start_index);

    return -2; // 遍历完整个数组都没找到
}

6. 删除键值对

注意:不能直接把状态设为EMPTY,否则会打断线性探测的链(后面的元素可能找不到),所以我们设为DELETED标记这个位置可以复用:

int static_hash_map_delete(StaticHashMap* map, Key key) {
    if (!map) return -1;

    int index = hash_function(key);
    int start_index = index;

    do {
        if (map->states[index] == EMPTY) {
            return -2; // Key不存在
        } else if (map->states[index] == OCCUPIED && map->keys[index] == key) {
            map->states[index] = DELETED;
            return 0; // 删除成功
        }

        index = (index + 1) % MAX_CAPACITY;
    } while (index != start_index);

    return -2; // 没找到要删除的Key
}
通用化方案(支持任意Key/Value类型)

如果要支持其他类型的Key或Value,C语言可以用宏来封装模板化的结构,或者用void指针(注意类型安全)。这里给个宏封装的例子:

// 先把EntryState枚举定义好(前面已经有了)
typedef enum { EMPTY, OCCUPIED, DELETED } EntryState;

// 宏定义:生成指定类型的静态哈希映射结构体和初始化函数
#define DEFINE_STATIC_HASH_MAP(MapName, KeyType, ValueType, Capacity) \
typedef struct { \
    KeyType keys[Capacity]; \
    ValueType values[Capacity]; \
    EntryState states[Capacity]; \
} MapName; \
\
void MapName##_init(MapName* map) { \
    if (!map) return; \
    for (int i = 0; i < Capacity; i++) { \
        map->states[i] = EMPTY; \
    } \
}

比如要生成一个字符串Key、int Value的哈希表:

// 生成名为StringIntHashMap的结构体和初始化函数
DEFINE_STATIC_HASH_MAP(StringIntHashMap, char*, int, 100)

这时候需要单独实现字符串的哈希函数,比如:

static int string_hash(const char* str) {
    unsigned long hash = 5381;
    int c;
    while ((c = *str++)) {
        hash = ((hash << 5) + hash) + c; /* 等价于 hash * 33 + c */
    }
    return hash % 100; // 对应Capacity=100
}

插入、查找函数可以参照前面的int版本,把哈希函数换成这个字符串哈希函数就行。

伪代码版本(更直观)

如果不想纠结C语言的语法,用伪代码看逻辑更清楚:

# 定义常量
MAX_CAPACITY = 100
EMPTY = 0
OCCUPIED = 1
DELETED = 2

# 初始化静态哈希映射,返回三个平行数组
def init_static_hash_map():
    keys = [None] * MAX_CAPACITY
    values = [None] * MAX_CAPACITY
    states = [EMPTY] * MAX_CAPACITY
    return (keys, values, states)

# 针对int Key的哈希函数
def hash_key(key):
    return abs(key) % MAX_CAPACITY

# 插入键值对,成功返回True,失败返回False(数组满了)
def insert(map, key, value):
    keys, values, states = map
    index = hash_key(key)
    start_index = index
    
    while True:
        if states[index] == EMPTY or states[index] == DELETED:
            keys[index] = key
            values[index] = value
            states[index] = OCCUPIED
            return True
        elif keys[index] == key:
            values[index] = value  # 已有Key,更新值
            return True
        
        index = (index + 1) % MAX_CAPACITY
        if index == start_index:
            return False  # 数组已满

# 查找值,找到返回对应值,没找到返回None
def get(map, key):
    keys, values, states = map
    index = hash_key(key)
    start_index = index
    
    while True:
        if states[index] == EMPTY:
            return None
        elif states[index] == OCCUPIED and keys[index] == key:
            return values[index]
        
        index = (index + 1) % MAX_CAPACITY
        if index == start_index:
            return None

# 删除键值对,成功返回True,失败返回False
def delete(map, key):
    keys, values, states = map
    index = hash_key(key)
    start_index = index
    
    while True:
        if states[index] == EMPTY:
            return False
        elif states[index] == OCCUPIED and keys[index] == key:
            states[index] = DELETED
            return True
        
        index = (index + 1) % MAX_CAPACITY
        if index == start_index:
            return False
几点注意事项
  • 哈希函数选择:如果你的int Key分布不均匀(比如大多是偶数),可以试试(key * 31) % MAX_CAPACITY这样的哈希函数,减少冲突率;字符串Key推荐用djb2或者MurmurHash这类成熟的算法。
  • 冲突处理:线性探测简单但容易出现“聚集”(连续一片被占用),可以换成二次探测或者双哈希来缓解,但实现会复杂一点。
  • 容量预估:静态数组容量固定,一定要提前算好最大需要存多少条目,避免插入失败;如果需要动态扩容,那就要换成动态数组了,但你要的是静态方案,所以这一点要注意。
  • 复杂Value类型:如果Value是结构体,C语言里插入时要注意深拷贝(如果结构体里有指针的话),或者直接存指针(但要管理内存)。

内容的提问来源于stack exchange,提问作者Albert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:33:30