散列表

散列表

  散列表的实现叫做散列。散列是一种以常数时间执行插入、删除和查找的技术。理想的散列数据结构只不过是一个包含有关键字的具有固定大小的数组。每个关键字带有一个或多个相关的值,并且每个关键字通过一个映射函数映射到散列表的适当的单元中。散列函数可以选择Horner函数:KeySize1i=0Key(KeySizei1)32i。解决当插入一个元素时,该处已经存在另一个元素时的冲突问题的简单方法有:分离链接法和开放定址法。

  分离链接法是将散列到同一个值的所有元素保留到一个表中。

/*
 *分离链接法散列表
 */

#ifndef SP_HASH_TABLE_H
#define SP_HASH_TABLE_H

#include <stdlib.h>
#include <string.h>
#include <assert.h>

/*散列表值类型*/
typedef int ElementType;

typedef struct SPHashValue
{
    ElementType hash_value;
    char hash_key[8];
    struct SPHashValue *next;
} SPHashValue;

/*散列表数据结构*/
typedef struct SPHashTable 
{
    int table_size; //散列表大小
    SPHashValue **hash_value_ptr; //指向散列值链表的指针
} SPHashTable;



/*给散列表链表节点分配内存*/
SPHashValue* create_note(const char *key, ElementType hash_value)
{
    SPHashValue *node = (SPHashValue*)malloc(sizeof(SPHashValue));
    if (node == NULL)
      return NULL;
    node->hash_value = hash_value;
    strncpy(node->hash_key, key, 7);
    node->hash_key[7] = '\0';
    node->next = NULL;
    return node;
}

/*释放散列表散列值链表内存*/
void free_hash_value(SPHashValue *hash_value_list)
{
    SPHashValue *tmp = NULL;
    while (hash_value_list)
    {
        tmp = hash_value_list->next;
        free(hash_value_list);
        hash_value_list = tmp;
    }
}

/*创建散列表,并初始化*/
SPHashTable* create_hash_table(int size)
{
    SPHashTable* hash_table = (SPHashTable*)malloc(sizeof(SPHashTable));
    hash_table->table_size = size;
    hash_table->hash_value_ptr = (SPHashValue**)malloc(sizeof(SPHashValue) * size);

    for (int i = 0; i < size; ++i)
    {
        hash_table->hash_value_ptr[i] = NULL; 
    }
    return hash_table;
}

/*删除散列表*/
void delete_hash_table(SPHashTable *hash_table)
{
    SPHashValue *tmp = NULL;
    /*释放散列值链表*/
    for (int i = 0; i < hash_table->table_size; ++i)
    {
        free_hash_value(hash_table->hash_value_ptr[i]);
    }
   /*释放指向散列值链表的指针的内存*/
    free(hash_table->hash_value_ptr);

    free(hash_table);

}

/*散列函数*/
int horner_hash(const char *key, int table_size)
{
    int hash_value = 0;

    while (*key != '\0')
    {
        hash_value = (hash_value * 27) + *key++;
    }

    return hash_value % table_size;
}

/*添加元素到散列表*/
void add(const SPHashTable *hash_table, const char *key, const ElementType value)
{
   int hash_value = horner_hash(key, hash_table->table_size);
   SPHashValue *value_note = create_note(key, value);
   assert(value_note != NULL);
   SPHashValue *tmp = hash_table->hash_value_ptr[hash_value];
   if (tmp == NULL)
   {
     hash_table->hash_value_ptr[hash_value] = value_note;
     return;
   }
   while (tmp->next != NULL)
   {
        tmp = tmp->next;
   }
   tmp->next = value_note;

}

/*在散列表中查找键,返回其在散列表中的位置*/
SPHashValue* find(const SPHashTable *hash_table, const char *key)
{
    int hash_value =  horner_hash(key, hash_table->table_size);
    SPHashValue *tmp = hash_table->hash_value_ptr[hash_value];
    while (tmp)
    {
        if (strcmp(tmp->hash_key, key) == 0)
          return tmp;
        tmp = tmp->next;
    }

    return NULL;
}

/*删除散列表中的指定的键值,删除成功返回1,后则返回0*/
int delete_keyvalue(const SPHashTable *hash_table, const char *key)
{
    int hash_value = horner_hash(key, hash_table->table_size);
    SPHashValue *tmp_prev = hash_table->hash_value_ptr[hash_value];
    if (tmp_prev == NULL)
      return 0;

    if (strcmp(tmp_prev->hash_key, key) == 0) //待删除键值链表第一个元素
    {
        free(tmp_prev);
        hash_table->hash_value_ptr[hash_value] = NULL;
        return 1;
    }
    SPHashValue *tmp = tmp_prev->next;
    while (tmp)
    {
        if (strcmp(tmp->hash_key, key) == 0)
        {
            tmp_prev->next = tmp->next;
            free(tmp);
            return 1;
        }
        tmp_prev = tmp;
        tmp = tmp->next;
    }

    return 0;
}

#endif /*end sp_hash_table.h*/

  开放定地址散列法中,如果有冲突发生,那么就尝试选择另外的单元,直到找出空的单元为止。常常选择一个冲突解决函数F(i)来解决表的散列,散列函数hi(X)=(Hash(X)+F(i))modTableSize

posted @ 2015-10-04 10:04  corfox  阅读(198)  评论(0编辑  收藏  举报