-
-
Save Wildhammer/df61e591e5065be75bf5 to your computer and use it in GitHub Desktop.
A quick hashtable implementation in c.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _XOPEN_SOURCE 500 /* Enable certain library functions (strdup) on linux. See feature_test_macros(7) */ | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <limits.h> | |
#include <string.h> | |
#define INITIAL_HASH_SIZE 4 | |
#define MAX_LOAD_FACTOR 2 | |
#define SCALE_FACTOR 2 | |
struct entry_s { | |
char *key; | |
char *value; | |
struct entry_s *next; | |
}; | |
typedef struct entry_s entry_t; | |
struct hashtable_s { | |
int size; | |
int num_items; | |
struct entry_s **table; | |
}; | |
typedef struct hashtable_s hashtable_t; | |
/* Create a new hashtable. */ | |
hashtable_t *ht_create( int size ) { | |
hashtable_t *hashtable = NULL; | |
int i; | |
if( size < 1 ) return NULL; | |
/* Allocate the table itself. */ | |
if( ( hashtable = malloc( sizeof( hashtable_t ) ) ) == NULL ) { | |
return NULL; | |
} | |
/* Allocate pointers to the head nodes. */ | |
if( ( hashtable->table = malloc( sizeof( entry_t * ) * size ) ) == NULL ) { | |
return NULL; | |
} | |
for( i = 0; i < size; i++ ) { | |
hashtable->table[i] = NULL; | |
} | |
hashtable->size = size; | |
hashtable->num_items = 0; | |
return hashtable; | |
} | |
/* Hash a string for a particular hash table. */ | |
int ht_hash( hashtable_t *hashtable, char *key ) { | |
int sum = 0; | |
for (; *key; key++) | |
sum = (37*sum + *key) % hashtable->size; | |
return sum; | |
} | |
/* Prints the table and its containing keys*/ | |
void ht_print_table(hashtable_t *hashtable){ | |
int i; | |
entry_t* j; | |
printf("Table contents: ////////////\n"); | |
for(i=0;i<hashtable->size;i++) | |
{ | |
for(j=hashtable->table[i];j;j=j->next){ | |
printf("%s ", j->key); | |
} | |
printf("\n"); | |
} | |
printf("////////////////////////////\n"); | |
} | |
/* Insert a key-value pair into a hash table. */ | |
void ht_set( hashtable_t *hashtable, char *key, char *value ); | |
/* Resizing the hashtable for efficiency purposes*/ | |
void ht_resize(hashtable_t* hashtable){ | |
struct entry_s **ttable; | |
entry_t *j; | |
ttable = hashtable->table;//free ttable | |
int i; | |
/* Allocate pointers to the head nodes. */ | |
if( ( hashtable->table = malloc( sizeof( entry_t * ) * hashtable->size*SCALE_FACTOR ) ) == NULL ) { | |
return; | |
} | |
for( i = 0; i < hashtable->size*SCALE_FACTOR; i++ ) { | |
hashtable->table[i] = NULL; | |
} | |
int size_before = hashtable->size; | |
hashtable->size *= SCALE_FACTOR; | |
hashtable->num_items=0; | |
for( i = 0; i < size_before; i++ ) { | |
for( j = ttable[i]; j; j=j->next) | |
{ | |
//fprintf(stderr, "%s\n",j->key); | |
ht_set(hashtable,j->key,j->value); | |
//free(ttable[i]); | |
} | |
} | |
} | |
/* Create a key-value pair. */ | |
entry_t *ht_newpair( char *key, char *value ) { | |
entry_t *newpair; | |
if( ( newpair = malloc( sizeof( entry_t ) ) ) == NULL ) { | |
return NULL; | |
} | |
if( ( newpair->key = strdup( key ) ) == NULL ) { | |
return NULL; | |
} | |
if( ( newpair->value = strdup( value ) ) == NULL ) { | |
return NULL; | |
} | |
newpair->next = NULL; | |
return newpair; | |
} | |
/* Insert a key-value pair into a hash table. */ | |
void ht_set( hashtable_t *hashtable, char *key, char *value ) { | |
int bin = 0; | |
entry_t *newpair = NULL; | |
entry_t *next = NULL; | |
entry_t *last = NULL; | |
bin = ht_hash( hashtable, key ); | |
next = hashtable->table[ bin ]; | |
while( next != NULL && next->key != NULL && strcmp( key, next->key ) > 0 ) { | |
last = next; | |
next = next->next; | |
} | |
/* There's already a pair. Let's replace that string. */ | |
if( next != NULL && next->key != NULL && strcmp( key, next->key ) == 0 ) { | |
free( next->value ); | |
next->value = strdup( value ); | |
/* Nope, could't find it. Time to grow a pair. */ | |
} else { | |
newpair = ht_newpair( key, value ); | |
hashtable->num_items++; | |
/* We're at the start of the linked list in this bin. */ | |
if( next == hashtable->table[ bin ] ) { | |
newpair->next = next; | |
hashtable->table[ bin ] = newpair; | |
/* We're at the end of the linked list in this bin. */ | |
} else if ( next == NULL ) { | |
last->next = newpair; | |
/* We're in the middle of the list. */ | |
} else { | |
newpair->next = next; | |
last->next = newpair; | |
} | |
/* Whenever the load factor gets bigger than MAX_LOAD_FACTOR we resize the hash table up*/ | |
if (hashtable->num_items/hashtable->size>=MAX_LOAD_FACTOR) | |
{ | |
ht_resize(hashtable); | |
} | |
} | |
} | |
/* Retrieve a key-value pair from a hash table. */ | |
char *ht_get( hashtable_t *hashtable, char *key ) { | |
int bin = 0; | |
entry_t *pair; | |
bin = ht_hash( hashtable, key ); | |
/* Step through the bin, looking for our value. */ | |
pair = hashtable->table[ bin ]; | |
while( pair != NULL && pair->key != NULL && strcmp( key, pair->key ) > 0 ) { | |
pair = pair->next; | |
} | |
/* Did we actually find anything? */ | |
if( pair == NULL || pair->key == NULL || strcmp( key, pair->key ) != 0 ) { | |
return NULL; | |
} else { | |
return pair->value; | |
} | |
} | |
int main( int argc, char **argv ) { | |
/* Just uncomment ht_print_table to see the contents of hashtable*/ | |
hashtable_t *hashtable = ht_create( INITIAL_HASH_SIZE ); | |
ht_set( hashtable, "te", "asi" ); | |
ht_set( hashtable, "dire", "es" ); | |
ht_set( hashtable, "un", "maria" ); | |
ht_set( hashtable, "secreto", "blanca" ); | |
ht_set( hashtable, "y", "como" ); | |
ht_set( hashtable, "que", "el" ); | |
ht_set( hashtable, "queda", "dia" ); | |
// ht_print_table(hashtable); | |
ht_set( hashtable, "entre", "pero" ); | |
// ht_print_table(hashtable); | |
ht_set( hashtable, "tu", "es" ); | |
ht_set( hashtable, "y", "veneno" ); | |
ht_set( hashtable, "yo", "es" ); | |
ht_set( hashtable, "siento", "veneno" ); | |
ht_set( hashtable, "que", "es" ); | |
ht_set( hashtable, "te", "veneno" ); | |
ht_set( hashtable, "quiero", "es" ); | |
ht_set( hashtable, "puede", "veneno" ); | |
ht_set( hashtable, "mueve", "te" ); | |
ht_set( hashtable, "mamita", "que" ); | |
ht_set( hashtable, "vuelvo", "me" ); | |
ht_set( hashtable, "loco", "loco" ); | |
ht_set( hashtable, "dando", "me" ); | |
ht_set( hashtable, "vuelta", "dia" ); | |
ht_set( hashtable, "feliz", "que" ); | |
// ht_print_table(hashtable); | |
printf( "%s\n", ht_get( hashtable, "tu" ) ); | |
printf( "%s\n", ht_get( hashtable, "loco" ) ); | |
printf( "%s\n", ht_get( hashtable, "mamita" ) ); | |
printf( "%s\n", ht_get( hashtable, "dire" ) ); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I implemented ht_resize function which basically resizes the hashtable up to SCALE_FACTOR whenever the load ratio gets bigger than MAX_LOAD_FACTOR.