[学习] 在C语言中使用字典(附示例)

在C语言中使用字典(附示例)

文章目录

  • 在C语言中使用字典(附示例)
    • 一、引言
    • 二、字典的基本概念
      • 1. 数据结构定义
      • 2. 实现方式
    • 三、C语言中字典的实现
      • 1. 定义基本结构
      • 2. 哈希函数(字符串哈希)
      • 3. 插入键值对
      • 4. 查找键值
      • 5. 销毁字典释放内存
    • 四、字典的应用场景及示例代码
      • 场景一:配置管理器(读取配置键值对)
        • ✅ 应用描述:
        • ✅ 示例代码:
        • ✅ 配置文件 `config.txt` 内容:
      • 场景二:单词计数器(统计词频)
        • ✅ 应用描述:
        • ✅ 示例代码:
    • 五、使用哈希表实现字典
      • 1. 核心设计思路
      • 2. 核心代码
      • 3. 测试验证程序
    • 六、结语


一、引言

在现代编程中,字典(Dictionary) 是一种非常重要的数据结构,它以 键值对(Key-Value Pair) 的形式存储数据,并通过键快速查找对应的值。虽然 C 语言本身没有内置的字典类型(如 Python 中的 dict 或 Java 中的 HashMap),但我们可以使用 结构体 + 哈希表 的方式手动实现一个高效的字典。

本文将详细介绍:

  • 字典的基本概念和原理;
  • C语言中如何自定义实现字典;
  • 字典的常见应用场景;
  • 提供完整的可编译运行的 C 示例代码。

二、字典的基本概念

1. 数据结构定义

字典是一种关联数组(Associative Array),由一组键值对组成,其中:

  • 键(Key) 是唯一的,用于标识对应的数据项。
  • 值(Value) 是与键相关联的数据。

例如:

KeyValue
“name”“Alice”
“age”25
“email”“alice@abc.com”

2. 实现方式

C语言中可以通过以下结构实现字典:

  • 使用 哈希表(Hash Table) 来提升查找效率。
  • 每个哈希桶(Bucket)是一个链表节点,解决冲突问题(拉链法)。

三、C语言中字典的实现

1. 定义基本结构

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

#define TABLE_SIZE 100

typedef struct Entry {
    char* key;
    char* value;
    struct Entry* next;
} Entry;

typedef struct Dictionary {
    Entry* table[TABLE_SIZE];
} Dictionary;

2. 哈希函数(字符串哈希)

unsigned int hash(const char* key) {
    unsigned long int value = 0;
    while (*key)
        value = value * 37 + *key++;
    return value % TABLE_SIZE;
}

3. 插入键值对

void dict_set(Dictionary* dict, const char* key, const char* value) {
    unsigned int index = hash(key);
    Entry* entry = dict->table[index];

    // 如果已存在该键,更新值
    while (entry != NULL) {
        if (strcmp(entry->key, key) == 0) {
            free(entry->value);
            entry->value = strdup(value);
            return;
        }
        entry = entry->next;
    }

    // 否则创建新条目
    Entry* newEntry = (Entry*)malloc(sizeof(Entry));
    newEntry->key = strdup(key);
    newEntry->value = strdup(value);
    newEntry->next = dict->table[index];
    dict->table[index] = newEntry;
}

4. 查找键值

char* dict_get(Dictionary* dict, const char* key) {
    unsigned int index = hash(key);
    Entry* entry = dict->table[index];

    while (entry != NULL) {
        if (strcmp(entry->key, key) == 0)
            return entry->value;
        entry = entry->next;
    }

    return NULL; // 未找到
}

5. 销毁字典释放内存

void dict_destroy(Dictionary* dict) {
    for (int i = 0; i < TABLE_SIZE; i++) {
        Entry* entry = dict->table[i];
        while (entry != NULL) {
            Entry* tmp = entry;
            entry = entry->next;
            free(tmp->key);
            free(tmp->value);
            free(tmp);
        }
    }
}

四、字典的应用场景及示例代码

场景一:配置管理器(读取配置键值对)

✅ 应用描述:

从文本文件中读取配置项并存入字典,便于后续程序调用。

✅ 示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 此处插入上述字典定义和函数

int main() {
    FILE* fp = fopen("config.txt", "r");
    if (!fp) {
        printf("无法打开配置文件\n");
        return 1;
    }

    Dictionary config;
    memset(&config, 0, sizeof(config));

    char line[256];
    while (fgets(line, sizeof(line), fp)) {
        char* key = strtok(line, "=");
        char* value = strtok(NULL, "\n");
        if (key && value) {
            dict_set(&config, key, value);
        }
    }

    fclose(fp);

    printf("host: %s\n", dict_get(&config, "host"));
    printf("port: %s\n", dict_get(&config, "port"));

    dict_destroy(&config);
    return 0;
}
✅ 配置文件 config.txt 内容:
host=localhost
port=8080
username=admin
password=secret

📌 编译命令:

gcc -o config_reader config_reader.c

场景二:单词计数器(统计词频)

✅ 应用描述:

读取一段英文文本,统计每个单词出现的次数。

✅ 示例代码:
#include <ctype.h>

int main() {
    Dictionary word_count;
    memset(&word_count, 0, sizeof(word_count));

    char text[] = "hello world hello c programming is fun and hello world";
    char* token = strtok(text, " ");
    while (token != NULL) {
        char* count_str = dict_get(&word_count, token);
        int count = count_str ? atoi(count_str) : 0;
        char buffer[10];
        sprintf(buffer, "%d", count + 1);
        dict_set(&word_count, token, buffer);
        token = strtok(NULL, " ");
    }

    for (int i = 0; i < TABLE_SIZE; i++) {
        Entry* entry = word_count.table[i];
        while (entry != NULL) {
            printf("%s: %s\n", entry->key, entry->value);
            entry = entry->next;
        }
    }

    dict_destroy(&word_count);
    return 0;
}

📌 编译命令:

gcc -o word_counter word_counter.c

五、使用哈希表实现字典

1. 核心设计思路

我们将构建以下组件:

组件描述
Entry存储键值对的节点结构
HashTable哈希表结构,包含多个桶(bucket)
hash()哈希函数,计算字符串键对应的索引
ht_put()插入或更新键值对
ht_get()获取指定键的值
ht_remove()删除指定键
ht_destroy()销毁哈希表并释放内存

2. 核心代码

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

// 定义哈希表大小
#define TABLE_SIZE 128

// 单个键值对结构体
typedef struct Entry {
    char* key;
    char* value;
    struct Entry* next; // 冲突解决:拉链法
} Entry;

// 哈希表结构体
typedef struct HashTable {
    Entry* table[TABLE_SIZE];
} HashTable;

// 哈希函数:简单字符串哈希算法
unsigned int hash(const char* key) {
    unsigned long int value = 0;
    while (*key)
        value = value * 37 + *key++;
    return value % TABLE_SIZE;
}

// 创建新条目
Entry* create_entry(const char* key, const char* value) {
    Entry* entry = (Entry*)malloc(sizeof(Entry));
    entry->key = strdup(key);
    entry->value = strdup(value);
    entry->next = NULL;
    return entry;
}

// 初始化哈希表
HashTable* ht_create() {
    HashTable* table = (HashTable*)malloc(sizeof(HashTable));
    for (int i = 0; i < TABLE_SIZE; ++i)
        table->table[i] = NULL;
    return table;
}

// 插入或更新键值对
void ht_put(HashTable* table, const char* key, const char* value) {
    unsigned int index = hash(key);
    Entry* current = table->table[index];

    // 如果键已存在,更新值
    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            free(current->value);
            current->value = strdup(value);
            return;
        }
        current = current->next;
    }

    // 否则插入新条目
    Entry* new_entry = create_entry(key, value);
    new_entry->next = table->table[index];
    table->table[index] = new_entry;
}

// 查找键对应的值
char* ht_get(HashTable* table, const char* key) {
    unsigned int index = hash(key);
    Entry* current = table->table[index];

    while (current != NULL) {
        if (strcmp(current->key, key) == 0)
            return current->value;
        current = current->next;
    }

    return NULL; // 未找到
}

// 删除指定键
void ht_remove(HashTable* table, const char* key) {
    unsigned int index = hash(key);
    Entry* current = table->table[index];
    Entry* prev = NULL;

    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            if (prev == NULL)
                table->table[index] = current->next;
            else
                prev->next = current->next;

            free(current->key);
            free(current->value);
            free(current);
            return;
        }
        prev = current;
        current = current->next;
    }
}

// 销毁整个哈希表
void ht_destroy(HashTable* table) {
    for (int i = 0; i < TABLE_SIZE; ++i) {
        Entry* current = table->table[i];
        while (current != NULL) {
            Entry* tmp = current;
            current = current->next;
            free(tmp->key);
            free(tmp->value);
            free(tmp);
        }
    }
    free(table);
}

3. 测试验证程序

下面是一个完整的测试程序,演示如何使用上述哈希表字典:

int main() {
    HashTable* table = ht_create();

    // 插入键值对
    ht_put(table, "name", "Alice");
    ht_put(table, "age", "30");
    ht_put(table, "email", "alice@example.com");

    // 修改已有键
    ht_put(table, "age", "31");

    // 查找键
    printf("name: %s\n", ht_get(table, "name"));
    printf("age: %s\n", ht_get(table, "age"));
    printf("email: %s\n", ht_get(table, "email"));

    // 删除键
    ht_remove(table, "email");

    // 尝试获取被删除的键
    printf("email after remove: %s\n", ht_get(table, "email")); // 应为 NULL

    // 释放资源
    ht_destroy(table);

    return 0;
}

📌 编译命令(GCC / MinGW):

gcc -o hash_table_dict hash_table_dict.c

📌 运行结果:

name: Alice
age: 31
email: alice@example.com
email after remove: (null)

六、结语

虽然 C 语言没有内置字典结构,但通过结构体和哈希表可以高效地实现这一功能。掌握字典的底层实现原理,有助于我们编写更高效、灵活的程序。希望本篇博客能帮助你理解并掌握 C 语言中字典的设计与应用!


研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值