Should we modify the program to ?
Hashing has several advantages that make it a popular choice for implementing dictionaries:
You can extend this with:
The program above is highly educational and suitable for small-scale projects, but scaling it requires a few extra considerations: c program to implement dictionary using hashing algorithms
The delete_key function safely tracks the current node ( temp ) and the preceding node ( prev ). When it finds a matching key, it alters the pointers to stitch the list around the removed item. This preserves the links to any subsequent items in the chain, eliminating memory leaks. 7. Performance and Optimization Considerations
new_entry->next = dict->buckets[index]; dict->buckets[index] = new_entry; dict->count++;
#include #include #include #define TABLE_SIZE 17 #define MAX_KEY_LEN 64 #define MAX_VAL_LEN 128 // Node structure for separate chaining typedef struct Node char key[MAX_KEY_LEN]; char value[MAX_VAL_LEN]; struct Node* next; Node; // Dictionary structure containing the hash table typedef struct Node* buckets[TABLE_SIZE]; Dictionary; // 1. The DJB2 Hashing Algorithm 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 % TABLE_SIZE; // Initialize the dictionary buckets to NULL void init_dictionary(Dictionary* dict) for (int i = 0; i < TABLE_SIZE; i++) dict->buckets[i] = NULL; // 2. Insert or Update a Key-Value Pair int insert(Dictionary* dict, const char* key, const char* value) unsigned long index = hash_function(key); Node* current = dict->buckets[index]; // Check if the key already exists to update its value while (current != NULL) if (strcmp(current->key, key) == 0) strncpy(current->value, value, MAX_VAL_LEN - 1); current->value[MAX_VAL_LEN - 1] = '\0'; return 1; // Updated existing key current = current->next; // Key does not exist; create a new node Node* new_node = (Node*)malloc(sizeof(Node)); if (!new_node) return 0; // Memory allocation failed strncpy(new_node->key, key, MAX_KEY_LEN - 1); new_node->key[MAX_KEY_LEN - 1] = '\0'; strncpy(new_node->value, value, MAX_VAL_LEN - 1); new_node->value[MAX_VAL_LEN - 1] = '\0'; // Insert at the head of the linked list (O(1) insertion) new_node->next = dict->buckets[index]; dict->buckets[index] = new_node; return 2; // Inserted new key // 3. Search for a Key const char* search(Dictionary* dict, const char* key) unsigned long index = hash_function(key); Node* current = dict->buckets[index]; while (current != NULL) if (strcmp(current->key, key) == 0) return current->value; // Key found current = current->next; return NULL; // Key not found // 4. Delete a Key-Value Pair int delete(Dictionary* dict, const char* key) unsigned long index = hash_function(key); Node* current = dict->buckets[index]; Node* prev = NULL; while (current != NULL) if (strcmp(current->key, key) == 0) if (prev == NULL) // Node to delete is the head of the bucket list dict->buckets[index] = current->next; else // Node to delete is in the middle or end prev->next = current->next; free(current); return 1; // Successfully deleted prev = current; current = current->next; return 0; // Key not found // 5. Display the Hash Table Structure void display_dictionary(Dictionary* dict) printf("\n--- Dictionary Hash Table Structure ---\n"); for (int i = 0; i < TABLE_SIZE; i++) printf("Bucket [%d]: ", i); Node* current = dict->buckets[i]; if (current == NULL) printf("NULL\n"); continue; while (current != NULL) printf("[%s: %s] -> ", current->key, current->value); current = current->next; printf("NULL\n"); printf("----------------------------------------\n"); // 6. Free Allocated Memory void free_dictionary(Dictionary* dict) for (int i = 0; i < TABLE_SIZE; i++) Node* current = dict->buckets[i]; while (current != NULL) Node* temp = current; current = current->next; free(temp); dict->buckets[i] = NULL; // Demonstration int main() Dictionary my_dict; init_dictionary(&my_dict); // Inserting values insert(&my_dict, "Alice", "Engineer"); insert(&my_dict, "Bob", "Designer"); insert(&my_dict, "Charlie", "Manager"); insert(&my_dict, "David", "Developer"); // Potential collision demo // Displaying initial table display_dictionary(&my_dict); // Searching test const char* target = "Bob"; const char* role = search(&my_dict, target); if (role) printf("\nFound! %s is a %s.\n", target, role); else printf("\n%s not found.\n", target); // Updating an existing key printf("\nUpdating Alice's role...\n"); insert(&my_dict, "Alice", "Director"); // Deleting a key printf("\nDeleting Charlie...\n"); delete(&my_dict, "Charlie"); // Displaying final table display_dictionary(&my_dict); // Clean up memory free_dictionary(&my_dict); return 0; Use code with caution. Detailed Code Walkthrough The DJB2 Hashing Function Should we modify the program to
Implementing a Dictionary in C Using Hashing Algorithms A dictionary is an abstract data type that stores data as key-value pairs. While arrays use integer indices, dictionaries allow you to use unique keys (like strings) to look up corresponding values. In C, there is no built-in dictionary type. To achieve fast
// 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;
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: This preserves the links to any subsequent items
To avoid memory leaks, we must free all allocated nodes, strings, and the dictionary structure itself before the program exits.
Will your dictionary manage (e.g., over 100,000 items)?
#include #include #include #define TABLE_SIZE 100 // Define the Node structure typedef struct Node char *key; char *value; struct Node *next; Node; // Define the Hash Table typedef struct Node *buckets[TABLE_SIZE]; HashTable; // The Hash Function (djb2) unsigned int hash(char *str) unsigned long hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; // hash * 33 + c return hash % TABLE_SIZE; // Create a new node Node* create_node(char *key, char *value) Node *new_node = malloc(sizeof(Node)); new_node->key = strdup(key); new_node->value = strdup(value); new_node->next = NULL; return new_node; // Insert into the dictionary void insert(HashTable *table, char *key, char *value) unsigned int index = hash(key); Node *new_node = create_node(key, value); // If bucket is empty, insert directly if (table->buckets[index] == NULL) table->buckets[index] = new_node; else // Handle collision via Chaining new_node->next = table->buckets[index]; table->buckets[index] = new_node; printf("Inserted: [%s : %s]\n", key, value); // Search for a key char* search(HashTable *table, char *key) unsigned int index = hash(key); Node *temp = table->buckets[index]; while (temp != NULL) if (strcmp(temp->key, key) == 0) return temp->value; temp = temp->next; return NULL; int main() HashTable dictionary = NULL; // Inserting values insert(&dictionary, "Apple", "A red fruit"); insert(&dictionary, "C", "A general-purpose programming language"); insert(&dictionary, "Hash", "A function that maps data"); // Searching char *key = "C"; char *result = search(&dictionary, key); if (result) printf("\nSearch Result for '%s': %s\n", key, result); else printf("\n'%s' not found.\n", key); return 0; Use code with caution. Why Use Hashing?