跳转到内容

C 语言字典实现

来自代码酷


介绍[编辑 | 编辑源代码]

字典(也称为关联数组哈希表)是一种高效的数据结构,用于存储键值对(key-value pairs)。在C语言中,字典可以通过多种方式实现,包括使用数组、链表、平衡二叉搜索树或哈希表。本文将重点介绍基于哈希表的字典实现,因其在平均情况下具有O(1)的查找、插入和删除时间复杂度。

字典的核心功能包括:

  • 插入(Insert):添加一个新的键值对。
  • 查找(Lookup):根据键查找对应的值。
  • 删除(Delete):移除指定的键值对。

哈希表基础[编辑 | 编辑源代码]

哈希表是字典的常见实现方式,其核心思想是通过哈希函数将键映射到数组的特定索引位置。理想情况下,哈希函数应均匀分布键,以减少冲突(即多个键映射到同一索引的情况)。

冲突处理[编辑 | 编辑源代码]

当冲突发生时,常见的解决方法有:

  • 链地址法(Chaining):使用链表存储同一索引下的所有键值对。
  • 开放寻址法(Open Addressing):在发生冲突时,探测数组中的下一个空闲位置。

本文将以链地址法为例实现字典。

字典实现步骤[编辑 | 编辑源代码]

以下是C语言中字典的完整实现步骤。

1. 定义键值对结构[编辑 | 编辑源代码]

每个键值对包含一个键(key)、一个值(value)和一个指向下一个键值对的指针(用于链地址法)。

typedef struct KeyValuePair {
    char *key;
    int value;
    struct KeyValuePair *next;
} KeyValuePair;

2. 定义字典结构[编辑 | 编辑源代码]

字典包含一个固定大小的数组(哈希表)和一个记录当前元素数量的变量。

#define TABLE_SIZE 100

typedef struct Dictionary {
    KeyValuePair *table[TABLE_SIZE];
    int count;
} Dictionary;

3. 哈希函数[编辑 | 编辑源代码]

哈希函数将字符串键转换为数组索引。这里使用简单的乘法哈希:

unsigned int hash(const char *key) {
    unsigned int hash_value = 0;
    for (int i = 0; key[i] != '\0'; i++) {
        hash_value = (hash_value * 31) + key[i];
    }
    return hash_value % TABLE_SIZE;
}

4. 字典初始化[编辑 | 编辑源代码]

初始化字典时,将所有数组元素设为NULL。

void dictionary_init(Dictionary *dict) {
    for (int i = 0; i < TABLE_SIZE; i++) {
        dict->table[i] = NULL;
    }
    dict->count = 0;
}

5. 插入键值对[编辑 | 编辑源代码]

插入时,先计算哈希值,然后检查是否已存在相同键。若存在则更新值,否则添加到链表头部。

void dictionary_insert(Dictionary *dict, const char *key, int value) {
    unsigned int index = hash(key);
    KeyValuePair *current = dict->table[index];

    // 检查键是否已存在
    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            current->value = value; // 更新值
            return;
        }
        current = current->next;
    }

    // 创建新键值对
    KeyValuePair *new_pair = malloc(sizeof(KeyValuePair));
    new_pair->key = strdup(key);
    new_pair->value = value;
    new_pair->next = dict->table[index];
    dict->table[index] = new_pair;
    dict->count++;
}

6. 查找键值对[编辑 | 编辑源代码]

查找时,先计算哈希值,然后遍历链表查找匹配的键。

int dictionary_lookup(Dictionary *dict, const char *key, int *value) {
    unsigned int index = hash(key);
    KeyValuePair *current = dict->table[index];

    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            *value = current->value;
            return 1; // 找到
        }
        current = current->next;
    }
    return 0; // 未找到
}

7. 删除键值对[编辑 | 编辑源代码]

删除时,先找到键值对,然后从链表中移除并释放内存。

int dictionary_delete(Dictionary *dict, const char *key) {
    unsigned int index = hash(key);
    KeyValuePair *current = dict->table[index];
    KeyValuePair *prev = NULL;

    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            if (prev == NULL) {
                dict->table[index] = current->next;
            } else {
                prev->next = current->next;
            }
            free(current->key);
            free(current);
            dict->count--;
            return 1; // 删除成功
        }
        prev = current;
        current = current->next;
    }
    return 0; // 未找到键
}

8. 清理字典[编辑 | 编辑源代码]

释放所有动态分配的内存。

void dictionary_free(Dictionary *dict) {
    for (int i = 0; i < TABLE_SIZE; i++) {
        KeyValuePair *current = dict->table[i];
        while (current != NULL) {
            KeyValuePair *temp = current;
            current = current->next;
            free(temp->key);
            free(temp);
        }
    }
    dict->count = 0;
}

示例代码与输出[编辑 | 编辑源代码]

以下是一个完整的示例程序,展示字典的插入、查找和删除操作。

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

// 上述所有结构体和函数定义

int main() {
    Dictionary dict;
    dictionary_init(&dict);

    // 插入键值对
    dictionary_insert(&dict, "apple", 10);
    dictionary_insert(&dict, "banana", 20);
    dictionary_insert(&dict, "orange", 30);

    // 查找键值对
    int value;
    if (dictionary_lookup(&dict, "banana", &value)) {
        printf("banana: %d\n", value); // 输出: banana: 20
    }

    // 删除键值对
    dictionary_delete(&dict, "banana");

    // 再次查找
    if (!dictionary_lookup(&dict, "banana", &value)) {
        printf("banana not found\n"); // 输出: banana not found
    }

    dictionary_free(&dict);
    return 0;
}

实际应用场景[编辑 | 编辑源代码]

字典在以下场景中非常有用:

  • 配置文件解析:存储配置项(如键值对)。
  • 缓存系统:快速查找缓存数据。
  • 数据库索引:加速记录查找。

性能优化[编辑 | 编辑源代码]

为提高字典性能,可考虑以下优化:

  • 动态扩容:当元素数量超过阈值时,扩大哈希表大小并重新哈希所有键。
  • 更好的哈希函数:如MurmurHash或CityHash,减少冲突概率。
  • 平衡树替代链表:在冲突较多时,使用红黑树代替链表(如Java的HashMap)。

复杂度分析[编辑 | 编辑源代码]

哈希表字典的平均时间复杂度如下:

操作 平均时间复杂度 最坏时间复杂度
插入 O(1) O(n)
查找 O(1) O(n)
删除 O(1) O(n)

总结[编辑 | 编辑源代码]

本文详细介绍了C语言中基于哈希表的字典实现,包括结构定义、哈希函数、冲突处理和核心操作。通过代码示例和实际应用场景,读者可以深入理解字典的工作原理及其在程序中的高效使用方式。