/**
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation;
author:liexusong<[email protected]>
HashTable
hash.h
*/
#ifndef _HASH_H
#define _HASH_H
struct _hash_node;
struct _hash_t;
typedef struct _hash_t HashTable;
typedef struct _hash_node HashNode;
typedef void (*dumpfunc)(void *);
struct _hash_node {
struct _hash_node *next;
char *key;
void *value;
};
struct _hash_t {
unsigned int size;
unsigned int used;
HashNode **ht;
};
HashTable *hash_create(unsigned int size);
int hash_free(HashTable *ht);
int hash_insert(HashTable *ht, char *key, void *value);
void *hash_find(HashTable *ht, char *key);
int hash_delete(HashTable *ht, char *key);
void hash_dump(HashTable *ht, dumpfunc print);
#endif
===========================================================
/**
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation;
author:liexusong<[email protected]>
HashTable
hash.c
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "hash.h"
static void hash_resize(HashTable *);
static unsigned int table_size[] = {
7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191,
16381, 32749, 65521, 131071,
262143, 524287, 1048575, 2097151, 4194303, 8388607,
16777211, 33554431, 67108863, 134217727, 268435455,
536870911, 1073741823, 2147483647, 0};
/* hash function: return unsignde int */
static unsigned int hash(HashTable *ht, const char *key)
{
unsigned int seed = 131;
unsigned int hash = 0;
while (*key) {
hash = hash * seed + (*key++);
}
return (hash & 0x7FFFFFFF) % table_size[ht->size];
}
/* create hash table: return HashTable */
HashTable *hash_create(unsigned int size)
{
HashTable *ht;
int i;
ht = (HashTable *)malloc(sizeof(HashTable));
if (ht == NULL) {
fprintf(stderr, "Out of memory/n");
return NULL;
}
ht->size = 0;
ht->used = 0;
while (table_size[ht->size] < size) {
ht->size++;
if (table_size[ht->size] == 0) {
ht->size--;
break;
}
}
ht->ht = (HashNode **)malloc(sizeof(HashNode *) * table_size[ht->size]);
if (ht->ht == NULL) {
free(ht);
fprintf(stderr, "Out of memory/n");
return NULL;
}
for (i = 0; i < size; i++)
ht->ht[i] = NULL;
return ht;
}
int hash_free(HashTable *ht)
{
int size;
HashNode *node, *next;
if (!ht) return -1;
size = ht->size - 1;
for (; size >= 0; size--)
{
node = ht->ht[size];
//free hash node
while (node) {
next = node->next;
free((void *)node->key);
free(node->value);
free(node);
node = next;
}
}
free(ht->ht);
free(ht);
return 0;
}
int hash_insert(HashTable *ht, char *key, void *value)
{
unsigned int h;
size_t len;
HashNode *node;
if (ht->used > table_size[ht->size]) hash_resize(ht);
node = (HashNode *)malloc(sizeof(HashNode));
if (!node) {
fprintf(stderr, "Out of memory/n");
return -1;
}
len = strlen(key) + 1;
node->key = (char *)malloc(len);
if (!node->key) {
free(node);
return -1;
}
strcpy(node->key, key);
node->value = value;
h = hash(ht, node->key);
if (!ht->ht[h])
{
node->next = NULL;
ht->ht[h] = node;
} else {
node->next = ht->ht[h];
ht->ht[h] = node;
}
ht->used++;
return 0;
}
void *hash_find(HashTable *ht, char *key)
{
unsigned int h;
HashNode *node;
h = hash(ht, key);
node = ht->ht[h];
while (node && (strcmp(key, node->key) != 0))
{
node = node->next;
}
if (node == NULL) {
return (void *)NULL;
} else {
return node->value;
}
}
int hash_delete(HashTable *ht, char *key) {
HashNode *node, *prev;
unsigned int h;
h = hash(ht, key);
node = prev = ht->ht[h];
while (node && (strcmp(key, node->key) != 0)) {
prev = node;
node = node->next;
}
if (node == NULL) {
return -1;
} else {
if (node == ht->ht[h]) {
ht->ht[h] = node->next;
} else {
prev->next = node->next;
}
free(node->key);
free(node->value);
free(node);
ht->used--;
}
return 0;
}
static void hash_resize(HashTable *h_old)
{
HashTable ht;
int i;
if (table_size[h_old->size + 1] == 0) return;
ht.used = h_old->used;
ht.size = h_old->size + 1;
ht.ht = (HashNode **)malloc(sizeof(HashNode *) * table_size[ht.size]);
if (!ht.ht) {
fprintf(stderr, "failed to malloc hashtable./n");
return;
}
/*
traverse the old hash table entries and re-link them into their
new places in the new table.
*/
for (i = 0; i < table_size[h_old->size]; i++) {
HashNode *e = h_old->ht[i];
HashNode *next_e;
while (e) {
unsigned int hashval = hash(&ht, e->key);//hash key
next_e = e->next;//save next node
e->next = ht.ht[hashval]; //--+
// |---- swap
ht.ht[hashval] = e; //--+
e = next_e;
}
}
/* overwrite the old with the new */
free(h_old->ht);
h_old->ht = ht.ht;
h_old->size = ht.size;
//printf("resize hashtable/n");
}
void hash_dump(HashTable *ht, dumpfunc print)
{
unsigned int size = table_size[ht->size];
int i;
for (i = 0; i < size; i++)
{
HashNode *e = ht->ht[i];
while (e) {
print((void *)e);
e = e->next;
}
}
}