htable实现,其中表的大小采用自适应方案

18 篇文章 0 订阅
10 篇文章 0 订阅

     前些天看到一个不错的hash table 的不错的实现方案,该哈希表的大小能够自适应的调整,当往哈希表插入了数据数等于哈希表的大小时,此时如果继续插入数据,冲突会增高,通过采用将哈希表扩大二倍,然后呢将原始已经插入原先表的数据重新插入新的哈希表中,但是存在一个问题:

    1.该哈希函数需要在表扩大二倍时,仍然能够在该表中呈现为均分分布。所以哈希函数的选择至关重要,这样冲突率很低,

    2.如何设计非常合理的结构,让哈希表操作方便,是我们考虑的重点

  接下来是我的代码:

//htable.h

#ifndef __HTABLE_H
#define __HTABLE_H
/************************************************
 * @aurhor Jacky Lau
 * @data   11/01/2014
 *
 ************************************************/


/*===================STRUCT==================================*/
typedef struct HTBALE_INFO {
    char *key;
    char *value;
    struct HTBALE_INFO *prev;
    struct HTBALE_INFO *next;
}HTBALE_INFO;

typedef struct HTBALE {
    int size;
    int used;
    struct HTBALE_INFO **data;
}HTABLE;


/*========================FUNCTION================================*/

HTABLE *htable_create(int size);
void htable_destroy(HTABLE *ht);
unsigned hash_function(const char *s, unsigned size);
void htable_growth(HTABLE *ht);
void htable_link(HTABLE *ht, HTBALE_INFO *element);
void htable_insert(HTABLE *ht, char *key, char *value);
void htable_delete(HTABLE *ht, const char *key);
char *htable_find(HTABLE *ht, const char *key);
HTBALE_INFO *htable_locate(HTABLE *ht, const char *key);
void htable_list_free(HTBALE_INFO **list);
HTBALE_INFO **htable_list(HTABLE *ht);

#endif


//htable.c

/************************************************
 * @aurhor Jacky Lau
 * @data   11/01/2014
 *
 ************************************************/
#include"htable.h"
#include<malloc.h>
#include<string.h>
#include<assert.h>



/********************************************************************************
 *
 *       ______
 *       |size|
 *       |used|
 *       |data|----------->-----
 *                        0 |----|       |----- \
 *                        1 |----|      \|/      \
 *                        2 |----|------->------  \    ---> |----
 *                        3 |----|        |----|   \  /     |----|
 *                        . |----|        |----|    \/      |----|
 *                        . |----|   prev |NULL|    /\----- |----|
 *                        . |----|   next |----|----        |NULL|
 *                    size-1|----|
 *
 *
 *
 **********************************************************************************/
HTABLE *htable_create(int size)
{
    HTABLE *ht = (HTABLE *)malloc(sizeof(HTABLE));
    ht->size =size;
    ht->used = 0;
    ht->data = (HTBALE_INFO **)malloc(size * sizeof(HTBALE_INFO *));
    memset(ht->data, 0, size * sizeof(HTBALE_INFO *));
    return ht;
}

void htable_destroy(HTABLE *ht)
{
    HTBALE_INFO *h;
    HTBALE_INFO *next;
    int i;
    for(i = 0; i < ht->size; i++)
    {
        for(h = ht->data[i]; h; h =next)
        {
            next = h->next;
            free(h->key);
            free(h->value);
            free(h);
        }
    }
    free(ht->data);
    free(ht);
}

unsigned hash_function(const char *s, unsigned size)
{
    unsigned long h = 0;
    unsigned long g;

    /*
     * From the "Dragon" book by Aho, Sethi and Ullman.
     */

    while (*s) {
    h = (h << 4) + *s++;
    if ((g = (h & 0xf0000000)) != 0) {
        h ^= (g >> 24);
        h ^= g;
    }
    }
    return (h % size);
}
//hash function needs to adjust automatically by the hash table size;
//so we need to rehash the key
void htable_growth(HTABLE *ht)
{
    int old_size = ht->size;
    ht->size = 2 * ht->size;
    ht->used = 0;
    HTBALE_INFO ** h = (HTBALE_INFO **)malloc(ht->size *sizeof(HTBALE_INFO *));
    memset(h, 0 , ht->size * sizeof(HTBALE_INFO *));
    HTBALE_INFO **p = ht->data;
    HTBALE_INFO **old_entry = ht->data;
    ht->data =h;

    int i;
    HTBALE_INFO *ptr;
    HTBALE_INFO *next;
    for(i = 0; i < old_size; i++)
    {
        for(ptr = *p++; ptr; ptr = next)
        {
           next = ptr->next;
           htable_link(ht, ptr);
        }

    }
    free(old_entry);
}


void htable_link(HTABLE *ht, HTBALE_INFO *element)
{
    assert(ht);
    assert(element);
    element->next = NULL; //when we are coding, we must set pointer to null
    element->prev = NULL; //especially there are so many malloc and free function
    int index = hash_function(element->key, ht->size);
    if(ht->data[index])
    {
        ht->data[index]->prev = element;
        element->next = ht->data[index];
    }
    ht->data[index] = element;
    ht->used++;
}

void htable_insert(HTABLE *ht, char *key, char *value)
{
    assert(ht);
    assert(key);
    assert(value);
    if(ht->used >= ht->size)
        htable_growth(ht);
    HTBALE_INFO *h = (HTBALE_INFO *)malloc(sizeof(HTBALE_INFO));
    h->key = key;
    h->value = value;
   // h->next = NULL;
   // h->prev =NULL;
    htable_link(ht, h);
}

void htable_delete(HTABLE *ht, const char *key)
{
    HTBALE_INFO *h = htable_locate(ht, key);
    if(h != NULL)
    {
        if(h->prev == NULL)
            ht->data[hash_function(key, ht->size)] = NULL;
        else if(h->next == NULL)
            h->prev->next = NULL;
        else
        {
            h->next->prev = h->prev;
            h->prev->next = h->next;
        }
        free(h->key);
        free(h->value);
        free(h);
        ht->used--;
    }
    else
    {
        printf("do not have this key\n");
    }
}


char *htable_find(HTABLE *ht, const char *key)
{
    int index = hash_function(key, ht->size);
    HTBALE_INFO *h = ht->data[index];
    for(; h && (strcmp(h->key, key) != 0); h = h->next);
    if(h == NULL)
        return NULL;
    return h->value;
}

HTBALE_INFO *htable_locate(HTABLE *ht, const char *key)
{
    int index = hash_function(key, ht->size);
    HTBALE_INFO *h = ht->data[index];
    for(; h && (strcmp(h->key, key) != 0); h = h->next);
    if(h == NULL)
        return NULL;
    return h;
}

HTBALE_INFO **htable_list(HTABLE *ht)
{
    assert(ht);
    HTBALE_INFO **list = (HTBALE_INFO **)malloc(sizeof(*list) *(ht->used +1));
    memset(list, 0 , sizeof(HTBALE_INFO *) *(ht->used +1));
    int i;
    HTBALE_INFO *h;
    int count = 0;
    for(i = 0; i < ht->size; i++)
    {
        for(h = ht->data[i]; h; h = h->next)
        {
            list[count++] = h;
        }
    }
    list[count] = NULL;
    return list;
}
void htable_list_free(HTBALE_INFO **list)
{
    assert(list);
    free(list);
}

//main.c

/************************************************
 * @aurhor Jacky Lau
 * @data   11/01/2014
 *
 ************************************************/

#include"htable.h"
#include<malloc.h>
#include<stdio.h>

void test_htable()
{
    HTABLE * ht = htable_create(10);
   // HTBALE_INFO *h = (HTBALE_INFO *)malloc(sizeof(HTBALE_INFO));
    int i;
    for(i = 0; i < 100; i++)
    {
        char *key = (char *)malloc(16);
        snprintf(key, 16, "key is %d", i);
        char *value = (char *)malloc(16);
        snprintf(value, 16, "value is %d",i);
        htable_insert(ht, key ,value);

        //printf("hash_function(%s): %d\n", key, hash_function(key, ht->size));
    }



    char *search_key = (char *)malloc(16);
//    for(i = 0; i < 20; i++)
//    {
//        snprintf(search_key, 32, "key is %d", i);
//        if(htable_find(ht, search_key) != NULL)
//            printf("%s\n", htable_find(ht, search_key));
//    }

    for(i = 0; i < 10; i++)
    {
        snprintf(search_key, 16, "key is %d", i);
        htable_delete(ht, search_key);
    }
    free(search_key);

    HTBALE_INFO **list = htable_list(ht);
    for(i = 0; i < ht->used; i++)
        printf("%s %s\n", list[i]->key, list[i]->value);
    htable_list_free(list);
    printf("table size %d, used %d\n", ht->size, ht->used);
    htable_destroy(ht);

}

int main()
{
    test_htable();
    return 1;
}

运行结果如下;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值