c哈希表hashtable操作

#ifndef HASH_TABLE_H
#define HASH_TABLE_H

#include "linkedlist.h"

typedef struct {
	int capacity;
	LinkedList **elements;
    int seed;
} HashTable;

HashTable *hash_table_construct(int size);
HashTable *hash_table_clone(HashTable *table);
void has_table_destroy_clone(HashTable *table);
void hash_table_destroy(HashTable *table);
void hash_table_add_element(HashTable *table, const void *data, int hash_code);
const void *hash_table_get_element(HashTable *table, int hash_code);
void hash_table_remove_element(HashTable *table, int hash_code);
int hash_table_get_index(HashTable *table, int hash_code);
int hash_table_get_hash_code_from_string(const char *string);
#endif

-------------------------------------------

#include "hashtable.h"
#include "linkedlist.h"
#include "logger.h"
#include <stdlib.h>
#include <stdio.h>

#ifdef DMALLOC
#include "dmalloc.h"
#endif

typedef struct {
    int hash_code;
    const void *data;
} HashTableElement;

static HashTableElement *hash_table_element_construct(int hash_code, const void *data); 
static void hash_table_element_destroy(HashTableElement *element);

/*
 * FIXME: Needs to handle growing past initial capacity when table gets full.
 *        Note that it will be a slow operation because all table elements
 *        will have to be rehashed.
 *
 * FIXME: Currently uses chaining which isn't great.  Probably would be better
 *        to do double hashing or quadratic probing or something. If not, 
 *        it would be at least a good idea to maintain which elements get 
 *        accessed the most in any given chain and move them to the front.
 */
HashTable *hash_table_construct(int size) {

	HashTable *table = NULL;
	
    /*
     * Allocate space for the object and set all fields to zero.
     */
 	table = calloc(1, sizeof(HashTable));
	
	if (table == NULL) {
        return NULL;
    }

    /*
     * Allocate space for the table elements 
     */
    table->elements = calloc(size, sizeof(LinkedList *));

    if (table->elements == NULL) {
        return NULL;
    }

    /*
     * Initially set the capacity to the passed size 
     */
    table->capacity = size;

    /*
     * FIXME: Do something with this.  Make it a random number or something.
     */
    table->seed = 1;

    /*
     * Return the HashTable object
     */
	return table;

}

void hash_table_destroy(HashTable *table) {
	
    int i = 0;
	if (table == NULL) {
        return;
    }
		
    /*
     * Free all the chains
     */
    if (table->elements != NULL) {

        for (i = 0; i < table->capacity; i++) { 
            if (table->elements[i] != NULL) {
                linked_list_destroy(table->elements[i]);
                table->elements[i] = NULL;
            }
        }

        free(table->elements);
        table->elements = NULL;
    }

	free(table);
}

HashTable *hash_table_clone(HashTable *table) {

    /*
     * Fixme, write this function!
     */ 
    return table;
}

void has_table_destroy_clone(HashTable *table) {
    
    /*
     * Fixme, write this function!
     */ 
}

void hash_table_add_element(HashTable *table, const void *data, int hash_code) {

    LinkedListNode *node = NULL;
    HashTableElement *element = NULL;
    int index = -1;

    if (table == NULL) {
        return;
    }

    /*
     * Find out which chain the element should be appended to.
     */
    index = hash_table_get_index(table, hash_code);

    if (index == -1) {
        return;
    }

    /*
     * If there isn't a LinkedList object at the index
     * already then put one there
     */
    if (table->elements[index] == NULL) {
        table->elements[index] = linked_list_construct();

        if (table->elements[index] == NULL) {
            return;
        }
    }

    /*
     * Create a HashTableElement object to hold the given data and hash code
     */
    element = hash_table_element_construct(hash_code, data);

    /*
     * If the element could not be created then bail
     */
    if (element == NULL) {
        return;
    }

    /*
     * Create a linked list node with the given element
     */
    node = linked_list_node_construct(element);

    if (node == NULL) {
        return;
    }

    /*
     * Otherwise, add the node to the linked list
     */
    linked_list_append_node(table->elements[index], node);

}

const void *hash_table_get_element(HashTable *table, int hash_code) {

    LinkedListNode *node = NULL;
    HashTableElement *element = NULL;
    const void *data = NULL;
    int index = -1;

    if (table == NULL) {
        return NULL;
    }

    /*
     * Which chain does the desired element reside on? 
     */
    index = hash_table_get_index(table, hash_code);

    if (index == -1) {
        return NULL;
    }

    if (table->elements[index] == NULL) {
        return NULL;
    }

    /*
     * Start at the beginning of the chain.
     */
    linked_list_seek_start(table->elements[index]);

    /*
     * Traverse each node, and compare hash codes for a valid match
     */
    while((node = linked_list_get_next_node(table->elements[index])) != NULL) {

        element = (HashTableElement *) linked_list_node_get_data(node);

        if (hash_code == element->hash_code) {

            data = element->data;
            break;
        }
    }

    if (data == NULL) {

    }

    return data;
}

int hash_table_get_index(HashTable *table, int hash_code) {

    if (table == NULL) {
        return -1;
    }
    
    if (hash_code < 0) {
        return -1;
    }

    if (table->capacity == 0) {
        return -1;
    }

    /*
     * Is their a better hashing function?
     */
    return (table->seed * hash_code) % table->capacity;
}

int hash_table_get_hash_code_from_string(const char *string) {
    const char *p = NULL;
    int hash_code = -1, i = 0;

    if (string == NULL) {
        return -1;
    }

    /*
     * Generate a reversed (least significant character is most significant
     * number) radix 128 evaluated polynomial of the input key
     */
    for (p = string; p[0] != 0; p++, i++) {

        int j = 0, coeff = 1;

        for (j = 0; j < i; j++) {
            coeff += 128;
        }

        hash_code += (p[0] * coeff);
        
    }

    return hash_code;
}

static HashTableElement *hash_table_element_construct(int hash_code, 
                                                const void *data) {
	
    HashTableElement *element = NULL;

    /*
     * Allocate space for the object and set all fields to zero.
     */
    element = calloc(1, sizeof(HashTableElement));

	if (element == NULL) {
        return NULL;
    }
		
    element->hash_code = hash_code;
    element->data = data;
	
    return element;
}

static void hash_table_element_destroy(HashTableElement *element) {
	
	if (element == NULL) {
        return;
    }

	free(element);
}
原文地址:https://www.cnblogs.com/fx2008/p/2193019.html