用此程序,演示了

1哈希表的建表和删除

2哈希函数

3哈希表插入结点

4打印哈希表对应位置

5哈希表根据键值查找

等功能

#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#define HARSH_TABLE_MAX_SIZE 3 // 哈希数组的最大元素个数

//哈希表节点定义
typedef struct HarshNode
{
    char *sKey;
    int nValue;
    // [sKey,nValue]是一对键值对
    //名值对=键值对=属性值对
    //元组的集合< name,value >
    struct HarshNode *pNext;
} HarshNode;

//哈希结点指针数组
//表中每一个元素都是指向结点的指针
HarshNode *myHarshTable[HARSH_TABLE_MAX_SIZE];
//这个变量用于记录哈希表中结点总数
unsigned int myHarshTableNodeNum = 0;
//用于将上述myHarshTable初始化
void myHarshTableInit()
{
    memset(myHarshTable, 0, sizeof(HarshNode *) * HARSH_TABLE_MAX_SIZE);
    myHarshTableNodeNum = 0;
}
//用于删除myHarshTable
//首先要删除各个结点中,为了保存字符串而分配的动态内存
//其次要删除各个结点本身
//该哈希表(指针数组)本身不是动态分配,故不需要删除
void myHarshTableFree()
{
    for (int i = 0; i < HARSH_TABLE_MAX_SIZE; i++)
    {
        //如果此处为空,则不必删除
        if (myHarshTable[i] == NULL)
            continue;
        //若非空则遍历该位置的每一个结点
        HarshNode *tmp1 = myHarshTable[i];
        HarshNode *tmp2;
        while (tmp1 != NULL)
        {
            free(tmp1->sKey);
            tmp2 = tmp1->pNext;
            free(tmp1);
            tmp1 = tmp2;
        }
    }
}

//利用键值求得哈希值的哈希函数
//使用时,要再进行模运算才能真正得到在哈希表中的位置
unsigned int HashFunction(const char *sKey)
{
    // https://blog.csdn.net/guotianqing/article/details/77341657
    //在遇到有char类型扩充的时候,必须要使用unsigned char才不会出错
    //默认的signed char只能表示-128~127,负数拓展到int时,会有符号拓展错误
    //只有用unsigned char才行
    //将char拓展为int时,要习惯于使用unsigned char和unsigned int
    const unsigned char *p = (const unsigned char *)sKey;
    //最初时value中保存着的,是sKey字符串中,第一个ASCII字符的int形式
    unsigned int value = *p;

    //通过这样一个变换
    //得到了跟所有的字符串都相关的哈希值value
    if (value)
    {
        for (p += 1; *p != '\0'; p++)
        {
            value = (value << 5) - value + *p;
        }
    }
    return value;
}

//根据键值对向哈希表中添加节点,如果sKey已经存在则直接更新键值nValue
//添加成功返回0,添加失败返回-1
int myHarshTableInsertNode(const char *sKey, int nValue)
{
    //首先存入哈希表指针数组中对应位置的头指针
    //随后经过遍历,达到对应位置链表的尾部
    HarshNode *pHarshNode = NULL;
    //保存键值对的新结点
    HarshNode *pNewNode = NULL;
    unsigned int pos = 0x0;

    //要保证装填因子小于1,并且要保证输入的键值非空
    //否则输入无效,返回-1
    if ((myHarshTableNodeNum >= HARSH_TABLE_MAX_SIZE) || (NULL == sKey))
    {
        printf("Node-Insert fail!\n");
        return -1;
    }
    //求出该键值对应在哈希表中的位置
    pos = HashFunction(sKey) % HARSH_TABLE_MAX_SIZE; //用这种方法计算sKey在哈希数组中对应的位置

    //插入成功,告知结点插入位置
    printf("The node is inserted at %d. \n", pos);

    pHarshNode = myHarshTable[pos];

    //此处首先判断现有键值是否已经存在
    //并为采用尾插法插入结点做准备
    //注意到此处没有头结点,只有头指针,故要对头指针采用特殊对待
    int isEmptyPos = 0;
    if (!pHarshNode)
        isEmptyPos = 1;
    else
    {
        HarshNode *tmp = pHarshNode->pNext;
        while (NULL != tmp)
        {
            if (strcmp(pHarshNode->sKey, sKey) == 0)
            {
                pHarshNode->nValue = nValue;
                return 0;
            }
            pHarshNode = tmp;
            tmp = pHarshNode->pNext;
        }
    }

    /* ----------- 以下语句用于赋值新结点 ---------- */
    //申请一块HarshNode大小的内存,分配给新结点
    //用于保存键值对
    pNewNode = (HarshNode *)malloc(sizeof(HarshNode));
    //如果内存不够则返回一个-1
    if (NULL == pNewNode)
    {
        return -1;
    }
    memset(pNewNode, 0, sizeof(HarshNode));
    //在这个结点内,申请一块存放字符串键值的空间
    pNewNode->sKey = (char *)malloc(strlen(sKey) + 1);
    //同样地,内存不够则返回-1
    if (NULL == pNewNode->sKey)
    {
        free(pNewNode);
        return -1;
    }
    memset(pNewNode->sKey, 0, strlen(sKey) + 1);
    //以上将空间分配完毕
    //以下将键值和值都赋予对应结点,正式初始化结点
    strcpy(pNewNode->sKey, sKey);
    pNewNode->nValue = nValue;
    pNewNode->pNext = NULL;
    /* ---------------------------------- */

    //采用尾插法插入结点
    if (isEmptyPos)
        myHarshTable[pos] = pNewNode;
    else
        pHarshNode->pNext = pNewNode;

    //最终成功插入了一个新结点,哈希表总结点数加1
    myHarshTableNodeNum++;

    return 0;
}

//哈希表中对应的pos位置的一串哈希值打印出来
void PrintHarshNode(int pos)
{
    HarshNode *pHarshNode = NULL;

    if (pos >= HARSH_TABLE_MAX_SIZE)
        return;

    pHarshNode = myHarshTable[pos];

    if (NULL == pHarshNode)
        printf("This position is empty!\n");
    else
        printf("This position is not empty: \n");

    while (NULL != pHarshNode)
    {
        printf("This node is: \n");
        printf("Position:%d, sKey:%s, nValue:%d \n", pos, pHarshNode->sKey, pHarshNode->nValue);
        pHarshNode = pHarshNode->pNext;
    }
}

//根据键值sKey查找对应的哈希节点
//找到则返回对应结点指针
//没有找到则返回空指针
HarshNode *myHarshTableLookUp(const char *sKey)
{
    unsigned int pos = 0;
    HarshNode *pHarshHead = NULL;

    if (NULL == sKey)
        return NULL;

    //根据哈希值计算出在哈希表中的位置
    pos = HashFunction(sKey) % HARSH_TABLE_MAX_SIZE;
    pHarshHead = myHarshTable[pos];

    //在对应位置寻找
    while (NULL != pHarshHead)
    {
        if (strcmp(sKey, pHarshHead->sKey) == 0)
            //找到了则返回对应指针
            return pHarshHead;

        pHarshHead = pHarshHead->pNext; // 没有找到的话来到下一个节点
    }
    //最终没有找到则返回空指针
    return NULL;
}

int main()
{
    //用于初始化哈希表
    myHarshTableInit();

    //先多插入几组数据
    myHarshTableInsertNode("hungers", 12345);
    myHarshTableInsertNode("qwerty", 54321);

    //待插入的键值对如下
    //在"abcd"的名称下,存有1234这个值
    char *pSkey = "abcd";
    int nValue = 1234;
    // return指示哈希结点是否成功插入哈希表中
    int ret = -1;
    //pos存入哈希值插入的位置
    int pos = 0xffffffff;
    //用于存放查找哈希值时,返回的指针
    HarshNode *pHarshNode = NULL;

    //将键值对存入哈希表中
    ret = myHarshTableInsertNode(pSkey, nValue);

    if (!ret)
    {
        pos = HashFunction(pSkey) % HARSH_TABLE_MAX_SIZE;
        printf("Try to find and print all the saved data at:%d\n", pos);
        PrintHarshNode(pos);
    }

    pHarshNode = myHarshTableLookUp(pSkey);

    if (NULL != pHarshNode)
    {
        printf("We could also find the node directly according to the sKey:%s\nthe nValue is: %d\n", pHarshNode->sKey, pHarshNode->nValue);
    }
    //一定要释放动态分配的空间
    myHarshTableFree();
    return 0;
}
/*
The node is inserted at 1. 
The node is inserted at 0. 
The node is inserted at 1. 
Try to find and print all the saved data at:1
This position is not empty: 
This node is: 
Position:1, sKey:hungers, nValue:12345 
This node is: 
Position:1, sKey:abcd, nValue:1234 
We could also find the node directly according to the sKey:abcd
the nValue is: 1234
*/

参考:https://blog.csdn.net/weixin_40204595/article/details/81584679