C Program To Implement Dictionary Using Hashing Algorithms

C Program To Implement Dictionary Using Hashing Algorithms

In this method, the hash table is an array of pointers. Each pointer points to a linked list. When two keys result in the same hash index (a collision), they are stored in the same linked list at that index.

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

#define SIZE 10

// Structure to represent a Key-Value pair (a node in the linked list) struct DictionaryItem int key; int value; struct DictionaryItem* next; ;

// Structure to represent the Hash Table struct HashTable struct DictionaryItem* table[SIZE]; // Array of pointers to DictionaryItems ;

// Hash Function: Maps a key to an index int hashFunction(int key) return key % SIZE;

// Initialize the hash table void initHashTable(struct HashTable* ht) for (int i = 0; i < SIZE; i++) ht->table[i] = NULL;

// Insert a key-value pair into the dictionary void insert(struct HashTable* ht, int key, int value) int index = hashFunction(key);

// Create a new item
struct DictionaryItem* newItem = (struct DictionaryItem*)malloc(sizeof(struct DictionaryItem));
newItem->key = key;
newItem->value = value;
newItem->next = NULL;
// If the bucket is empty, place the new item there
if (ht->table[index] == NULL) 
    ht->table[index] = newItem;
 else 
    // Collision handling: Add to the beginning of the linked list
    // (You could also check for duplicate keys here to update the value)
    struct DictionaryItem* current = ht->table[index];
// Check if key already exists to update value
    while (current != NULL) 
        if (current->key == key) 
            current->value = value; // Update existing value
            free(newItem); // Free the unused new item
            printf("Key %d updated.\n", key);
            return;
current = current->next;
// If key doesn't exist, insert at the head of the list
    newItem->next = ht->table[index];
    ht->table[index] = newItem;
    printf("Key %d inserted (Collision handled).\n", key);

// Search for a value by key int search(struct HashTable* ht, int key) int index = hashFunction(key); struct DictionaryItem* current = ht->table[index];

while (current != NULL) 
    if (current->key == key) 
        return current->value;
current = current->next;
return -1; // Key not found

// Delete a key-value pair void deleteItem(struct HashTable* ht, int key) int index = hashFunction(key); struct DictionaryItem* current = ht->table[index]; struct DictionaryItem* prev = NULL;

while (current != NULL && current->key != key) 
    prev = current;
    current = current->next;
if (current == NULL) 
    printf("Key %d not found.\n", key);
    return;
if (prev == NULL) 
    // The item to delete is the head of the list
    ht->table[index] = current->next;
 else 
    // The item is in the middle or end
    prev->next = current->next;
free(current);
printf("Key %d deleted.\n", key);

// Display the dictionary void display(struct HashTable* ht) printf("\n--- Dictionary Contents ---\n"); for (int i = 0; i < SIZE; i++) printf("Index %d: ", i); struct DictionaryItem* current = ht->table[i]; while (current != NULL) printf("(%d -> %d) ", current->key, current->value); current = current->next; printf("NULL\n"); printf("---------------------------\n");

int main() struct HashTable ht; initHashTable(&ht);

// Inserting values
insert(&ht, 1, 100);
insert(&ht, 2, 200);
insert(&ht, 11, 1100); // Collision: 11 % 10 = 1 (chains with key 1)
insert(&ht, 21, 2100); // Collision: 21 % 10 = 1 (chains with key 1 and 11)
insert(&ht, 5, 500);
display(&ht);
// Searching
int keyToFind = 11;
int result = search(&ht, keyToFind);
if (result != -1)
    printf("\nSearch: Value for key %d is %d\n", keyToFind, result);
else
    printf("\nSearch: Key %d not found.\n", keyToFind);
// Deleting
deleteItem(&ht, 2);
deleteItem(&ht, 99); // Non-existent key
display(&ht);
return 0;

A dictionary (map) stores key–value pairs allowing fast insert, search, and delete. Hashing provides average O(1) operations by computing an index from a key using a hash function and resolving collisions. This article explains design choices, collision resolution strategies, and presents a clear C implementation of a dictionary for string keys and integer values using separate chaining with linked lists.

| Operation | Average Case | Worst Case (All Collisions) | |-----------|--------------|-------------------------------| | Insert | O(1) | O(n) | | Search | O(1) | O(n) | | Delete | O(1) | O(n) | c program to implement dictionary using hashing algorithms

Factors affecting performance:

Benchmarking tip: Run the dictionary with 100,000 insertions and measure average time per operation using clock() or gettimeofday().


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

#define TABLE_SIZE 101

// A key-value pair node typedef struct Entry char* key; int value; struct Entry* next; Entry;

// Dictionary structure typedef struct Entry** buckets; int size; // number of buckets (table size) int count; // number of key-value pairs stored Dictionary;

Search: Value for key 11 is 1100 Key 2 deleted. Key 99 not found. ...

In C, a dictionary is typically implemented using a hash table, which maps unique keys to specific values. Since C doesn't have a built-in dictionary type like Python or Java, you must build one using an array and a hashing function. 1. Define the Data Structures

The foundation of a dictionary consists of a structure for individual entries and the table itself. This example uses separate chaining with linked lists to handle collisions (when two keys hash to the same index).

#include #include #include #define TABLE_SIZE 101 // Structure for a single dictionary entry typedef struct Entry char *key; char *value; struct Entry *next; // Pointer to next entry in case of collision Entry; // The Hash Table (Dictionary) Entry *dictionary[TABLE_SIZE]; Use code with caution. Copied to clipboard 2. Implement the Hashing Algorithm

A good hash function should distribute keys evenly across the table to minimize collisions. The djb2 algorithm is a popular, efficient choice for string keys.

// djb2 hashing algorithm unsigned int hash(const char *str) unsigned long hash = 5381; int c; while ((c = *str++)) // hash * 33 + c hash = ((hash << 5) + hash) + c; return hash % TABLE_SIZE; Use code with caution. Copied to clipboard 3. Implement Core Operations

A dictionary requires three primary functions: insert, search, and delete. Insert (Put)

This function adds a new key-value pair or updates the value if the key already exists.

void insert(const char *key, const char *value) unsigned int index = hash(key); Entry *new_entry = dictionary[index]; // Check if key already exists to update it while (new_entry != NULL) if (strcmp(new_entry->key, key) == 0) free(new_entry->value); new_entry->value = strdup(value); return; new_entry = new_entry->next; // Create a new entry if not found new_entry = malloc(sizeof(Entry)); new_entry->key = strdup(key); new_entry->value = strdup(value); new_entry->next = dictionary[index]; // Insert at the head of the list dictionary[index] = new_entry; Use code with caution. Copied to clipboard Search (Get)

Implementing a dictionary in C using a hash table is the most efficient way to achieve near-constant time ( ) for searching, inserting, and deleting data.

Below is a complete C implementation using Separate Chaining (linked lists) for collision handling, which is a robust and common choice for beginners and pros alike. C Dictionary Implementation In this method, the hash table is an array of pointers

#include #include #include #define TABLE_SIZE 10 // 1. Define the entry structure (Key-Value Pair) typedef struct Node char* key; char* value; struct Node* next; // For handling collisions via chaining Node; // 2. Define the dictionary (Hash Table) structure typedef struct Node* buckets[TABLE_SIZE]; Dictionary; // 3. Simple Hashing Algorithm (djb2) unsigned int hash(const char* key) unsigned int hash_val = 5381; int c; while ((c = *key++)) hash_val = ((hash_val << 5) + hash_val) + c; // hash * 33 + c return hash_val % TABLE_SIZE; // 4. Dictionary Operations Dictionary* dict_create() Dictionary* dict = malloc(sizeof(Dictionary)); for (int i = 0; i < TABLE_SIZE; i++) dict->buckets[i] = NULL; return dict; void dict_insert(Dictionary* dict, const char* key, const char* value) unsigned int index = hash(key); Node* new_node = malloc(sizeof(Node)); new_node->key = strdup(key); new_node->value = strdup(value); new_node->next = dict->buckets[index]; // Insert at head of chain dict->buckets[index] = new_node; char* dict_get(Dictionary* dict, const char* key) unsigned int index = hash(key); Node* temp = dict->buckets[index]; while (temp) if (strcmp(temp->key, key) == 0) return temp->value; temp = temp->next; return "Not Found"; int main() Dictionary* my_dict = dict_create(); dict_insert(my_dict, "C", "A powerful programming language"); dict_insert(my_dict, "Hash", "A function that maps data to a fixed size"); printf("Search 'C': %s\n", dict_get(my_dict, "C")); printf("Search 'Python': %s\n", dict_get(my_dict, "Python")); return 0; Use code with caution. Copied to clipboard Helpful Features for Your Dictionary

To make your implementation more "professional," consider adding these features often found in production-ready libraries:

Dynamic Resizing (Load Factor): Automatically double the table size when it gets too full (e.g., when entries reach 75% of table size) to prevent performance slowdowns.

Generic Data Types: Use void* for values so your dictionary can store anything—integers, floats, or custom structs—instead of just strings.

Persistence: Add functions to save and load the dictionary to a binary file, allowing data to stay between program runs.

Iterators: Implement a function that allows you to loop through all key-value pairs currently in the table. If you'd like to improve this code, tell me: Should it handle dynamic resizing?


Implementing a dictionary in C demands meticulous memory management. Keys must be duplicated (using strdup or manual allocation) to ensure they persist independently of the caller’s scope. Each dynamically allocated node must be freed in a destructor function to prevent memory leaks. Additionally, robust code checks for allocation failures and handles empty buckets gracefully.

Ready to take it further? Implement open addressing with quadratic probing, or add a for_each function to iterate over all key-value pairs. Happy coding!

This article provides a comprehensive guide and a complete C implementation for creating a dictionary data structure using hashing. Implementing a Dictionary in C Using Hashing Algorithms

A Dictionary is an abstract data type that stores data in key-value pairs. While simple arrays or linked lists can store these pairs, a Hash Table is the most efficient way to implement a dictionary, offering near-constant time complexity for insertion, deletion, and lookup operations. 1. Core Concepts The Hash Function

The heart of a dictionary is the hash function. It takes a "key" (usually a string) and converts it into an integer index. A good hash function distributes keys uniformly across the table to minimize collisions. Collision Handling

Since two different keys can produce the same hash index, we must handle collisions. This implementation uses Separate Chaining (using linked lists at each index), which is flexible and easy to implement in C. 2. The C Implementation

This program implements a dictionary where keys are strings (words) and values are also strings (meanings).

#include #include #include #define TABLE_SIZE 10 // Node structure for Separate Chaining struct Node char key[50]; char value[100]; struct Node* next; ; // Hash Table structure struct HashTable struct Node* bucket[TABLE_SIZE]; ; // A simple Hash Function (DJB2 algorithm style) unsigned int hash(char* key) unsigned int hashValue = 0; for (int i = 0; key[i] != '\0'; i++) hashValue = (hashValue << 5) + key[i]; return hashValue % TABLE_SIZE; // Create a new node struct Node* createNode(char* key, char* value) struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); strcpy(newNode->key, key); strcpy(newNode->value, value); newNode->next = NULL; return newNode; // Insert into Dictionary void insert(struct HashTable* ht, char* key, char* value) unsigned int index = hash(key); struct Node* newNode = createNode(key, value); if (ht->bucket[index] == NULL) ht->bucket[index] = newNode; else // Handle collision via Separate Chaining (insert at head) newNode->next = ht->bucket[index]; ht->bucket[index] = newNode; printf("Inserted: [%s : %s]\n", key, value); // Search for a key void search(struct HashTable* ht, char* key) unsigned int index = hash(key); struct Node* temp = ht->bucket[index]; while (temp != NULL) if (strcmp(temp->key, key) == 0) printf("Found: %s -> %s\n", key, temp->value); return; temp = temp->next; printf("Error: Key '%s' not found.\n", key); // Main Driver Code int main() struct HashTable ht; // Initialize buckets to NULL for (int i = 0; i < TABLE_SIZE; i++) ht.bucket[i] = NULL; insert(&ht, "C", "A general-purpose programming language."); insert(&ht, "Hash", "A function that converts data into a fixed-size value."); insert(&ht, "Pointer", "A variable that stores a memory address."); printf("\n--- Dictionary Search ---\n"); search(&ht, "C"); search(&ht, "Python"); // Not inserted return 0; Use code with caution. 3. How the Code Works

The Structs: We define a Node to hold the data and a pointer for the linked list. The HashTable is simply an array of these pointers.

Hashing: The hash() function iterates through the string. By using bit-shifting (<< 5), we ensure that even small changes in the string result in significantly different hash values.

Insertion: We calculate the index. If the index is empty, we place the node there. If a node already exists (collision), we push the new node to the front of the list at that index. // Insert a key-value pair into the dictionary

Retrieval: The program hashes the search key to jump directly to the correct "bucket" and then traverses the small linked list at that index to find the exact match. 4. Advantages of Hashing for Dictionaries Speed: Faster than binary search trees for large datasets.

Dynamic: With separate chaining, the dictionary can handle more elements than the TABLE_SIZE.

Flexibility: You can store any data type as a "value," from simple integers to complex structs.

To implement a dictionary in C using hashing, you must map string keys to values through a hash function and handle potential "collisions" where two keys produce the same hash . The most common approach for C dictionaries is Separate Chaining

, which uses an array of linked lists to store multiple entries at the same index. 1. Define Data Structures

A dictionary entry needs to store a key, its associated value, and a pointer to the next entry in case of a collision. Stack Overflow TABLE_SIZE Entry *next; } Entry;

Entry *hash_table[TABLE_SIZE]; Use code with caution. Copied to clipboard 2. Implement the Hash Function

A reliable hash function distributes keys uniformly across the table. The

algorithm is a popular choice for strings because it is simple and efficient. ((c = *str++)) hash = ((hash << ) + hash) + c; // hash * 33 + c hash % TABLE_SIZE; } Use code with caution. Copied to clipboard 3. Implement Core Operations

Dictionary operations include inserting new pairs, searching for keys, and deleting entries. Insert (and Update)

function calculates the hash, checks if the key already exists to update it, or adds a new node to the front of the linked list if it doesn't. Stack Overflow index = hash(key); Entry *temp = hash_table[index]; // Check if key already exists to update value (temp != NULL) (strcmp(temp->key, key) ==

) free(temp->value); temp->value = strdup(value); ; temp = temp->next; // Key not found, create new entry Entry *new_entry = malloc(

(Entry)); new_entry->key = strdup(key); new_entry->value = strdup(value); new_entry->next = hash_table[index]; hash_table[index] = new_entry; } Use code with caution. Copied to clipboard

function retrieves the value associated with a key by traversing the list at the hashed index. Stack Overflow index = hash(key); Entry *temp = hash_table[index]; (temp != NULL) (strcmp(temp->key, key) == temp->value; temp = temp->next; // Not found Use code with caution. Copied to clipboard 4. Comparison of Collision Strategies While Separate Chaining is flexible, another method is Linear Probing

, where collisions are resolved by moving to the next open slot in the array. How to implement a hash table (in C) - Ben Hoyt