We need three primary structures:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// --- Configuration ---
#define TABLE_SIZE 100
// --- Data Structures ---
// 1. The Key-Value Pair Node
typedef struct KeyValue
char *key;
int value;
struct KeyValue *next; // For collision chaining
KeyValue;
// 2. The Dictionary Structure
typedef struct Dictionary
KeyValue **table; // Array of pointers to KeyValue nodes
int size;
int count; // Number of elements currently stored
Dictionary;
// --- Hash Function ---
// djb2 Hash Function
unsigned long hash(const char *str)
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash % TABLE_SIZE;
// --- Memory Helpers ---
// Helper to duplicate string (C99 standard has strdup, but this is portable)
char* duplicate_string(const char *src)
char *dst = malloc(strlen(src) + 1);
if (dst) strcpy(dst, src);
return dst;
// --- Dictionary Operations ---
// 1. Initialization
Dictionary* create_dictionary()
Dictionary *dict = (Dictionary*)malloc(sizeof(Dictionary));
dict->size = TABLE_SIZE;
dict->count = 0;
// Allocate memory for the array of pointers and initialize to NULL
dict->table = (KeyValue**)calloc(TABLE_SIZE, sizeof(KeyValue*));
return dict;
// 2. Insertion / Update
void insert(Dictionary *dict, const char *key, int value)
unsigned long index = hash(key);
KeyValue *current = dict->table[index];
// Case A: Key exists? Update the value.
while (current != NULL)
if (strcmp(current->key, key) == 0)
current->value = value;
return;
current = current->next;
// Case B: Key does not exist. Create a new node.
KeyValue *new_node = (KeyValue*)malloc(sizeof(KeyValue));
new_node->key = duplicate_string(key);
new_node->value = value;
// Insert at the head of the linked list (O(1) prepend)
new_node->next = dict->table[index];
dict->table[index] = new_node;
dict->count++;
// 3. Search / Lookup
// Returns pointer to value so we can check for NULL if key not found
int* get(Dictionary *dict, const char *key)
unsigned long index = hash(key);
KeyValue *current = dict->table[index];
while (current != NULL)
if (strcmp(current->key, key) == 0)
return &(current->value); // Return address of value
current = current->next;
return NULL; // Key not found
// 4. Deletion
void delete_key(Dictionary *dict, const char *key)
unsigned long index = hash(key);
KeyValue *current = dict->table[index];
KeyValue *prev = NULL;
while (current != NULL)
if (strcmp(current->key, key) == 0)
if (prev == NULL)
// Node is at the head
dict->table[index] = current->next;
else
// Node is in the middle or end
prev->next = current->next;
free(current->key);
free(current);
dict->count--;
return;
prev = current;
current = current->next;
printf("Key '%s' not found.\n", key);
// 5. Cleanup
void free_dictionary(Dictionary *dict)
for (int i = 0; i < dict->size; i++)
KeyValue *current = dict->table[i];
while (current != NULL)
KeyValue *temp = current;
current = current->next;
free(temp->key);
free(temp);
free(dict->table);
free(dict);
// 6. Utility: Print Dictionary
void print_dictionary(Dictionary *dict)
printf("\n--- Dictionary Contents ---\n");
for (int i = 0; i < dict->size; i++)
KeyValue *current = dict->table[i];
if (current != NULL)
printf("Index [%d]: ", i);
while (current != NULL)
printf("(%s: %d) -> ", current->key, current->value);
current = current->next;
printf("NULL\n");
printf("---------------------------\n");
// --- Main Driver ---
int main()
Dictionary *myDict = create_dictionary();
// Insertions
insert(myDict, "apple", 10);
insert(myDict, "banana", 20);
insert(myDict, "cherry", 30);
// Update
insert(myDict, "apple", 15); // Update apple's value
// Lookup
int *val = get(myDict, "banana");
if (val) printf("Get 'banana': %d\n", *val);
val = get(myDict, "grape");
if (!val) printf("Get 'grape': Key not found.\n");
// Print all to see structure
print_dictionary(myDict);
// Deletion
printf("Deleting 'banana'...\n");
delete_key(myDict, "banana");
print_dictionary(myDict);
// Cleanup
free_dictionary(myDict);
return 0;
In the realm of computer science, a dictionary (also known as a map, symbol table, or associative array) is one of the most fundamental and versatile data structures. It allows you to store key-value pairs and retrieve values in near-constant time, regardless of the size of the data. While languages like Python, Java, and C++ have built-in dictionary implementations (e.g., dict, HashMap, std::unordered_map), the C programming language does not provide a standard one. This forces C developers to implement their own dictionary from scratch. c program to implement dictionary using hashing algorithms
The most efficient way to implement a dictionary in C is by using hashing algorithms. This article provides an exhaustive guide to building a robust dictionary using hashing, covering everything from the theory of hash functions to collision resolution strategies, complete with a fully functional C implementation. We need three primary structures: #include <stdio
Resizing involves creating a new larger bucket array, rehashing all entries, and freeing the old structure. In the realm of computer science, a dictionary
void resize_dictionary(Dictionary *dict) unsigned long old_size = dict->size; Entry **old_buckets = dict->buckets;// Double the size dict->size *= 2; dict->buckets = (Entry**)calloc(dict->size, sizeof(Entry*)); dict->count = 0; // Will be rebuilt // Rehash all entries for (unsigned long i = 0; i < old_size; i++) Entry *curr = old_buckets[i]; while (curr) Entry *next = curr->next; unsigned long new_index = dict->hash_func(curr->key) % dict->size; curr->next = dict->buckets[new_index]; dict->buckets[new_index] = curr; dict->count++; curr = next; free(old_buckets);