哈希桶(链地址法)

哈希表使用链地址法进行数据的存储

哈希桶是在发生冲突时,将数据直接链接在该表位置的后面

当发生冲突时采用链式结构,将相同地址的数链接在后面。适用于经常删除和增加的情况。

当同一地址连接的数据过多时,就会造成效率过低,退化。

#ifndef __hashtablebucket_h__
#define __hashtablebucket_h__
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int HTBKeyType;
typedef int HTBvalueType;

typedef struct HashNode     //存放数据节点
{
    struct HashNode* next;  
    HTBKeyType key;
    HTBvalueType value;
}HashNode;

typedef struct HashTableBucket  //定义哈希桶
{
    HashNode** tables;
    int size;
    int len;
}HTB;
//初始化
void HTBInit(HTB* htb, int len);
//销毁
void HTBDestroy(HTB* htb);
//插入
int HTBInsert(HTB* htb, HTBKeyType key, HTBvalueType value);
//删除
int HTBRemove(HTB* htb, HTBKeyType key);
//查找
HashNode* Find(HTB* htb,HTBKeyType key);
//大小
int HTBsize(HTB* htb);
//判空
int HTBEmpty(HTB* HTB);



#endif

初始化函数

void HTBInit(HTB* htb,unsigned long len)

{
    assert(htb);
    int i = 0;
    // 使用素数表对齐做哈希表的容量,降低哈希冲突
    static const unsigned long _PrimeList[28] =
    {
        53ul, 97ul, 193ul, 389ul, 769ul,
        1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
        49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
        1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
        50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
        1610612741ul, 3221225473ul, 4294967291ul
    };
    for (i=0; i < 28; i++)    //选取合适的素数表长
    {
        if (len < _PrimeList[i])
        {
            len = _PrimeList[i];
            break;
        }
    }
    htb->len = len;
    if ((htb->tables = (HashNode**)malloc(sizeof(HashNode*)*htb->len)) == NULL)
        return; 
    htb->size = 0;
    for (i = 0; i < htb->len; i++)
        htb->tables[i] = NULL;

}

哈希函数

int  HashFunc(HTB* htb,HTBKeyType key)
{
    return (key%htb->len);
}

分配数据节点空间

HashNode* BuyNode(HTBKeyType key,HTBvalueType value)
{
    HashNode* node = malloc(sizeof(HashNode));
    node->key = key;
    node->next = NULL;
    node->value =value;

    return node;
}

扩容函数

HashNode* CheckCapacity(HTB* htb)
{
    assert(htb);
    if ((htb->size / htb->len) * 10 > 7)  //当装填因子大于0.7时进行空间的增容
    {
    int i = 0;
    HTB newtables;
    HashNode* cur;
    HashNode* prev;
    int index = 0;
    HTB* new ;
    HTB* tmp;
    new = &newtables;

        HTBInit(new, htb->len);//开辟新的空间
        if (new != NULL)
        {
            for (; i < htb->len; i++)
            {
                cur = htb->tables[i];
                while (cur)
                {
                    HTBInsert(new, cur->key, cur->value);   //将原空间的数重新转进新开的空间中
                    cur = cur->next;
                }
            }
        }
        tmp =htb;
        HTBDestroy(tmp);
        htb->tables = new->tables;   //将新开的空间给旧的空间
        htb->len = new->len;
        htb->size = new->size;
    }
    return htb;
}

插入一个节点

//插入
int HTBInsert(HTB* htb, HTBKeyType key, HTBvalueType value)

{
    assert(htb);
    int index = 0;
    HashNode* tmp;
    htb=CheckCapacity(htb);   //扩容
    index = HashFunc(htb,key);   //哈希函数计算位置
    tmp = BuyNode(key, value);
    if (tmp == NULL)
        return -1;
    if (htb->tables[index] == NULL)      //当第一个节点为空时
        htb->tables[index] = tmp;
    else                                  //第一个节点不为空,头插
    {
        tmp->next = htb->tables[index];
        htb->tables[index] = tmp;
    }
    htb->size++;
    return 0;
}

删除一个节点

int HTBRemove(HTB* htb, HTBKeyType key)
{
    assert(htb);
    HashNode* cur=NULL;
    HashNode* prev=NULL;
    int index;
    index = HashFunc(htb, key);
    cur = htb->tables[index];
    while (cur)
    {
        if (cur->key == key)
        {
            if (cur == htb->tables[index])      //当第一个节点为空,直接删除
            htb->tables[index] = cur->next;
            else
                prev->next = cur->next;        //第一个节点不为空
            free(cur);
            cur = NULL;
            htb->size--;
            return 0;
        }
        prev = cur;
        cur = cur->next;
    }
    return -1;
}

查找

HashNode* Find(HTB* htb,HTBKeyType key)
{

    assert(htb);
    int index;
    index = HashFunc(htb,key);
    HashNode* cur=htb->tables[index];   //确定该数的位置
    while (cur)
    {
        if (cur->key == key)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}
//打印
void HTBprint(HTB* htb)
{
    assert(htb);
    HashNode* cur;
    int i = 0;
    if (htb->size == 0)
        return;
    for (; i < htb->len; i++)
    {
        cur = htb->tables[i];
        printf("%d: ",i);
        while (cur)
        {
            printf("->%d:%d", cur->key, cur->value);
            cur = cur->next;
        }
        printf("\n");
    }
}

猜你喜欢

转载自blog.csdn.net/M_jianjianjiao/article/details/82424626