NoFear

导航

哈希表的简单实现【链地址法解决冲突】

Posted on 2012-08-29 12:58  Fear_Hao  阅读(3150)  评论(0编辑  收藏  举报
//节点类
struct LISTNODE
{
    int n_value ;
    int count;
    char *str_value ;
    LISTNODE * p_next ;
};
//哈希表
struct HASHTABLE
{
    int n_tablesize ;
    LISTNODE ** p_node ;
};

void hashtable_clear(HASHTABLE* head_ht);
LISTNODE* hashtable_find(char *str ,HASHTABLE* head);
int hashtable_hash(char* str, int tablesize);
HASHTABLE * hashtable_init( int table_size );
LISTNODE * hashtable_newnode(char* str , int len);
int hashtable_insert(char * str, HASHTABLE * head);


//初始化
HASHTABLE * hashtable_init( int table_size )
{
    //表头
    HASHTABLE * head_ht ;

    head_ht = (HASHTABLE *)malloc( sizeof(HASHTABLE ));
    if(head_ht == NULL)
        return NULL ;
    //元素总数尽量素数保证mod尽可能均匀
    head_ht->n_tablesize = table_size;

    //链表队列一条链为一个散列位置
    head_ht->p_node = (LISTNODE **) malloc(sizeof (LISTNODE*) * table_size);

    //每一个散列链初始化
    for(int i=0; i<head_ht ->n_tablesize; i++)
    {
        head_ht->p_node[i] = NULL;
    }

    return head_ht ;
}

//清理
void hashtable_clear (HASHTABLE* head_ht)
{
    if(head_ht == NULL)
        return;

    //每一个散列链free
    for(int i=0; i<head_ht ->n_tablesize; i++)
    {
        if(head_ht ->p_node[ i])
        {
            LISTNODE *list = head_ht->p_node[i];

            //当前链表不空
            while(list != NULL)
            {
                //取得下一个
                LISTNODE *tempnode = list-> p_next;
                //free当前字符串指针
                if(list ->str_value)
                {
                    free(list ->str_value);
                    list->str_value = NULL;
                }
                //free当前位置
                if(list )
                    free(list );
                //指向下一个
                list = tempnode ;
            }
        }
    }

    //链表队列free
    if(head_ht ->p_node)
    {
        free(head_ht ->p_node);
        head_ht->p_node = NULL;
    }

    //哈希头节点free
    if(head_ht )
    {
        free(head_ht );
        head_ht = NULL ;
    }

}

//哈希函数
//得到字符串在哈希表中的位置
int hashtable_hash (char* str, int tablesize)
{
    unsigned int hash_val = 0;

    while(*str != '\0')
        hash_val += (hash_val << 5) + *str++;

    int pos = hash_val % tablesize;
    return pos ;
}

//拿到这个字符串存在的节点
LISTNODE * hashtable_find( char *str ,HASHTABLE* head)
{
    //哪一条链表
    LISTNODE * list = NULL;

    if(head == NULL)
        return NULL ;
    int pos = hashtable_hash(str,head-> n_tablesize);
    list = head ->p_node[pos];

    //链表查找
    while(list != NULL)
    {
        if(memcmp (str, list->str_value ,strlen( str)) == 0)
            break;
        list = list ->p_next;
    }

    return list ;
}

//得到新一个新节点
LISTNODE * hashtable_newnode( char* str , int len)
{
    //插入节点初始化
    LISTNODE *insert_node =(LISTNODE*) malloc(sizeof (LISTNODE));
    insert_node->p_next = NULL;
    insert_node->count = 1;
    insert_node->str_value =(char*) malloc(len +1);
    memset(insert_node ->str_value,0, len+1);
    memcpy(insert_node ->str_value, str,len );
    return insert_node ;

}

int hashtable_insert (char * str, HASHTABLE * head)
{
    //拿到哈希位置
    int pos = hashtable_hash( str,head ->n_tablesize);
    int len = strlen( str);

    printf("[insert] %s pos:%d\n",str,pos);

    //拿到插入的链表
    LISTNODE *list_pos =  head-> p_node[pos];

    //假如存在 计数器+1
    for(;list_pos!=NULL;list_pos=list_pos->p_next)
    {
        if(memcmp(list_pos->str_value,str,strlen(str)) == 0)
        {
            list_pos->count++;
            return pos;
        }
    }
    
    //不存在
    LISTNODE *node = hashtable_newnode(str,strlen(str));

    node->p_next = head-> p_node[pos];
    head-> p_node[pos] = node;

    return pos ;
}


int main (void)
{
    HASHTABLE * head ;
    //初始一个个链表的哈希表 size最好为素数
    head = hashtable_init (1001);
    //插入一个字符串"12345"返回值为插入链表位置
    hashtable_insert("12345" ,head);
    hashtable_insert("12345" ,head);
    hashtable_insert("12345" ,head);
    //找到这个字符串具体位置
    LISTNODE * node = hashtable_find( "12345",head );

    if(node != NULL)
        printf("str:%s count:%d",node->str_value,node->count);

    //清理
    hashtable_clear(head );
    return 0;
}