C Program To Implement Dictionary Using Hashing Algorithms 〈No Survey〉
Building a High-Performance Dictionary in C: A Complete Guide to Hashing Algorithms
Why Separate Chaining?
In the main function, notice the call to print_dictionary. Because we used Separate Chaining, you can visually see collisions.
If "apple" and "banana" (hypothetically) hashed to the same index, the output would show:
Index [5]: (banana: 20) -> (apple: 15) -> NULL
This structure ensures that even if collisions occur, no data is lost, and performance degrades gracefully (linearly with chain length) rather than failing or requiring complex re-probing loops.
Chapter 5: Complete Example Program
Here is a working example that ties everything together:
#include <stdio.h> #include <stdlib.h> #include <string.h>// [Include all the functions defined above: hash_djb2, create_hash_table, // insert, search, delete_key, display, destroy_hash_table]
int main() // Create a dictionary with 10007 buckets HashTable *dict = create_hash_table(TABLE_SIZE); if (!dict) printf("Failed to create dictionary\n"); return 1;
printf("=== Dictionary Implementation using Hashing in C ===\n\n"); // Insert some key-value pairs printf("Inserting entries...\n"); insert(dict, "apple", 10); insert(dict, "banana", 20); insert(dict, "orange", 30); insert(dict, "grape", 40); insert(dict, "apple", 99); // Update existing key display(dict); // Search for keys printf("\nSearching for keys:\n"); int found; int value = search(dict, "banana", &found); if (found) printf("banana -> %d\n", value); else printf("banana not found\n"); value = search(dict, "kiwi", &found); if (found) printf("kiwi -> %d\n", value); else printf("kiwi not found\n"); // Delete a key printf("\nDeleting 'orange'...\n"); if (delete_key(dict, "orange")) printf("'orange' deleted successfully.\n"); else printf("'orange' not found.\n"); display(dict); // Check dictionary size printf("\nTotal number of key-value pairs: %d\n", dict->count); // Cleanup destroy_hash_table(dict); return 0;
Expected Output:
=== Dictionary Implementation using Hashing in C ===
Inserting entries...
Why Hashing for a Dictionary?
Before writing code, we must understand why hashing is the preferred method for dictionary implementation.
A dictionary needs three core operations: c program to implement dictionary using hashing algorithms
- Insert(key, value) – Store a pair.
- Search(key) – Retrieve the value for a given key.
- Delete(key) – Remove a key-value pair.
If you use an array (sorted), search is O(log n) with binary search, but insert/delete are O(n). If you use a linked list, search is O(n). Hashing transforms this by using a hash function to convert the key into an integer index, allowing direct access to an array slot. In an ideal scenario, all operations are O(1).
The Hash Function
We need a deterministic function that converts a string into an integer. A popular choice is the djb2 algorithm (by Daniel J. Bernstein), which uses bit shifting to generate a well-distributed hash.
unsigned long hash_function(const char *str)
unsigned long hash = 5381;
int c;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
Insert (or update) a key-value pair
void put(Dictionary* dict, const char* key, int value)
int index = hash(key, dict->size);
Entry* curr = dict->buckets[index];
// Check if key already exists
while (curr != NULL)
if (strcmp(curr->key, key) == 0)
curr->value = value; // update
return;
curr = curr->next;
// Insert new node at head of chain
Entry* new_entry = (Entry*)malloc(sizeof(Entry));
new_entry->key = strdup(key);
new_entry->value = value;
new_entry->next = dict->buckets[index];
dict->buckets[index] = new_entry;
dict->count++;
Step 4: Alternative Implementation – Open Addressing (Linear Probing)
While separate chaining is robust, open addressing saves memory by storing entries directly in the array. Here’s a simplified version using linear probing. Building a High-Performance Dictionary in C: A Complete
typedef struct
char *key;
char *value;
int is_occupied; // Tombstone support for deletions
HashEntry;
typedef struct
HashEntry *entries;
unsigned long size;
unsigned long count;
ProbeDict;
unsigned long find_slot(ProbeDict *dict, const char *key)
unsigned long hash = hash_djb2(key);
unsigned long index = hash % dict->size;
unsigned long original = index;
while (dict->entries[index].is_occupied)
if (dict->entries[index].key && strcmp(dict->entries[index].key, key) == 0)
return index; // Found
index = (index + 1) % dict->size;
if (index == original) break; // Full table
return index; // Empty slot or tombstone
Pros of probing: Better cache locality.
Cons: Clustering issues, more complex deletions (require tombstones). This structure ensures that even if collisions occur,
3. Dictionary Operations
1. Abstract
This report presents the design and implementation of a dictionary data structure in the C programming language using hashing techniques. A dictionary, also known as a symbol table or associative array, stores key-value pairs and supports efficient insertion, search, and deletion operations. Hashing provides average-case O(1) time complexity for these operations. This implementation uses separate chaining to handle collisions and a simple polynomial rolling hash function for strings.