w3resource

C Program: Collision Resolution Performance Analysis

C Program to implement Hash Tables: Exercise-8 with Solution

Write a C program that compares the performance of different collision resolution methods (chaining, linear probing, etc.) in terms of speed and memory usage.

Sample Solution:

C Code:

// Including necessary header files
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <chrono>

#define TABLE_SIZE 10000

// Structure for a key-value pair
struct KeyValuePair {
    char key[50];
    char value[50];
    struct KeyValuePair* next;
};

// Structure for the hash table
struct HashTable {
    int size;
    struct KeyValuePair** table;
};

// Hash function for strings (djb2 algorithm)
unsigned long hashFunction(const char* str) {
    unsigned long hash = 5381;
    int c;

    while ((c = *str++) != '\0') {
        hash = ((hash << 5) + hash) + c; // hash * 33 + c
    }

    return hash;
}

// Function to create a new key-value pair
struct KeyValuePair* createKeyValuePair(const char* key, const char* value) {
    struct KeyValuePair* newPair = (struct KeyValuePair*)malloc(sizeof(struct KeyValuePair));
    if (newPair != NULL) {
        strcpy(newPair->key, key);
        strcpy(newPair->value, value);
        newPair->next = NULL;
    }
    return newPair;
}

// Function to create a new hash table
struct HashTable* createHashTable(int size) {
    struct HashTable* newTable = (struct HashTable*)malloc(sizeof(struct HashTable));
    if (newTable != NULL) {
        newTable->size = size;
        newTable->table = (struct KeyValuePair**)calloc(size, sizeof(struct KeyValuePair*));
    }
    return newTable;
}

// Function to insert a key-value pair into the hash table using chaining
void insertChaining(struct HashTable* hashTable, const char* key, const char* value) {
    unsigned long index = hashFunction(key) % hashTable->size;

    // Create a new key-value pair
    struct KeyValuePair* newPair = createKeyValuePair(key, value);

    // Insert the new pair at the beginning of the linked list
    newPair->next = hashTable->table[index];
    hashTable->table[index] = newPair;
}

// Function to retrieve the value associated with a key using chaining
const char* retrieveChaining(struct HashTable* hashTable, const char* key) {
    unsigned long index = hashFunction(key) % hashTable->size;
    struct KeyValuePair* current = hashTable->table[index];

    // Traverse the linked list at the index
    while (current != NULL) {
        if (strcmp(current->key, key) == 0) {
            return current->value; // Key found, return the value
        }
        current = current->next;
    }
    return "Key not found"; // Key not found
}

// Function to free the memory allocated for the hash table using chaining
void freeHashTableChaining(struct HashTable* hashTable) {
    for (int i = 0; i < hashTable->size; i++) {
        struct KeyValuePair* current = hashTable->table[i];
        while (current != NULL) {
            struct KeyValuePair* temp = current;
            current = current->next;
            free(temp);
        }
    }

    free(hashTable->table);
    free(hashTable);
}

// Function to insert a key-value pair into the hash table using linear probing
void insertLinearProbing(struct HashTable* hashTable, const char* key, const char* value) {
    unsigned long index = hashFunction(key) % hashTable->size;

    // Linear probing to find an empty slot
    while (hashTable->table[index] != NULL) {
        index = (index + 1) % hashTable->size;
    }

    // Create a new key-value pair
    struct KeyValuePair* newPair = createKeyValuePair(key, value);
    hashTable->table[index] = newPair;
}

// Function to retrieve the value associated with a key using linear probing
const char* retrieveLinearProbing(struct HashTable* hashTable, const char* key) {
    unsigned long index = hashFunction(key) % hashTable->size;

    // Linear probing to find the key
    while (hashTable->table[index] != NULL) {
        if (strcmp(hashTable->table[index]->key, key) == 0) {
            return hashTable->table[index]->value; // Key found, return the value
        }
        index = (index + 1) % hashTable->size;
    }
    return "Key not found"; // Key not found
}

// Function to free the memory allocated for the hash table using linear probing
void freeHashTableLinearProbing(struct HashTable* hashTable) {
    for (int i = 0; i < hashTable->size; i++) {
        free(hashTable->table[i]);
    }

    free(hashTable->table);
    free(hashTable);
}

// Function to perform performance testing with chaining
void testChaining() {
    struct HashTable* hashTable = createHashTable(TABLE_SIZE);

    // Insert key-value pairs
    for (int i = 0; i < TABLE_SIZE; i++) {
        char key[50];
        char value[50];
        sprintf(key, "Key%d", i);
        sprintf(value, "Value%d", i);
        insertChaining(hashTable, key, value);
    }

    // Retrieve key-value pairs
    for (int i = 0; i < TABLE_SIZE; i++) {
        char key[50];
        sprintf(key, "Key%d", i);
        const char* result = retrieveChaining(hashTable, key);
        printf("Chaining - Retrieved value for key '%s': %s\n", key, result);
    }

    // Free allocated memory
    freeHashTableChaining(hashTable);
}

// Function to perform performance testing with linear probing
void testLinearProbing() {
    struct HashTable* hashTable = createHashTable(TABLE_SIZE);

    // Insert key-value pairs
    for (int i = 0; i < TABLE_SIZE; i++) {
        char key[50];
        char value[50];
        sprintf(key, "Key%d", i);
        sprintf(value, "Value%d", i);
        insertLinearProbing(hashTable, key, value);
    }

    // Retrieve key-value pairs
    for (int i = 0; i < TABLE_SIZE; i++) {
        char key[50];
        sprintf(key, "Key%d", i);
        const char* result = retrieveLinearProbing(hashTable, key);
        printf("Linear Probing - Retrieved value for key '%s': %s\n", key, result);
    }

    // Free allocated memory
    freeHashTableLinearProbing(hashTable);
}

int main() {
    // Perform performance testing with chaining
    auto startChaining = std::chrono::high_resolution_clock::now();
    testChaining();
    auto endChaining = std::chrono::high_resolution_clock::now();
    auto durationChaining = std::chrono::duration_cast<std::chrono::microseconds>(endChaining - startChaining);

    // Perform performance testing with linear probing
    auto startLinearProbing = std::chrono::high_resolution_clock::now();
    testLinearProbing();
    auto endLinearProbing = std::chrono::high_resolution_clock::now();
    auto durationLinearProbing = std::chrono::duration_cast<std::chrono::microseconds>(endLinearProbing - startLinearProbing);

    // Print performance results
    printf("\nPerformance Results:\n");
    printf("Chaining Duration: %lld microseconds\n", durationChaining.count());
    printf("Linear Probing Duration: %lld microseconds\n", durationLinearProbing.count());

    return 0;
}

Output:

Linear Probing - Retrieved value for key 'Key1007': Value1007
Linear Probing - Retrieved value for key 'Key1008': Value1008
Linear Probing - Retrieved value for key 'Key1009': Value1009
Linear Probing - Retrieved value for key 'Key1010': Value1010
Linear Probing - Retrieved value for key 'Key1011': Value1011
Linear Probing - Retrieved value for key 'Key1012': Value1012
Linear Probing - Retrieved value for key 'Key1013': Value1013
Linear Probing - Retrieved value for key 'Key1014': Value1014
Linear Probing - Retrieved value for key 'Key1015': Value1015
Linear Probing - Retrieved value for key 'Key1016': Value1016
Linear Probing - Retrieved value for key 'Key1017': Value1017
Linear Probing - Retrieved value for key 'Key1018': Value1018
Linear Probing - Retrieved value for key 'Key1019': Value1019
-  -  -  -  -  -  -  - -  -  -  -  -  -  -  -  -  - -  -  -  -  -  -  -  -  -  -
-  -  -  -  -  -  -  - -  -  -  -  -  -  -  -  -  - -  -  -  -  -  -  -  -  -  -

Explanation:

In the exercise above,

  • Hash table structure:
    • The program defines a structure 'KeyValuePair' for a key-value pair and a structure 'HashTable' for a hash table.
    • The hash table uses an array of pointers to 'KeyValuePair' structures (struct KeyValuePair** table).
  • Hash function:
    • The hashFunction is a simple hash function (djb2 algorithm) that generates a hash value for a given string.
  • Key-Value Pair Creation:
    • The createKeyValuePair function dynamically allocates memory for a new key-value pair and initializes its fields.
  • Hash table creation:
    • The createHashTable function dynamically allocates memory for a new hash table and initializes its fields.
  • Chaining Operations:
    • insertChaining: Inserts a key-value pair into the hash table using chaining.
    • retrieveChaining: Retrieves the value associated with a key using chaining.
    • freeHashTableChaining: Frees the memory allocated for the hash table using chaining.
  • Linear probing operations:
    • insertLinearProbing: Inserts a key-value pair into the hash table using linear probing.
    • retrieveLinearProbing: Retrieves the value associated with a key using linear probing.
    • freeHashTableLinearProbing: Frees the memory allocated for the hash table using linear probing.
  • Performance testing:
    • The testChaining and testLinearProbing functions perform performance testing for chaining and linear probing, respectively.
    • Key-value pairs are inserted into the hash table, and then retrieval operations are performed.
  • Main functions:
    • The "main()" function measures the duration of the chaining and linear probing tests using the library for timing.
    • The program prints the duration of each test, providing insights into the performance of the two collision resolution methods.

Flowchart:

Flowchart: C Program: Hash Table with Open Addressing.
Flowchart: C Program: Hash Table with Open Addressing.
Flowchart: C Program: Hash Table with Open Addressing.
Flowchart: C Program: Hash Table with Open Addressing.
Flowchart: C Program: Hash Table with Open Addressing.
Flowchart: C Program: Hash Table with Open Addressing.

C Programming Code Editor:

Previous: C Program: Hash Table with Open Addressing.
Next: Creating a Generic Hash table in C for flexible data storage.

What is the difficulty level of this exercise?

Test your Programming skills with w3resource's quiz.



Become a Patron!

Follow us on Facebook and Twitter for latest update.

It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.

https://w3resource.com/c-programming-exercises/hash/c-hash-exercises-8.php