Skip to content

Instantly share code, notes, and snippets.

@Wildhammer
Forked from tonious/hash.c
Last active February 13, 2016 06:53
Show Gist options
  • Save Wildhammer/df61e591e5065be75bf5 to your computer and use it in GitHub Desktop.
Save Wildhammer/df61e591e5065be75bf5 to your computer and use it in GitHub Desktop.
A quick hashtable implementation in c.
#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;
}
@Wildhammer
Copy link
Author

I implemented ht_resize function which basically resizes the hashtable up to SCALE_FACTOR whenever the load ratio gets bigger than MAX_LOAD_FACTOR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment