diff --git a/0x1A-hash_tables/0-hash_table_create.c b/0x1A-hash_tables/0-hash_table_create.c new file mode 100644 index 0000000..4a63dcf --- /dev/null +++ b/0x1A-hash_tables/0-hash_table_create.c @@ -0,0 +1,27 @@ +#include "hash_tables.h" + +/** + * hash_table_create - creates a hash table + * @size: size of the array + * + * Return: pointer to the newly created hash table + */ +hash_table_t *hash_table_create(unsigned long int size) +{ + hash_table_t *hash_table; + unsigned long int i; + + hash_table = malloc(sizeof(hash_table_t)); + if (hash_table == NULL) + return (NULL); + hash_table->size = size; + hash_table->array = malloc(size * sizeof(hash_node_t *)); + if (hash_table->array == NULL) + { + free(hash_table); + return (NULL); + } + for (i = 0; i < size; i++) + hash_table->array[i] = NULL; + return (hash_table); +} diff --git a/0x1A-hash_tables/1-djb2.c b/0x1A-hash_tables/1-djb2.c new file mode 100644 index 0000000..acd997d --- /dev/null +++ b/0x1A-hash_tables/1-djb2.c @@ -0,0 +1,20 @@ +#include "hash_tables.h" + +/** + * hash_djb2 - implementation of the djb2 algorithm + * @str: string used to generate hash value + * + * Return: hash value + */ +unsigned long int hash_djb2(const unsigned char *str) +{ + unsigned long int hash; + int c; + + hash = 5381; + while ((c = *str++)) + { + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + } + return (hash); +} diff --git a/0x1A-hash_tables/100-sorted_hash_table.c b/0x1A-hash_tables/100-sorted_hash_table.c new file mode 100644 index 0000000..111c28c --- /dev/null +++ b/0x1A-hash_tables/100-sorted_hash_table.c @@ -0,0 +1,249 @@ +#include "hash_tables.h" + +/** + * shash_table_create - creates a sorted hash table + * @size: size of the hash table + * + * Return: pointer to the new table, or NULL on failure + */ +shash_table_t *shash_table_create(unsigned long int size) +{ + shash_table_t *sht; + unsigned long int i; + + sht = malloc(sizeof(shash_table_t)); + if (sht == NULL) + return (NULL); + sht->size = size; + sht->shead = NULL; + sht->stail = NULL; + sht->array = malloc(sizeof(shash_node_t) * size); + if (sht->array == NULL) + { + free(sht); + return (NULL); + } + for (i = 0; i < size; i++) + { + sht->array[i] = NULL; + } + return (sht); +} + +/** + * make_shash_node - makes a node for the sorted hash table + * @key: key for the data + * @value: data to be stored + * + * Return: pointer to the new node, or NULL on failure + */ +shash_node_t *make_shash_node(const char *key, const char *value) +{ + shash_node_t *shn; + + shn = malloc(sizeof(shash_node_t)); + if (shn == NULL) + return (NULL); + shn->key = strdup(key); + if (shn->key == NULL) + { + free(shn); + return (NULL); + } + shn->value = strdup(value); + if (shn->value == NULL) + { + free(shn->key); + free(shn); + return (NULL); + } + shn->next = shn->snext = shn->sprev = NULL; + return (shn); +} + +/** + * add_to_sorted_list - add a node to the sorted (by key's ASCII) linked list + * @table: the sorted hash table + * @node: the node to add + * + * Return: void + */ +void add_to_sorted_list(shash_table_t *table, shash_node_t *node) +{ + shash_node_t *tmp; + + if (table->shead == NULL && table->stail == NULL) + { + table->shead = table->stail = node; + return; + } + tmp = table->shead; + while (tmp != NULL) + { + if (strcmp(node->key, tmp->key) < 0) + { + node->snext = tmp; + node->sprev = tmp->sprev; + tmp->sprev = node; + if (node->sprev != NULL) + node->sprev->snext = node; + else + table->shead = node; + return; + } + tmp = tmp->snext; + } + node->sprev = table->stail; + table->stail->snext = node; + table->stail = node; +} + +/** + * shash_table_set - sets a key to a value in the hash table + * @ht: sorted hash table + * @key: key to the data + * @value: data to add + * + * Return: 1 on success, 0 otherwise + */ +int shash_table_set(shash_table_t *ht, const char *key, const char *value) +{ + unsigned long int index; + char *new_value; + shash_node_t *shn, *tmp; + + if (ht == NULL || ht->array == NULL || ht->size == 0 || + key == NULL || strlen(key) == 0 || value == NULL) + return (0); + index = key_index((const unsigned char *)key, ht->size); + tmp = ht->array[index]; + while (tmp != NULL) + { + if (strcmp(tmp->key, key) == 0) + { + new_value = strdup(value); + if (new_value == NULL) + return (0); + free(tmp->value); + tmp->value = new_value; + return (1); + } + tmp = tmp->next; + } + shn = make_shash_node(key, value); + if (shn == NULL) + return (0); + shn->next = ht->array[index]; + ht->array[index] = shn; + add_to_sorted_list(ht, shn); + return (1); +} + +/** + * shash_table_get - retrieve a value from the hash table + * @ht: hash table + * @key: key to the data + * + * Return: the value associated with key, or NULL on failure + */ +char *shash_table_get(const shash_table_t *ht, const char *key) +{ + unsigned long int index; + shash_node_t *tmp; + + if (ht == NULL || ht->array == NULL || ht->size == 0 || + key == NULL || strlen(key) == 0) + return (NULL); + index = key_index((const unsigned char *)key, ht->size); + tmp = ht->array[index]; + while (tmp != NULL) + { + if (strcmp(tmp->key, key) == 0) + return (tmp->value); + tmp = tmp->next; + } + return (NULL); +} + +/** + * shash_table_print - prints a sorted hash table + * @ht: hash table to print + * + * Return: void + */ +void shash_table_print(const shash_table_t *ht) +{ + shash_node_t *tmp; + char flag = 0; /* 0 before printing any data, 1 after*/ + + if (ht == NULL || ht->array == NULL) + return; + printf("{"); + tmp = ht->shead; + while (tmp != NULL) + { + if (flag == 1) + printf(", "); + printf("'%s': '%s'", tmp->key, tmp->value); + flag = 1; + tmp = tmp->snext; + } + printf("}\n"); +} + +/** + * shash_table_print_rev - prints a sorted hash table in reverse + * @ht: hash table to print + * + * Return: void + */ +void shash_table_print_rev(const shash_table_t *ht) +{ + shash_node_t *tmp; + char flag = 0; /* 0 before printing any data, 1 after*/ + + if (ht == NULL || ht->array == NULL) + return; + printf("{"); + tmp = ht->stail; + while (tmp != NULL) + { + if (flag == 1) + printf(", "); + printf("'%s': '%s'", tmp->key, tmp->value); + flag = 1; + tmp = tmp->sprev; + } + printf("}\n"); +} + +/** + * shash_table_delete - deletes a sorted hash table + * @ht: hash table to delete + * + * Return: void + */ +void shash_table_delete(shash_table_t *ht) +{ + unsigned long int i; + shash_node_t *next; + + if (ht == NULL || ht->array == NULL || ht->size == 0) + return; + for (i = 0; i < ht->size; i++) + { + while (ht->array[i] != NULL) + { + next = ht->array[i]->next; + free(ht->array[i]->key); + free(ht->array[i]->value); + free(ht->array[i]); + ht->array[i] = next; + } + } + free(ht->array); + ht->array = NULL; + ht->shead = ht->stail = NULL; + ht->size = 0; + free(ht); +} diff --git a/0x1A-hash_tables/2-key_index.c b/0x1A-hash_tables/2-key_index.c new file mode 100644 index 0000000..d275605 --- /dev/null +++ b/0x1A-hash_tables/2-key_index.c @@ -0,0 +1,13 @@ +#include "hash_tables.h" + +/** + * key_index - gives the index of a key + * @key: key to get index for + * @size: size of the hash table + * + * Return: index for the key + */ +unsigned long int key_index(const unsigned char *key, unsigned long int size) +{ + return (hash_djb2(key) % size); +} diff --git a/0x1A-hash_tables/3-hash_table_set.c b/0x1A-hash_tables/3-hash_table_set.c new file mode 100644 index 0000000..c9d5a4a --- /dev/null +++ b/0x1A-hash_tables/3-hash_table_set.c @@ -0,0 +1,73 @@ +#include "hash_tables.h" + +/** + * make_hash_node - creates a new hash node + * @key: key for the node + * @value: for the node + * + * Return: the new node, or NULL on failure + */ +hash_node_t *make_hash_node(const char *key, const char *value) +{ + hash_node_t *node; + + node = malloc(sizeof(hash_node_t)); + if (node == NULL) + return (NULL); + node->key = strdup(key); + if (node->key == NULL) + { + free(node); + return (NULL); + } + node->value = strdup(value); + if (node->value == NULL) + { + free(node->key); + free(node); + return (NULL); + } + node->next = NULL; + return (node); +} + + +/** + * hash_table_set - sets a key to a value in the hash table + * @ht: hash table to add elemt to + * @key: key for the data + * @value: data to store + * + * Return: 1 if successful, 0 otherwise + */ +int hash_table_set(hash_table_t *ht, const char *key, const char *value) +{ + unsigned long int index; + hash_node_t *hash_node, *tmp; + char *new_value; + + if (ht == NULL || ht->array == NULL || ht->size == 0 || + key == NULL || strlen(key) == 0 || value == NULL) + return (0); + index = key_index((const unsigned char *)key, ht->size); + tmp = ht->array[index]; + while (tmp != NULL) + { + if (strcmp(tmp->key, key) == 0) + { + new_value = strdup(value); + if (new_value == NULL) + return (0); + free(tmp->value); + tmp->value = new_value; + return (1); + } + tmp = tmp->next; + } + hash_node = make_hash_node(key, value); + if (hash_node == NULL) + return (0); + hash_node->next = ht->array[index]; + ht->array[index] = hash_node; + return (1); +} diff --git a/0x1A-hash_tables/4-hash_table_get.c b/0x1A-hash_tables/4-hash_table_get.c new file mode 100644 index 0000000..885f6cc --- /dev/null +++ b/0x1A-hash_tables/4-hash_table_get.c @@ -0,0 +1,27 @@ +#include "hash_tables.h" + +/** + * hash_table_get - retrieves a value associated with a key + * @ht: table to retrieve value from + * @key: key to find value + * + * Return: value associated with key, or NULL if key cannot be found + */ +char *hash_table_get(const hash_table_t *ht, const char *key) +{ + unsigned long int index; + hash_node_t *tmp; + + if (ht == NULL || ht->array == NULL || ht->size == 0 || + key == NULL || strlen(key) == 0) + return (NULL); + index = key_index((const unsigned char *)key, ht->size); + tmp = ht->array[index]; + while (tmp != NULL) + { + if (strcmp(tmp->key, key) == 0) + return (tmp->value); + tmp = tmp->next; + } + return (NULL); +} diff --git a/0x1A-hash_tables/5-hash_table_print.c b/0x1A-hash_tables/5-hash_table_print.c new file mode 100644 index 0000000..92937bc --- /dev/null +++ b/0x1A-hash_tables/5-hash_table_print.c @@ -0,0 +1,31 @@ +#include "hash_tables.h" + +/** + * hash_table_print - prints a hash table + * @ht: hash table to print + * + * Return: void + */ +void hash_table_print(const hash_table_t *ht) +{ + unsigned long int i; + hash_node_t *tmp; + char flag = 0; /* 0 while no data has been printed yet */ + + if (ht == NULL || ht->array == NULL) + return; + printf("{"); + for (i = 0; i < ht->size; i++) + { + tmp = ht->array[i]; + while (tmp != NULL) + { + if (flag == 1) + printf(", "); + printf("'%s': '%s'", tmp->key, tmp->value); + flag = 1; + tmp = tmp->next; + } + } + printf("}\n"); +} diff --git a/0x1A-hash_tables/6-hash_table_delete.c b/0x1A-hash_tables/6-hash_table_delete.c new file mode 100644 index 0000000..aa17676 --- /dev/null +++ b/0x1A-hash_tables/6-hash_table_delete.c @@ -0,0 +1,31 @@ +#include "hash_tables.h" + +/** + * hash_table_delete - deletes a hash table + * @ht: hash table to delete + * + * Return: void + */ +void hash_table_delete(hash_table_t *ht) +{ + unsigned long int i; + hash_node_t *next; + + if (ht == NULL || ht->array == NULL || ht->size == 0) + return; + for (i = 0; i < ht->size; i++) + { + while (ht->array[i] != NULL) + { + next = ht->array[i]->next; + free(ht->array[i]->key); + free(ht->array[i]->value); + free(ht->array[i]); + ht->array[i] = next; + } + } + free(ht->array); + ht->array = NULL; + ht->size = 0; + free(ht); +} diff --git a/0x1A-hash_tables/README.md b/0x1A-hash_tables/README.md new file mode 100644 index 0000000..39231c1 --- /dev/null +++ b/0x1A-hash_tables/README.md @@ -0,0 +1 @@ +0x1A. C - Hash tables diff --git a/0x1A-hash_tables/hash_tables.h b/0x1A-hash_tables/hash_tables.h new file mode 100644 index 0000000..3aebd72 --- /dev/null +++ b/0x1A-hash_tables/hash_tables.h @@ -0,0 +1,89 @@ +#ifndef _HASH_TABLES_H_ +#define _HASH_TABLES_H_ + +#include +#include +#include + +/** + * struct hash_node_s - Node of a hash table + * + * @key: The key, string + * The key is unique in the HashTable + * @value: The value corresponding to a key + * @next: A pointer to the next node of the List + */ +typedef struct hash_node_s +{ + char *key; + char *value; + struct hash_node_s *next; +} hash_node_t; + +/** + * struct hash_table_s - Hash table data structure + * + * @size: The size of the array + * @array: An array of size @size + * Each cell of this array is a pointer to the first node of a linked list, + * because we want our HashTable to use a Chaining collision handling + */ +typedef struct hash_table_s +{ + unsigned long int size; + hash_node_t **array; +} hash_table_t; + +hash_table_t *hash_table_create(unsigned long int size); +unsigned long int hash_djb2(const unsigned char *str); +unsigned long int key_index(const unsigned char *key, unsigned long int size); +int hash_table_set(hash_table_t *ht, const char *key, const char *value); +char *hash_table_get(const hash_table_t *ht, const char *key); +void hash_table_print(const hash_table_t *ht); +void hash_table_delete(hash_table_t *ht); + +/** + * struct shash_node_s - Node of a sorted hash table + * + * @key: The key, string + * The key is unique in the HashTable + * @value: The value corresponding to a key + * @next: A pointer to the next node of the List + * @sprev: A pointer to the previous element of the sorted linked list + * @snext: A pointer to the next element of the sorted linked list + */ +typedef struct shash_node_s +{ + char *key; + char *value; + struct shash_node_s *next; + struct shash_node_s *sprev; + struct shash_node_s *snext; +} shash_node_t; + +/** + * struct shash_table_s - Sorted hash table data structure + * + * @size: The size of the array + * @array: An array of size @size + * Each cell of this array is a pointer to the first node of a linked list, + * because we want our HashTable to use a Chaining collision handling + * @shead: A pointer to the first element of the sorted linked list + * @stail: A pointer to the last element of the sorted linked list + */ +typedef struct shash_table_s +{ + unsigned long int size; + shash_node_t **array; + shash_node_t *shead; + shash_node_t *stail; +} shash_table_t; + +shash_table_t *shash_table_create(unsigned long int size); +int shash_table_set(shash_table_t *ht, const char *key, const char *value); +char *shash_table_get(const shash_table_t *ht, const char *key); +void shash_table_print(const shash_table_t *ht); +void shash_table_print_rev(const shash_table_t *ht); +void shash_table_delete(shash_table_t *ht); + +#endif /* _HASH_TABLES_H_ */