在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) 是与键相关联的数据。
例如:
Key | Value |
---|---|
“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 语言中字典的设计与应用!
研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)