diff --git a/hashtable.c b/hashtable.c index 0d286e44ae75b609cf8f8475fab4f6be8b6d0da0..7e2c0dd9c5ef9d6a94b36e894d66dafc4419a3ea 100644 --- a/hashtable.c +++ b/hashtable.c @@ -8,30 +8,156 @@ #include <stdlib.h> #include <string.h> +int hash(char *key, int64_t length) { + // If the size of the int is too low the hash methods will generate overflow errors + int64_t val = 0; + for (size_t i = 0; i < strlen(key); i++) { + val = 43 * val + key[i]; + } + return (val % length); +} + +entry *entry_create_empty() { + entry *e = malloc(sizeof(entry)); + e->key = NULL; + e->value = NULL; + e->next = NULL; + return e; +} + hm *hm_create(unsigned int length) { - return NULL; + hm *hashmap = malloc(sizeof(hm)); + hashmap->length = length; + hashmap->entries = malloc(sizeof(entry) * length); + for (size_t i = 0; i < length; i++) { + hashmap->entries[i] = entry_create_empty(); + } + + return hashmap; } -void hm_destroy(hm **hm) { +entry *get_entry_by_key(entry *e, char *key) { + if (e->key == key) { + return e; + } else if (e->next != NULL) { + return get_entry_by_key(e->next, key); + } else { + return e; + } +} +void hm_destroy(hm **hm) { + for (int i = 0; i < (*hm)->length; i++) { + entry *e = (*hm)->entries[i]; + while (e != NULL) { + entry *to_free = e; + e = e->next; + free(to_free); + } + } + free((*hm)->entries); + free((*hm)); + (*hm) = NULL; } hm *hm_set(hm *hm, const char *const key, const char *const value) { - return NULL; + // Hash the key and get the corresponding entry + int key_index = hash((char *)key, hm->length); + entry *e = get_entry_by_key(hm->entries[key_index], (char *)key); + + // Set the key and create the next entry if the key is not existing + if (e->key != key) { + e->key = (char *)key; + if (e->next == NULL) { + e->next = entry_create_empty(); + } + } + + // Set the entry value and return the hashmap + e->value = (char *)value; + return hm; } char *hm_get(const hm *const hm, const char *const key) { - return NULL; + int key_index = hash((char *)key, hm->length); + char *c = get_entry_by_key(hm->entries[key_index], (char *)key)->value; + return c; } char *hm_rm(hm *hm, const char *const key) { - return NULL; + int key_index = hash((char *)key, hm->length); + entry *e = get_entry_by_key(hm->entries[key_index], (char *)key); + entry *previous_entry = NULL; + entry *current_entry = hm->entries[key_index]; + int entry_index = 0; + + while (current_entry != e) { + previous_entry = current_entry; + current_entry = current_entry->next; + entry_index++; + } + + if (entry_index == 0) { + hm->entries[key_index] = hm->entries[key_index]->next; + } else if (previous_entry != NULL) { + previous_entry->next = e->next; + } + + char *entry_key = e->key; + free(e); + e = NULL; + return entry_key; +} + +int get_entry_list_size(entry *e) { + int size = 0; + size += sizeof(e->key) + sizeof(e->value) + 16; + if (e->next != NULL) { + size += get_entry_list_size(e->next); + } + return size; } -char *hmo_str(const hm *const hm) { - return NULL; +char *hm_to_str(const hm *const hm) { + int str_size = sizeof(hm) * hm->length; + for (int i = 0; i < hm->length; i++) { + str_size += get_entry_list_size(hm->entries[i]); + } + + char *hm_str = malloc(str_size); + // Ensure that the string is empty before doing anything + hm_str[0] = '\0'; + + strcat(hm_str, "[\n"); + for (int i = 0; i < hm->length; i++) { + strcat(hm_str, " [\n"); + entry *e = hm->entries[i]; + while (e != NULL && e->key != NULL) { + strcat(hm_str, " [\""); + strcat(hm_str, e->key); + strcat(hm_str, "\": \""); + strcat(hm_str, e->value); + strcat(hm_str, "\"]"); + if (e->next != NULL && e->next->key != NULL) { + strcat(hm_str, ","); + } + strcat(hm_str, "\n"); + e = e->next; + } + + strcat(hm_str, " ]"); + if (i < hm->length - 1) { + strcat(hm_str, ","); + } + strcat(hm_str, "\n"); + } + + strcat(hm_str, "]\n"); + return hm_str; } void hm_print(const hm *const hm) { - return NULL; + char *str = hm_to_str(hm); + printf("%s\n", str); + free(str); } diff --git a/main.c b/main.c index df0280e64212cccf9b2028951c8713148afd51ff..354750d38c22c7b42850d723360c65dcd019062c 100644 --- a/main.c +++ b/main.c @@ -5,7 +5,60 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include "hashtable.h" int main() { + srand(0); + hm *hashmap = hm_create(5); + + while (true) { + printf("Add (1), Delete (2), Search (3), Print (4), Exit (5)...\n"); + int selection; + scanf("%d", &selection); + if (selection < 1 || selection > 5) { + printf("Bad input, try again.\n"); + continue; + } + char phone[10]; + char name[10]; + + if (selection == 1) { + printf("Phone :\n"); + scanf("%s", phone); + printf("Name :\n"); + scanf("%s", name); + char *p = strdup(phone); + char *n = strdup(name); + hm_set(hashmap, p, n); + hm_print(hashmap); + free(n); + free(p); + } + if (selection == 2) { + printf("Phone to delete :\n"); + scanf("%s", phone); + hm_rm(hashmap, phone); + hm_print(hashmap); + } + if (selection == 3) { + printf("Phone to search :\n"); + scanf("%s", phone); + char *p = strdup(phone); + char *name = hm_get(hashmap, p); + if (name != NULL) { + printf("%s\n", name); + } + } + if (selection == 4) { + hm_print(hashmap); + } + if (selection == 5) { + break; + } + } + + hm_destroy(&hashmap); + return EXIT_SUCCESS; }