Abstract
A dictionary is a data structure that stores a collection of key-value pairs, where each key is unique and maps to a specific value. In this paper, we implement a dictionary using hashing algorithms in C programming language. We use a hash function to map keys to indices of a hash table, which stores the key-value pairs. The goal of this implementation is to provide efficient insertion, search, and deletion operations. We discuss the design and implementation of the dictionary using hashing algorithms and present the C code for the same.
Introduction
A dictionary, also known as a hash table or a map, is a fundamental data structure in computer science that stores a collection of key-value pairs. It allows for efficient retrieval of values by their associated keys. Hashing algorithms are widely used to implement dictionaries, as they provide fast lookup, insertion, and deletion operations.
Hashing Algorithms
Hashing algorithms are used to map keys to indices of a hash table. A hash function takes a key as input and generates a hash code, which is an integer that represents the index of the hash table where the corresponding value is stored. A good hash function should have the following properties:
Design and Implementation
Our implementation of the dictionary using hashing algorithms consists of the following components:
C Code
Here is the C code for the dictionary implementation using hashing algorithms:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASH_TABLE_SIZE 10
typedef struct Node
char* key;
char* value;
struct Node* next;
Node;
typedef struct HashTable
Node** buckets;
int size;
HashTable;
// Hash function
int hash(char* key)
int hashCode = 0;
for (int i = 0; i < strlen(key); i++)
hashCode += key[i];
return hashCode % HASH_TABLE_SIZE;
// Create a new node
Node* createNode(char* key, char* value)
Node* node = (Node*) malloc(sizeof(Node));
node->key = (char*) malloc(strlen(key) + 1);
strcpy(node->key, key);
node->value = (char*) malloc(strlen(value) + 1);
strcpy(node->value, value);
node->next = NULL;
return node;
// Create a new hash table
HashTable* createHashTable()
HashTable* hashTable = (HashTable*) malloc(sizeof(HashTable));
hashTable->buckets = (Node**) malloc(sizeof(Node*) * HASH_TABLE_SIZE);
hashTable->size = HASH_TABLE_SIZE;
for (int i = 0; i < HASH_TABLE_SIZE; i++)
hashTable->buckets[i] = NULL;
return hashTable;
// Insert a key-value pair into the hash table
void insert(HashTable* hashTable, char* key, char* value)
int index = hash(key);
Node* node = createNode(key, value);
if (hashTable->buckets[index] == NULL)
hashTable->buckets[index] = node;
else
Node* current = hashTable->buckets[index];
while (current->next != NULL)
current = current->next;
current->next = node;
// Search for a value by its key
char* search(HashTable* hashTable, char* key)
int index = hash(key);
Node* current = hashTable->buckets[index];
while (current != NULL)
if (strcmp(current->key, key) == 0)
return current->value;
current = current->next;
return NULL;
// Delete a key-value pair from the hash table
void delete(HashTable* hashTable, char* key)
int index = hash(key);
Node* current = hashTable->buckets[index];
if (current == NULL) return;
if (strcmp(current->key, key) == 0)
hashTable->buckets[index] = current->next;
free(current->key);
free(current->value);
free(current);
else
Node* previous = current;
current = current->next;
while (current != NULL)
if (strcmp(current->key, key) == 0)
previous->next = current->next;
free(current->key);
free(current->value);
free(current);
return;
previous = current;
current = current->next;
// Print the hash table
void printHashTable(HashTable* hashTable)
for (int i = 0; i < HASH_TABLE_SIZE; i++)
Node* current = hashTable->buckets[i];
printf("Bucket %d: ", i);
while (current != NULL)
printf("%s -> %s, ", current->key, current->value);
current = current->next;
printf("\n");
int main()
HashTable* hashTable = createHashTable();
insert(hashTable, "apple", "fruit");
insert(hashTable, "banana", "fruit");
insert(hashTable, "carrot", "vegetable");
printHashTable(hashTable);
char* value = search(hashTable, "banana");
printf("Value for key 'banana': %s\n", value);
delete(hashTable, "apple");
printHashTable(hashTable);
return 0;
Conclusion
In this paper, we implemented a dictionary using hashing algorithms in C programming language. We discussed the design and implementation of the dictionary, including the hash function, insertion, search, and deletion operations. The C code provided demonstrates the implementation of the dictionary using hashing algorithms. This implementation provides efficient insertion, search, and deletion operations, making it suitable for a wide range of applications. c program to implement dictionary using hashing algorithms
References
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
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( Abstract A dictionary is a data structure that
(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
dictionary is an abstract data type that maps unique keys to values. Since C lacks a built-in dictionary like Python or C#, you can implement one efficiently using a hash table . This approach provides average constant-time complexity, , for insertion, search, and deletion. 1. Define the Data Structures
A dictionary requires a structure for individual entries (key-value pairs) and a structure for the table itself. To handle collisions—when two different keys produce the same hash—we use Separate Chaining
, where each table index points to a linked list of entries. GeeksforGeeks
// 1. Structure for a single dictionary entry (node in linked list) Entry *next; } Entry; // 2. Structure for the Dictionary (Hash Table) Entry *buckets[TABLE_SIZE]; Dictionary; Use code with caution. Copied to clipboard 2. Implement the Hash Function
The hash function converts a string key into an integer index within the table's bounds. A common and effective algorithm for strings is
, which uses bit-shifting and a prime number (33) to minimize collisions. Stack Overflow hash_val = ((c = *key++)) hash_val = ((hash_val << ) + hash_val) + c; // hash * 33 + c hash_val % TABLE_SIZE; Use code with caution. Copied to clipboard 3. Core Dictionary Operations
These functions manage the lifecycle of entries in the dictionary: Stack Overflow
Deletion requires careful pointer management. Deterministic : Given a key, the hash function
int delete_key(Dictionary *dict, const char *key) unsigned long hash = dict->hash_func(key); unsigned long index = hash % dict->size;Entry *curr = dict->buckets[index]; Entry *prev = NULL; while (curr) if (strcmp(curr->key, key) == 0) if (prev) prev->next = curr->next; else dict->buckets[index] = curr->next; free(curr->key); free(curr->value); free(curr); dict->count--; return 1; // Success prev = curr; curr = curr->next; return 0; // Key not found
Let's analyze the time complexities:
| Operation | Average Case | Worst Case (All Collisions) | |-----------|-------------|-------------------------------| | Insert | O(1) | O(n) | | Search | O(1) | O(n) | | Delete | O(1) | O(n) | | Resize | O(n) amortized | O(n) |
The worst case occurs when all keys hash to the same bucket.
Let’s write each function systematically.
We need to handle:
hash % size).void insert(Dictionary *dict, const char *key, const char *value) unsigned long hash = dict->hash_func(key); unsigned long index = hash % dict->size;// Check if key already exists Entry *curr = dict->buckets[index]; while (curr) if (strcmp(curr->key, key) == 0) // Update existing value free(curr->value); curr->value = strdup(value); return; curr = curr->next; // Create new entry Entry *new_entry = (Entry*)malloc(sizeof(Entry)); new_entry->key = strdup(key); new_entry->value = strdup(value); new_entry->next = dict->buckets[index]; dict->buckets[index] = new_entry; dict->count++; // Check load factor and resize if needed if ((float)dict->count / dict->size > LOAD_FACTOR_THRESHOLD) resize_dictionary(dict);
int delete_key(Dictionary* dict, const char* key) int index = hash(key, dict->size); Entry* curr = dict->buckets[index]; Entry* prev = NULL;while (curr != NULL) if (strcmp(curr->key, key) == 0) if (prev == NULL) // deleting head of chain dict->buckets[index] = curr->next; else prev->next = curr->next; free(curr->key); free(curr); dict->count--; return 1; // success prev = curr; curr = curr->next; return 0; // key not found