I wrote code that implements perfect hash table, according to its description in the book "Introduction to Algorithms by Thomas H Cormen", but the code does not pass time tests in contest. I would really appreciate any help in making this code run faster (code must be in clear C).
(Regarding Regarding the main function, we enter the number of elements in the set Then the elements themselves. Then requests, we respond to requests with "YES"|"NO" We finish reading requests when we encounter '.')
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#define BUFFER_SIZE 1024 // Size of buffer for input
#define P_VALUE 4294967311
struct Node {
int key;
int value;
};
// Define the structure for the hash table
struct SecondLevelHashTable {
size_t size;
size_t numElements;
struct Node** table;
size_t a;
size_t b;
};
// Define the structure for the hash table
struct FirstLevelHashTable {
size_t size;
size_t numElements;
struct SecondLevelHashTable** table;
size_t a;
size_t b;
};
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m);
// Function to check if a number is prime
bool isPrime(int n);
// Function to find the minimum prime number greater than m
int findNextPrime(int m);
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b);
// Function to initialize node
struct Node* initializeNode(int key, int value);
// Function to create a second-level hash table
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size);
// Function to create a first-level hash table
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size);
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys);
// Function to initialize second-level hash tables based on counts
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts);
// Function to initialize hash for second-level hash tables
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index);
// Function to check if an element exists in the hash table
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable);
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable);
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable);
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m) {
return ((a * key + b) % P_VALUE) % m;
}
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b) {
// Generate random values for a and b
*a = (rand() % (P_VALUE - 1)) + 1; // Ensure a falls within the range [1, p - 1]
*b = rand() % P_VALUE; // Ensure b falls within the range [0, p - 1]
}
// Function to initialize node
struct Node* initializeNode(int key, int value) {
// Allocate memory for the new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
// Handle memory allocation failure
perror("Memory allocation failed");
return NULL;
}
// Assign key and value to the node
newNode->key = key;
newNode->value = value;
return newNode;
}
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct SecondLevelHashTable* secondLevelHashTable = (struct SecondLevelHashTable*)malloc(sizeof(struct SecondLevelHashTable));
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to doubly linked lists
secondLevelHashTable->table = (struct Node**)malloc(size * sizeof(struct Node*));
if (secondLevelHashTable->table == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
secondLevelHashTable->table[i] = NULL;
}
// Set the size and number of elements
secondLevelHashTable->size = size;
secondLevelHashTable->numElements = 0;
return secondLevelHashTable;
}
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct FirstLevelHashTable* firstLevelHashTable = (struct FirstLevelHashTable*)malloc(sizeof(struct FirstLevelHashTable));
if (firstLevelHashTable == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to second-level hash tables
firstLevelHashTable->table = (struct SecondLevelHashTable**)malloc(size * sizeof(struct SecondLevelHashTable*));
if (firstLevelHashTable->table == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
/**
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
firstLevelHashTable->table[i] = createSecondLevelHashTable(1LL<<14);
}
**/
firstLevelHashTable->size = size;
firstLevelHashTable->numElements = 0;
firstLevelHashTable->a = 0;
firstLevelHashTable->b = 0;
generateRandomValues(&firstLevelHashTable->a, &firstLevelHashTable->b);
return firstLevelHashTable;
}
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys) {
// Allocate memory for the array of counts
size_t* counts = (size_t*)calloc(firstLevelHashTable->size, sizeof(size_t));
if (counts == NULL) {
perror("Memory allocation failed");
return NULL;
}
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t hashValue = universalHash(keys[i], firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Increment the count at the corresponding index
counts[hashValue]++;
}
return counts;
}
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts) {
if (firstLevelHashTable == NULL || counts == NULL) {
return;
}
// Iterate over each index in the first-level hash table
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
size_t size = counts[i] * counts[i] + 1; // Get the size from the counts array
// Allocate memory for the second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = createSecondLevelHashTable(size);
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
return;
}
// Assign the second-level hash table to the first-level hash table
firstLevelHashTable->table[i] = secondLevelHashTable;
}
}
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index) {
if (secondLevelHashTable == NULL || keys == NULL) {
return;
}
secondLevelHashTable->a = 0;
secondLevelHashTable->b = 0;
bool isCorrect = true;
do {
generateRandomValues(&secondLevelHashTable->a, &secondLevelHashTable->b);
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t firstHashValue = universalHash(keys[i], firstLevelHashTable->a,
firstLevelHashTable->b,
firstLevelHashTable->size);
// Increment the count at the corresponding index
if (firstHashValue == index) {
size_t secondHashValue = universalHash(keys[i], secondLevelHashTable->a,
secondLevelHashTable->b,
secondLevelHashTable->size);
//printf("%lld\n", secondLevelHashTable->size);
if (secondLevelHashTable->table[secondHashValue] == NULL) {
secondLevelHashTable->table[secondHashValue] = initializeNode(keys[i], 1);
} else {
isCorrect = false;
break;
}
}
}
} while (isCorrect != true);
}
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable) {
// Calculate the hash value for the input key
size_t firstHashValue = universalHash(x, firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Get the corresponding second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[firstHashValue];
if (secondLevelHashTable == NULL) {
return false; // No elements at this index
}
// Calculate the hash value for the input key in the second-level hash table
size_t secondHashValue = universalHash(x, secondLevelHashTable->a, secondLevelHashTable->b, secondLevelHashTable->size);
// Check if the key exists in the second-level hash table
if (secondLevelHashTable->table[secondHashValue] != NULL && secondLevelHashTable->table[secondHashValue]->key == x) {
return true; // Key exists
}
return false; // Key does not exist
}
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable) {
if (firstLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[i];
freeSecondLevelHashTable(secondLevelHashTable);
}
free(firstLevelHashTable->table);
free(firstLevelHashTable);
}
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable) {
if (secondLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < secondLevelHashTable->size; i++) {
free(secondLevelHashTable->table[i]);
}
free(secondLevelHashTable->table);
free(secondLevelHashTable);
}
int main() {
// Seed the random number generator
srand(time(NULL));
size_t num_elements, i;
int query;
char buffer[BUFFER_SIZE];
// Reading the number of elements in the set
if (!fgets(buffer, sizeof(buffer), stdin) || sscanf(buffer, "%zu", &num_elements) != 1 || num_elements <= 0) {
fprintf(stderr, "Error: invalid input for the number of elements.\n");
return EXIT_FAILURE;
}
int* elements = (int*)malloc(num_elements * sizeof(int*));
if (!elements) {
fprintf(stderr, "Error: memory allocation failed.\n");
return EXIT_FAILURE;
}
// Reading the elements of the set
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error: invalid input for elements.\n");
free(elements);
return EXIT_FAILURE;
}
char *token = strtok(buffer, " \t\n");
for (i = 0; i < num_elements; i++) {
if (!token) {
fprintf(stderr, "Error: insufficient elements in the input.\n");
free(elements);
return EXIT_FAILURE;
}
elements[i] = (int)(uintptr_t)strtoull(token, NULL, 10);
token = strtok(NULL, " \t\n");
}
struct FirstLevelHashTable* firstLevelHashTable = createFirstLevelHashTable(1LL << 3);
if (!firstLevelHashTable) {
fprintf(stderr, "Error: failed to create first-level hash table.\n");
free(elements);
return EXIT_FAILURE;
}
size_t* counts = countElementsByHash(elements, firstLevelHashTable, num_elements);
if (!counts) {
fprintf(stderr, "Error: failed to count elements by hash.\n");
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeSecondLevelHashTables(firstLevelHashTable, counts);
for (size_t j = 0; j < firstLevelHashTable->size; j++) {
struct SecondLevelHashTable *secondLevelHashTable = firstLevelHashTable->table[j];
if (!secondLevelHashTable) {
fprintf(stderr, "Error: failed to initialize second-level hash table.\n");
free(counts);
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeHashForSecondHashTables(secondLevelHashTable, firstLevelHashTable,elements,num_elements,j);
}
while (1) {
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error reading input.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
// Check if the input is '.'
if (buffer[0] == '.') {
break; // End of input
}
// Convert input to a long long integer
if (sscanf(buffer, "%lld", &query) != 1) {
fprintf(stderr, "Error: incorrect input format.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
if (locate(query, firstLevelHashTable)) {
printf("YES\n");
} else {
printf("NO\n");
}
}
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_SUCCESS;
}
```
I wrote code that implements perfect hash table, according to its description in the book "Introduction to Algorithms by Thomas H Cormen" but the code does not pass time tests in contest. I would really appreciate any help in making this code run faster (code must be in clear C).
(Regarding the main function, we enter the number of elements in the set Then the elements themselves. Then requests, we respond to requests with "YES"|"NO" We finish reading requests when we encounter '.')
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#define BUFFER_SIZE 1024 // Size of buffer for input
#define P_VALUE 4294967311
struct Node {
int key;
int value;
};
// Define the structure for the hash table
struct SecondLevelHashTable {
size_t size;
size_t numElements;
struct Node** table;
size_t a;
size_t b;
};
// Define the structure for the hash table
struct FirstLevelHashTable {
size_t size;
size_t numElements;
struct SecondLevelHashTable** table;
size_t a;
size_t b;
};
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m);
// Function to check if a number is prime
bool isPrime(int n);
// Function to find the minimum prime number greater than m
int findNextPrime(int m);
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b);
// Function to initialize node
struct Node* initializeNode(int key, int value);
// Function to create a second-level hash table
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size);
// Function to create a first-level hash table
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size);
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys);
// Function to initialize second-level hash tables based on counts
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts);
// Function to initialize hash for second-level hash tables
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index);
// Function to check if an element exists in the hash table
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable);
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable);
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable);
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m) {
return ((a * key + b) % P_VALUE) % m;
}
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b) {
// Generate random values for a and b
*a = (rand() % (P_VALUE - 1)) + 1; // Ensure a falls within the range [1, p - 1]
*b = rand() % P_VALUE; // Ensure b falls within the range [0, p - 1]
}
// Function to initialize node
struct Node* initializeNode(int key, int value) {
// Allocate memory for the new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
// Handle memory allocation failure
perror("Memory allocation failed");
return NULL;
}
// Assign key and value to the node
newNode->key = key;
newNode->value = value;
return newNode;
}
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct SecondLevelHashTable* secondLevelHashTable = (struct SecondLevelHashTable*)malloc(sizeof(struct SecondLevelHashTable));
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to doubly linked lists
secondLevelHashTable->table = (struct Node**)malloc(size * sizeof(struct Node*));
if (secondLevelHashTable->table == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
secondLevelHashTable->table[i] = NULL;
}
// Set the size and number of elements
secondLevelHashTable->size = size;
secondLevelHashTable->numElements = 0;
return secondLevelHashTable;
}
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct FirstLevelHashTable* firstLevelHashTable = (struct FirstLevelHashTable*)malloc(sizeof(struct FirstLevelHashTable));
if (firstLevelHashTable == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to second-level hash tables
firstLevelHashTable->table = (struct SecondLevelHashTable**)malloc(size * sizeof(struct SecondLevelHashTable*));
if (firstLevelHashTable->table == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
/**
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
firstLevelHashTable->table[i] = createSecondLevelHashTable(1LL<<14);
}
**/
firstLevelHashTable->size = size;
firstLevelHashTable->numElements = 0;
firstLevelHashTable->a = 0;
firstLevelHashTable->b = 0;
generateRandomValues(&firstLevelHashTable->a, &firstLevelHashTable->b);
return firstLevelHashTable;
}
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys) {
// Allocate memory for the array of counts
size_t* counts = (size_t*)calloc(firstLevelHashTable->size, sizeof(size_t));
if (counts == NULL) {
perror("Memory allocation failed");
return NULL;
}
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t hashValue = universalHash(keys[i], firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Increment the count at the corresponding index
counts[hashValue]++;
}
return counts;
}
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts) {
if (firstLevelHashTable == NULL || counts == NULL) {
return;
}
// Iterate over each index in the first-level hash table
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
size_t size = counts[i] * counts[i] + 1; // Get the size from the counts array
// Allocate memory for the second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = createSecondLevelHashTable(size);
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
return;
}
// Assign the second-level hash table to the first-level hash table
firstLevelHashTable->table[i] = secondLevelHashTable;
}
}
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index) {
if (secondLevelHashTable == NULL || keys == NULL) {
return;
}
secondLevelHashTable->a = 0;
secondLevelHashTable->b = 0;
bool isCorrect = true;
do {
generateRandomValues(&secondLevelHashTable->a, &secondLevelHashTable->b);
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t firstHashValue = universalHash(keys[i], firstLevelHashTable->a,
firstLevelHashTable->b,
firstLevelHashTable->size);
// Increment the count at the corresponding index
if (firstHashValue == index) {
size_t secondHashValue = universalHash(keys[i], secondLevelHashTable->a,
secondLevelHashTable->b,
secondLevelHashTable->size);
//printf("%lld\n", secondLevelHashTable->size);
if (secondLevelHashTable->table[secondHashValue] == NULL) {
secondLevelHashTable->table[secondHashValue] = initializeNode(keys[i], 1);
} else {
isCorrect = false;
break;
}
}
}
} while (isCorrect != true);
}
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable) {
// Calculate the hash value for the input key
size_t firstHashValue = universalHash(x, firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Get the corresponding second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[firstHashValue];
if (secondLevelHashTable == NULL) {
return false; // No elements at this index
}
// Calculate the hash value for the input key in the second-level hash table
size_t secondHashValue = universalHash(x, secondLevelHashTable->a, secondLevelHashTable->b, secondLevelHashTable->size);
// Check if the key exists in the second-level hash table
if (secondLevelHashTable->table[secondHashValue] != NULL && secondLevelHashTable->table[secondHashValue]->key == x) {
return true; // Key exists
}
return false; // Key does not exist
}
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable) {
if (firstLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[i];
freeSecondLevelHashTable(secondLevelHashTable);
}
free(firstLevelHashTable->table);
free(firstLevelHashTable);
}
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable) {
if (secondLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < secondLevelHashTable->size; i++) {
free(secondLevelHashTable->table[i]);
}
free(secondLevelHashTable->table);
free(secondLevelHashTable);
}
int main() {
// Seed the random number generator
srand(time(NULL));
size_t num_elements, i;
int query;
char buffer[BUFFER_SIZE];
// Reading the number of elements in the set
if (!fgets(buffer, sizeof(buffer), stdin) || sscanf(buffer, "%zu", &num_elements) != 1 || num_elements <= 0) {
fprintf(stderr, "Error: invalid input for the number of elements.\n");
return EXIT_FAILURE;
}
int* elements = (int*)malloc(num_elements * sizeof(int*));
if (!elements) {
fprintf(stderr, "Error: memory allocation failed.\n");
return EXIT_FAILURE;
}
// Reading the elements of the set
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error: invalid input for elements.\n");
free(elements);
return EXIT_FAILURE;
}
char *token = strtok(buffer, " \t\n");
for (i = 0; i < num_elements; i++) {
if (!token) {
fprintf(stderr, "Error: insufficient elements in the input.\n");
free(elements);
return EXIT_FAILURE;
}
elements[i] = (int)(uintptr_t)strtoull(token, NULL, 10);
token = strtok(NULL, " \t\n");
}
struct FirstLevelHashTable* firstLevelHashTable = createFirstLevelHashTable(1LL << 3);
if (!firstLevelHashTable) {
fprintf(stderr, "Error: failed to create first-level hash table.\n");
free(elements);
return EXIT_FAILURE;
}
size_t* counts = countElementsByHash(elements, firstLevelHashTable, num_elements);
if (!counts) {
fprintf(stderr, "Error: failed to count elements by hash.\n");
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeSecondLevelHashTables(firstLevelHashTable, counts);
for (size_t j = 0; j < firstLevelHashTable->size; j++) {
struct SecondLevelHashTable *secondLevelHashTable = firstLevelHashTable->table[j];
if (!secondLevelHashTable) {
fprintf(stderr, "Error: failed to initialize second-level hash table.\n");
free(counts);
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeHashForSecondHashTables(secondLevelHashTable, firstLevelHashTable,elements,num_elements,j);
}
while (1) {
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error reading input.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
// Check if the input is '.'
if (buffer[0] == '.') {
break; // End of input
}
// Convert input to a long long integer
if (sscanf(buffer, "%lld", &query) != 1) {
fprintf(stderr, "Error: incorrect input format.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
if (locate(query, firstLevelHashTable)) {
printf("YES\n");
} else {
printf("NO\n");
}
}
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_SUCCESS;
}
```
I wrote code that implements perfect hash table, according to its description in the book "Introduction to Algorithms by Thomas H Cormen", but the code does not pass time tests in contest. I would really appreciate any help in making this code run faster (code must be in clear C).
Regarding the main function, we enter the number of elements in the set Then the elements themselves. Then requests, we respond to requests with "YES"|"NO" We finish reading requests when we encounter '.'
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#define BUFFER_SIZE 1024 // Size of buffer for input
#define P_VALUE 4294967311
struct Node {
int key;
int value;
};
// Define the structure for the hash table
struct SecondLevelHashTable {
size_t size;
size_t numElements;
struct Node** table;
size_t a;
size_t b;
};
// Define the structure for the hash table
struct FirstLevelHashTable {
size_t size;
size_t numElements;
struct SecondLevelHashTable** table;
size_t a;
size_t b;
};
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m);
// Function to check if a number is prime
bool isPrime(int n);
// Function to find the minimum prime number greater than m
int findNextPrime(int m);
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b);
// Function to initialize node
struct Node* initializeNode(int key, int value);
// Function to create a second-level hash table
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size);
// Function to create a first-level hash table
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size);
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys);
// Function to initialize second-level hash tables based on counts
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts);
// Function to initialize hash for second-level hash tables
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index);
// Function to check if an element exists in the hash table
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable);
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable);
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable);
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m) {
return ((a * key + b) % P_VALUE) % m;
}
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b) {
// Generate random values for a and b
*a = (rand() % (P_VALUE - 1)) + 1; // Ensure a falls within the range [1, p - 1]
*b = rand() % P_VALUE; // Ensure b falls within the range [0, p - 1]
}
// Function to initialize node
struct Node* initializeNode(int key, int value) {
// Allocate memory for the new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
// Handle memory allocation failure
perror("Memory allocation failed");
return NULL;
}
// Assign key and value to the node
newNode->key = key;
newNode->value = value;
return newNode;
}
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct SecondLevelHashTable* secondLevelHashTable = (struct SecondLevelHashTable*)malloc(sizeof(struct SecondLevelHashTable));
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to doubly linked lists
secondLevelHashTable->table = (struct Node**)malloc(size * sizeof(struct Node*));
if (secondLevelHashTable->table == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
secondLevelHashTable->table[i] = NULL;
}
// Set the size and number of elements
secondLevelHashTable->size = size;
secondLevelHashTable->numElements = 0;
return secondLevelHashTable;
}
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct FirstLevelHashTable* firstLevelHashTable = (struct FirstLevelHashTable*)malloc(sizeof(struct FirstLevelHashTable));
if (firstLevelHashTable == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to second-level hash tables
firstLevelHashTable->table = (struct SecondLevelHashTable**)malloc(size * sizeof(struct SecondLevelHashTable*));
if (firstLevelHashTable->table == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
/**
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
firstLevelHashTable->table[i] = createSecondLevelHashTable(1LL<<14);
}
**/
firstLevelHashTable->size = size;
firstLevelHashTable->numElements = 0;
firstLevelHashTable->a = 0;
firstLevelHashTable->b = 0;
generateRandomValues(&firstLevelHashTable->a, &firstLevelHashTable->b);
return firstLevelHashTable;
}
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys) {
// Allocate memory for the array of counts
size_t* counts = (size_t*)calloc(firstLevelHashTable->size, sizeof(size_t));
if (counts == NULL) {
perror("Memory allocation failed");
return NULL;
}
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t hashValue = universalHash(keys[i], firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Increment the count at the corresponding index
counts[hashValue]++;
}
return counts;
}
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts) {
if (firstLevelHashTable == NULL || counts == NULL) {
return;
}
// Iterate over each index in the first-level hash table
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
size_t size = counts[i] * counts[i] + 1; // Get the size from the counts array
// Allocate memory for the second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = createSecondLevelHashTable(size);
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
return;
}
// Assign the second-level hash table to the first-level hash table
firstLevelHashTable->table[i] = secondLevelHashTable;
}
}
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index) {
if (secondLevelHashTable == NULL || keys == NULL) {
return;
}
secondLevelHashTable->a = 0;
secondLevelHashTable->b = 0;
bool isCorrect = true;
do {
generateRandomValues(&secondLevelHashTable->a, &secondLevelHashTable->b);
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t firstHashValue = universalHash(keys[i], firstLevelHashTable->a,
firstLevelHashTable->b,
firstLevelHashTable->size);
// Increment the count at the corresponding index
if (firstHashValue == index) {
size_t secondHashValue = universalHash(keys[i], secondLevelHashTable->a,
secondLevelHashTable->b,
secondLevelHashTable->size);
//printf("%lld\n", secondLevelHashTable->size);
if (secondLevelHashTable->table[secondHashValue] == NULL) {
secondLevelHashTable->table[secondHashValue] = initializeNode(keys[i], 1);
} else {
isCorrect = false;
break;
}
}
}
} while (isCorrect != true);
}
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable) {
// Calculate the hash value for the input key
size_t firstHashValue = universalHash(x, firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Get the corresponding second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[firstHashValue];
if (secondLevelHashTable == NULL) {
return false; // No elements at this index
}
// Calculate the hash value for the input key in the second-level hash table
size_t secondHashValue = universalHash(x, secondLevelHashTable->a, secondLevelHashTable->b, secondLevelHashTable->size);
// Check if the key exists in the second-level hash table
if (secondLevelHashTable->table[secondHashValue] != NULL && secondLevelHashTable->table[secondHashValue]->key == x) {
return true; // Key exists
}
return false; // Key does not exist
}
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable) {
if (firstLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[i];
freeSecondLevelHashTable(secondLevelHashTable);
}
free(firstLevelHashTable->table);
free(firstLevelHashTable);
}
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable) {
if (secondLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < secondLevelHashTable->size; i++) {
free(secondLevelHashTable->table[i]);
}
free(secondLevelHashTable->table);
free(secondLevelHashTable);
}
int main() {
// Seed the random number generator
srand(time(NULL));
size_t num_elements, i;
int query;
char buffer[BUFFER_SIZE];
// Reading the number of elements in the set
if (!fgets(buffer, sizeof(buffer), stdin) || sscanf(buffer, "%zu", &num_elements) != 1 || num_elements <= 0) {
fprintf(stderr, "Error: invalid input for the number of elements.\n");
return EXIT_FAILURE;
}
int* elements = (int*)malloc(num_elements * sizeof(int*));
if (!elements) {
fprintf(stderr, "Error: memory allocation failed.\n");
return EXIT_FAILURE;
}
// Reading the elements of the set
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error: invalid input for elements.\n");
free(elements);
return EXIT_FAILURE;
}
char *token = strtok(buffer, " \t\n");
for (i = 0; i < num_elements; i++) {
if (!token) {
fprintf(stderr, "Error: insufficient elements in the input.\n");
free(elements);
return EXIT_FAILURE;
}
elements[i] = (int)(uintptr_t)strtoull(token, NULL, 10);
token = strtok(NULL, " \t\n");
}
struct FirstLevelHashTable* firstLevelHashTable = createFirstLevelHashTable(1LL << 3);
if (!firstLevelHashTable) {
fprintf(stderr, "Error: failed to create first-level hash table.\n");
free(elements);
return EXIT_FAILURE;
}
size_t* counts = countElementsByHash(elements, firstLevelHashTable, num_elements);
if (!counts) {
fprintf(stderr, "Error: failed to count elements by hash.\n");
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeSecondLevelHashTables(firstLevelHashTable, counts);
for (size_t j = 0; j < firstLevelHashTable->size; j++) {
struct SecondLevelHashTable *secondLevelHashTable = firstLevelHashTable->table[j];
if (!secondLevelHashTable) {
fprintf(stderr, "Error: failed to initialize second-level hash table.\n");
free(counts);
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeHashForSecondHashTables(secondLevelHashTable, firstLevelHashTable,elements,num_elements,j);
}
while (1) {
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error reading input.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
// Check if the input is '.'
if (buffer[0] == '.') {
break; // End of input
}
// Convert input to a long long integer
if (sscanf(buffer, "%lld", &query) != 1) {
fprintf(stderr, "Error: incorrect input format.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
if (locate(query, firstLevelHashTable)) {
printf("YES\n");
} else {
printf("NO\n");
}
}
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_SUCCESS;
}
Optimizing Perfect Hash Table Implementation in C for Improved Performance
I wrote code that implements perfect hash table, according to its description in the book "Introduction to Algorithms by Thomas H Cormen" but the code does not pass time tests in contest. I would really appreciate any help in making this code run faster (code must be in clear C).
(Regarding the main function, we enter the number of elements in the set Then the elements themselves. Then requests, we respond to requests with "YES"|"NO" We finish reading requests when we encounter '.')
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
#define BUFFER_SIZE 1024 // Size of buffer for input
#define P_VALUE 4294967311
struct Node {
int key;
int value;
};
// Define the structure for the hash table
struct SecondLevelHashTable {
size_t size;
size_t numElements;
struct Node** table;
size_t a;
size_t b;
};
// Define the structure for the hash table
struct FirstLevelHashTable {
size_t size;
size_t numElements;
struct SecondLevelHashTable** table;
size_t a;
size_t b;
};
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m);
// Function to check if a number is prime
bool isPrime(int n);
// Function to find the minimum prime number greater than m
int findNextPrime(int m);
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b);
// Function to initialize node
struct Node* initializeNode(int key, int value);
// Function to create a second-level hash table
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size);
// Function to create a first-level hash table
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size);
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys);
// Function to initialize second-level hash tables based on counts
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts);
// Function to initialize hash for second-level hash tables
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index);
// Function to check if an element exists in the hash table
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable);
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable);
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable);
// Define the hash function
size_t universalHash(int key, size_t a, size_t b, size_t m) {
return ((a * key + b) % P_VALUE) % m;
}
// Function to generate random values for a and b
void generateRandomValues(size_t *a, size_t *b) {
// Generate random values for a and b
*a = (rand() % (P_VALUE - 1)) + 1; // Ensure a falls within the range [1, p - 1]
*b = rand() % P_VALUE; // Ensure b falls within the range [0, p - 1]
}
// Function to initialize node
struct Node* initializeNode(int key, int value) {
// Allocate memory for the new node
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (newNode == NULL) {
// Handle memory allocation failure
perror("Memory allocation failed");
return NULL;
}
// Assign key and value to the node
newNode->key = key;
newNode->value = value;
return newNode;
}
struct SecondLevelHashTable* createSecondLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct SecondLevelHashTable* secondLevelHashTable = (struct SecondLevelHashTable*)malloc(sizeof(struct SecondLevelHashTable));
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to doubly linked lists
secondLevelHashTable->table = (struct Node**)malloc(size * sizeof(struct Node*));
if (secondLevelHashTable->table == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
secondLevelHashTable->table[i] = NULL;
}
// Set the size and number of elements
secondLevelHashTable->size = size;
secondLevelHashTable->numElements = 0;
return secondLevelHashTable;
}
struct FirstLevelHashTable* createFirstLevelHashTable(size_t size) {
// Allocate memory for the hash table structure
struct FirstLevelHashTable* firstLevelHashTable = (struct FirstLevelHashTable*)malloc(sizeof(struct FirstLevelHashTable));
if (firstLevelHashTable == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
// Allocate memory for the array of pointers to second-level hash tables
firstLevelHashTable->table = (struct SecondLevelHashTable**)malloc(size * sizeof(struct SecondLevelHashTable*));
if (firstLevelHashTable->table == NULL) {
freeFirstLevelHashTable(firstLevelHashTable);
perror("Memory allocation failed");
return NULL;
}
/**
// Initialize each pointer in the array to NULL
for (int i = 0; i < size; i++) {
firstLevelHashTable->table[i] = createSecondLevelHashTable(1LL<<14);
}
**/
firstLevelHashTable->size = size;
firstLevelHashTable->numElements = 0;
firstLevelHashTable->a = 0;
firstLevelHashTable->b = 0;
generateRandomValues(&firstLevelHashTable->a, &firstLevelHashTable->b);
return firstLevelHashTable;
}
// Function to create an array of counts based on hash function results
size_t* countElementsByHash(int* keys, struct FirstLevelHashTable *firstLevelHashTable, size_t numKeys) {
// Allocate memory for the array of counts
size_t* counts = (size_t*)calloc(firstLevelHashTable->size, sizeof(size_t));
if (counts == NULL) {
perror("Memory allocation failed");
return NULL;
}
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t hashValue = universalHash(keys[i], firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Increment the count at the corresponding index
counts[hashValue]++;
}
return counts;
}
void initializeSecondLevelHashTables(struct FirstLevelHashTable* firstLevelHashTable, size_t* counts) {
if (firstLevelHashTable == NULL || counts == NULL) {
return;
}
// Iterate over each index in the first-level hash table
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
size_t size = counts[i] * counts[i] + 1; // Get the size from the counts array
// Allocate memory for the second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = createSecondLevelHashTable(size);
if (secondLevelHashTable == NULL) {
freeSecondLevelHashTable(secondLevelHashTable);
return;
}
// Assign the second-level hash table to the first-level hash table
firstLevelHashTable->table[i] = secondLevelHashTable;
}
}
void initializeHashForSecondHashTables(struct SecondLevelHashTable* secondLevelHashTable, struct FirstLevelHashTable* firstLevelHashTable, int* keys, size_t numKeys, size_t index) {
if (secondLevelHashTable == NULL || keys == NULL) {
return;
}
secondLevelHashTable->a = 0;
secondLevelHashTable->b = 0;
bool isCorrect = true;
do {
generateRandomValues(&secondLevelHashTable->a, &secondLevelHashTable->b);
// Iterate over each key
for (size_t i = 0; i < numKeys; i++) {
// Calculate the hash value for the current key
size_t firstHashValue = universalHash(keys[i], firstLevelHashTable->a,
firstLevelHashTable->b,
firstLevelHashTable->size);
// Increment the count at the corresponding index
if (firstHashValue == index) {
size_t secondHashValue = universalHash(keys[i], secondLevelHashTable->a,
secondLevelHashTable->b,
secondLevelHashTable->size);
//printf("%lld\n", secondLevelHashTable->size);
if (secondLevelHashTable->table[secondHashValue] == NULL) {
secondLevelHashTable->table[secondHashValue] = initializeNode(keys[i], 1);
} else {
isCorrect = false;
break;
}
}
}
} while (isCorrect != true);
}
bool locate(int x, struct FirstLevelHashTable* firstLevelHashTable) {
// Calculate the hash value for the input key
size_t firstHashValue = universalHash(x, firstLevelHashTable->a, firstLevelHashTable->b, firstLevelHashTable->size);
// Get the corresponding second-level hash table
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[firstHashValue];
if (secondLevelHashTable == NULL) {
return false; // No elements at this index
}
// Calculate the hash value for the input key in the second-level hash table
size_t secondHashValue = universalHash(x, secondLevelHashTable->a, secondLevelHashTable->b, secondLevelHashTable->size);
// Check if the key exists in the second-level hash table
if (secondLevelHashTable->table[secondHashValue] != NULL && secondLevelHashTable->table[secondHashValue]->key == x) {
return true; // Key exists
}
return false; // Key does not exist
}
void freeFirstLevelHashTable(struct FirstLevelHashTable* firstLevelHashTable) {
if (firstLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < firstLevelHashTable->size; ++i) {
struct SecondLevelHashTable* secondLevelHashTable = firstLevelHashTable->table[i];
freeSecondLevelHashTable(secondLevelHashTable);
}
free(firstLevelHashTable->table);
free(firstLevelHashTable);
}
void freeSecondLevelHashTable(struct SecondLevelHashTable* secondLevelHashTable) {
if (secondLevelHashTable == NULL) {
return;
}
for (size_t i = 0; i < secondLevelHashTable->size; i++) {
free(secondLevelHashTable->table[i]);
}
free(secondLevelHashTable->table);
free(secondLevelHashTable);
}
int main() {
// Seed the random number generator
srand(time(NULL));
size_t num_elements, i;
int query;
char buffer[BUFFER_SIZE];
// Reading the number of elements in the set
if (!fgets(buffer, sizeof(buffer), stdin) || sscanf(buffer, "%zu", &num_elements) != 1 || num_elements <= 0) {
fprintf(stderr, "Error: invalid input for the number of elements.\n");
return EXIT_FAILURE;
}
int* elements = (int*)malloc(num_elements * sizeof(int*));
if (!elements) {
fprintf(stderr, "Error: memory allocation failed.\n");
return EXIT_FAILURE;
}
// Reading the elements of the set
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error: invalid input for elements.\n");
free(elements);
return EXIT_FAILURE;
}
char *token = strtok(buffer, " \t\n");
for (i = 0; i < num_elements; i++) {
if (!token) {
fprintf(stderr, "Error: insufficient elements in the input.\n");
free(elements);
return EXIT_FAILURE;
}
elements[i] = (int)(uintptr_t)strtoull(token, NULL, 10);
token = strtok(NULL, " \t\n");
}
struct FirstLevelHashTable* firstLevelHashTable = createFirstLevelHashTable(1LL << 3);
if (!firstLevelHashTable) {
fprintf(stderr, "Error: failed to create first-level hash table.\n");
free(elements);
return EXIT_FAILURE;
}
size_t* counts = countElementsByHash(elements, firstLevelHashTable, num_elements);
if (!counts) {
fprintf(stderr, "Error: failed to count elements by hash.\n");
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeSecondLevelHashTables(firstLevelHashTable, counts);
for (size_t j = 0; j < firstLevelHashTable->size; j++) {
struct SecondLevelHashTable *secondLevelHashTable = firstLevelHashTable->table[j];
if (!secondLevelHashTable) {
fprintf(stderr, "Error: failed to initialize second-level hash table.\n");
free(counts);
free(firstLevelHashTable);
free(elements);
return EXIT_FAILURE;
}
initializeHashForSecondHashTables(secondLevelHashTable, firstLevelHashTable,elements,num_elements,j);
}
while (1) {
if (!fgets(buffer, sizeof(buffer), stdin)) {
fprintf(stderr, "Error reading input.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
// Check if the input is '.'
if (buffer[0] == '.') {
break; // End of input
}
// Convert input to a long long integer
if (sscanf(buffer, "%lld", &query) != 1) {
fprintf(stderr, "Error: incorrect input format.\n");
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_FAILURE;
}
if (locate(query, firstLevelHashTable)) {
printf("YES\n");
} else {
printf("NO\n");
}
}
freeFirstLevelHashTable(firstLevelHashTable);
free(elements);
free(counts);
return EXIT_SUCCESS;
}
```