all repos — hashtable @ 145aaa3e3e20dd56197b4713e1981b88c5dd1cdf

A very simple hashtable implementation in C

add files
prithugoswami prithugoswami524@gmail.com
Thu, 07 Mar 2019 19:06:03 +0530
commit

145aaa3e3e20dd56197b4713e1981b88c5dd1cdf

parent

075f16a7a7fbf621723aef9b1279c25e0262b91b

4 files changed, 360 insertions(+), 0 deletions(-)

jump to
A hashtable.c

@@ -0,0 +1,211 @@

+#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "hashtable.h" + + +/* --------------------- */ +/* Linked List Functions */ +/* --------------------- */ + +static List * ListInit(){ + List *list = (List *)malloc(sizeof(List)); + return list; +} + +static bool ListIsEmpty(const List *plist){ + return plist->first == NULL; +} + +static bool ListAppend(void * data, List *plist){ + Node *newNode = (Node *)malloc(sizeof(Node)); + if (newNode == NULL){ + fprintf(stderr, "Error: No Memory Available"); + return false; + } + if(ListIsEmpty(plist)){ + newNode->data = data; + newNode->next = NULL; + + plist->first=newNode; + plist->length++; + return true; + } + + Node *temp; + temp = plist->first; + while(temp->next != NULL) + temp = temp->next; + + newNode->data = data; + newNode->next = NULL; + + temp->next=newNode; + plist->length++; + return true; +} + +static bool ListInsertFront(void * data, List *plist){ + Node *newNode = (Node *)malloc(sizeof(Node)); + if(newNode == NULL){ + fprintf(stderr, "Error: No Memory Available"); + return false; + } + else{ + newNode->data = data; + newNode->next = plist->first; + plist->first = newNode; + plist->length++; + return true; + } +} + +static bool ListInsert(void * data, int pos, List *plist){ + if(pos >= plist->length || pos < 0){ + fprintf(stderr, LL_Err_OUTOFBOUNDS); + return false; + } + + if(pos==0) + return ListInsertFront(data, plist); + + int c=0; + Node *temp = plist->first; + /* `temp` will point to the node that is just before the position `pos` + * where the new node has to be added */ + while(c < pos-1){ + temp = temp->next; + c++; + } + + Node *newNode = (Node *)malloc(sizeof(Node)); + if(newNode == NULL){ + fprintf(stderr, "Error: No Memory Available"); + return false; + } + else{ + newNode->data = data; + newNode->next = temp->next; + temp->next=newNode; + plist->length++; + return true; + } +} + +static void * ListGetItem(int pos, List *plist){ + if(pos >= plist->length || pos < 0){ + fprintf(stderr, LL_Err_OUTOFBOUNDS); + exit(1); + } + + int c=0; + Node *temp = plist->first; + while(c < pos){ + temp = temp->next; + c++; + } + + return temp->data; +} + +static void * ListPopItem(int pos, List *plist){ + if(pos >= plist->length || pos < 0){ + fprintf(stderr, LL_Err_OUTOFBOUNDS); + exit(1); + } + + int c=0; + Node *prevNode = plist->first; + while(c < pos-1){ + prevNode = prevNode->next; + c++; + } + Node *currNode = prevNode->next; + Node *nextNode = currNode->next; + prevNode->next = nextNode; + + void *data = currNode->data; + free(currNode); + plist->length--; + return data; +} + + + +/* ------------------- */ +/* HashTable Functions */ +/* ------------------- */ + +static unsigned long +hash_function(char *str, size_t capacity){ + unsigned long hash = 0; + int c; + char *strcpy = str; + while(c = *strcpy++) + hash +=c; + return hash%capacity; +} + +HashTable * +createHashTable(size_t capacity){ + HashTable *hashtable = (HashTable *)malloc(sizeof(HashTable)); + List **lists = (List **)malloc(sizeof(List*)*capacity); + for(int i=0; i<capacity; i++) + lists[i] = ListInit(); + hashtable->lists = lists; + hashtable->capacity = capacity; + return hashtable; +} + +bool +HashTableInsert(char *key, void *data, HashTable *hashtable){ + unsigned long hash = hash_function(key, hashtable->capacity); + List *list = hashtable->lists[hash]; + + if(ListIsEmpty(list)){ + elem_t *elem = (elem_t *)malloc(sizeof(elem_t)); + elem->key = key; + elem->value = data; + ListAppend(elem, list); + hashtable->length++; + return true; + } + else{ + elem_t *elem_tmp; + for(int i=0; i<list->length; i++){ + elem_tmp = (elem_t *)ListGetItem(i, list); + if (strcmp(key ,elem_tmp->key)==0) + return false;//key already exists + } + elem_t *elem = (elem_t *)malloc(sizeof(elem_t)); + elem->key = key; + elem->value = data; + ListAppend(elem, list); + hashtable->length++; + return true; + } +} + +void * +HashTableGet(char *key, HashTable *hashtable){ + unsigned long hash = hash_function(key, hashtable->capacity); + List *list = hashtable->lists[hash]; + if (ListIsEmpty(list)) + return NULL; + + else if(list->length > 1){ + elem_t *elem_tmp; + for(int i=0; i<list->length; i++){ + elem_tmp = ListGetItem(i, list); + if(strcmp(key, elem_tmp->key)==0){ + return elem_tmp->value; + } + } + return NULL; + } + + else{// if only one element in the list + elem_t *elem = ListGetItem(0, list); + return elem->value; + } +}
A hashtable.h

@@ -0,0 +1,82 @@

+#ifndef _HASHTABLE_H +#define _HASHTABLE_H +#include <stdbool.h> +#include <stddef.h> +#define LL_Err_OUTOFBOUNDS "ListError: Index Out of Bounds\n" + + +/* Simple HashTable implementation + * + * Inserting Into the hastable can be done with: + * HashTableInsert(<key>, <value>, <hashtable pointer>); + * + * Accessing the hastable can be done with: + * HashTableGet(<key>, <hashtable pointer>); + * + * EXAMPLE USAGE: + * + * HashTable *ht = createHashTable(100); + * int rc = HashTableInsert("name", "Prithu", ht); + * if(rc) + * fprintf(stderr, "Cannot Insert the data into the Hashtable"); + * + * char *my_name = (char *)HashTableGet("name", ht); + * + * FILE *fp = fopen("my_file.txt", "r"); + * HashTableInsert("file", fp, ht); + * + * FILE *my_file = (FILE *)HashTableGet("file", ht); + * + * +*/ + +/* -------------------- */ +/* LinkedList Protoypes */ +/* -------------------- */ + +typedef struct node{ + void *data; + struct node *next; +} Node; + +typedef struct list{ + Node *first; + size_t length; +} List; + +static List * ListInit(); +static bool ListIsEmpty(const List *plist); +static bool ListAppend(void *data, List *plist); +static bool ListInsertFront(void *data, List *plist); +static bool ListInsert(void *data, int position, List *plist); +static void * ListPopItem(int pos, List *plist); +static void * ListGetItem(int pos, List *plist); + + +/* -------------------------------------------------- */ +/* Hashtable Type Definitions and Function Prototypes */ +/* -------------------------------------------------- */ + +typedef struct hash_table{ + size_t capacity; + size_t length; + List **lists; +} HashTable; + +typedef struct elem_s{ + char *key; + void *value; +} elem_t; + +/* Create a hashtable and returns a pointer to it */ +/* capcity decides the number of array indeces for data */ +HashTable * createHashTable(size_t capacity); + +/* Inserts the value into the HashTable `hashtable` along with the key*/ +bool HashTableInsert(char *key, void *value, HashTable *hashtable); + +/* Returns a pointer to the data mapped to the key in the + * Hashtable pointed by `hashtable` */ +void * HashTableGet(char *key, HashTable * hashtable); + +#endif
A hashtable.test.c

@@ -0,0 +1,58 @@

+#include "hashtable.h" +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <stdlib.h> + +typedef struct student{ + char *name; + int age; +} Student; + + +int main(){ + HashTable *ht = createHashTable(100); + + Student prithu = {"Prithu", 19}; + Student nilesh = {"Nilesh", 21}; + + HashTableInsert("name", "Prithu", ht); + HashTableInsert("age", "19", ht); + HashTableInsert("age1", "20", ht); + HashTableInsert("intrests", "programming;graphic_designing", ht); + HashTableInsert("country", "India", ht); + HashTableInsert("country2", "Russia", ht); + HashTableInsert("country3", "USA", ht); + HashTableInsert("student_prithu", &prithu, ht); + HashTableInsert("student_nilesh", &nilesh, ht); + + + // checking values from HashTable + assert(!strcmp(HashTableGet("name", ht), "Prithu")); + assert(!strcmp(HashTableGet("age", ht), "19")); + assert(!strcmp(HashTableGet("age1", ht), "20")); + assert(!strcmp(HashTableGet("intrests", ht), "programming;graphic_designing")); + assert(!strcmp(HashTableGet("country", ht), "India")); + assert(!strcmp(HashTableGet("country2", ht), "Russia")); + assert(!strcmp(HashTableGet("country3", ht), "USA")); + + // for Student structure + assert( ((Student *)HashTableGet("student_prithu", ht))->age == 19); + assert( ((Student *)HashTableGet("student_nilesh", ht))->age == 21); + assert(!strcmp(((Student *)HashTableGet("student_nilesh", ht))->name, "Nilesh")); + + // checking length and capacity + assert(ht->length==9); + assert(ht->capacity==100); + + // existing key should not be added + bool added = HashTableInsert("country", "India", ht); + assert(!added); + + // non-existent key must return NULL + char *non = HashTableGet("non-existent-key", ht); + assert(non == NULL); + + fprintf(stderr, "\033[32;1mSUCCESS!\033[0m\n"); + free(ht); +}
A makefile

@@ -0,0 +1,9 @@

+CC=gcc +CFLAG=-I. + +# hashtable_test: hashtable.c hashtable.test.c +# $(CC) hashtable.c hashtable.test.c -o hashtable_test && ./hashtable_test\ +# && rm ./hashtable_test + +hashtable_test: hashtable.c hashtable.test.c + $(CC) hashtable.c hashtable.test.c -o hashtable_test && ./hashtable_test