自己写的hashtable

/**
  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;
        }
    }
}

你可能感兴趣的:(struct,function,table,null,delete,insert)