简单字符串哈希表的实现
为什么去做这个?
之前接触过一些简单哈希表的实现,是用数字进行实现的,而在生活的大多数场景中,还是比较多的去使用的是字符串,那么就产生了将字符串保存入哈希表的想法,在这里使用的字符串是一些URL,在工作中,我们往往会接触到MQTT这个协议,其中发布与订阅者之间的订阅树的维护,就是使用这种解析URL以后,将其存放到对应的哈希表中。关于这一部分内容,感兴趣的小伙伴可以去看看逍遥子的mosquitto源码解析,https://blog.csdn.net/sinat_31500569/article/details/64200902?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522162061160616780357298624%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=162061160616780357298624&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-10-64200902.pc_search_result_no_baidu_js&utm_term=mosquitto+%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90&spm=1018.2226.3001.4187,还有一些代码的优化,也很实用。
代码展示
头文件
#ifndef __HASH_H__
#define __HASH_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASH_TABLE_SIZE 676
#define URL_SIZE 128
#define URL_LEN 32
#define ASCII_A 161
#define FRIST_BIT 0
#define TWO_BIT 1
typedef char DataType[URL_SIZE];
typedef struct node
{
DataType Data;
struct node *pNext;
}LinkNode;
#endif
c文件
#include "hash.h"
//创建哈希表组
LinkNode *HashTable[HASH_TABLE_SIZE] = {0};
//寻找url二级键值
char* getKeyValue(char *url)
{
char *new_url = NULL;
new_url = strtok(url,"/");
new_url = strtok(NULL,"/");
return new_url;
}
//将键值转化为数字键值
int getIdxValue(char *key)
{
char valuel = 0;//键值第一个字母
char two_valuel = 0;//键值第二个字母
char keykey[URL_SIZE] = {0};
int idxl = 0;
if(NULL != key)
{
strcpy(keykey,key);
valuel = keykey[FRIST_BIT];
two_valuel = keykey[TWO_BIT];
idxl = (valuel -'\0') + (two_valuel-'\0') - ASCII_A;
return idxl;
}
return 0;
}
//将url插入哈希表
int InsertHashTable(char *url)
{
int len = 0;
char old_url[URL_SIZE] = {0};
char *value = NULL;
strcpy(old_url,url);
char *key = getKeyValue(url);
if(NULL == key)
{
return 0;
}
int idx = getIdxValue(key);
len = strlen(key);
value = strstr(old_url,key);
value++;
value += len;
LinkNode *pInsertNode = malloc(sizeof(LinkNode));
if(NULL == pInsertNode)
{
perror("fail to malloc");
return -1;
}
strcpy(pInsertNode->Data,value);
pInsertNode->pNext = NULL;
LinkNode **ppTmp = &HashTable[idx];
while(NULL != (*ppTmp))
{
ppTmp = &((*ppTmp)->pNext);
}
pInsertNode->pNext = *ppTmp;
*ppTmp = pInsertNode;
}
//打印哈希表
void ShowHashTable()
{
int i = 0;
for(i = 0; i < HASH_TABLE_SIZE;i++)
{
if(NULL != HashTable[i])
{
LinkNode *pTmpNode = HashTable[i];
while(pTmpNode != NULL)
{
printf("%s ",pTmpNode->Data);
pTmpNode = pTmpNode->pNext;
}
printf("\n");
}
continue;
}
}
//查找哈希表中是否存在该url
int FindHashTable(char *url)
{
int len = 0;
char old_url[URL_SIZE] = {0};
char *value = NULL;
strcpy(old_url,url);
char *key = getKeyValue(url);
if(NULL == key)
{
return 0;
}
int idx = getIdxValue(key);
len = strlen(key);
value = strstr(old_url,key);
value++;
value += len;
LinkNode *pTmpNode = HashTable[idx];
while(pTmpNode != NULL)
{
if(!strcmp(pTmpNode->Data,value))
{
printf("有该URL:%s\n",pTmpNode->Data);
return 1;
}
pTmpNode = pTmpNode->pNext;
}
return 0;
}
//销毁哈希表
void DestroyHashTable()
{
int i = 0;
LinkNode *pFreeNode = NULL;
LinkNode *pTmpNode = NULL;
for(i = 0; i < HASH_TABLE_SIZE; i++)
{
pTmpNode = HashTable[i];
while(pTmpNode != NULL)
{
pFreeNode = pTmpNode;
pTmpNode = pTmpNode->pNext;
free(pFreeNode);
}
}
return;
}
int main(void)
{
char value[URL_SIZE] ={0};
int i = 0;
char url[URL_LEN][URL_SIZE] ={"/ISA/Syste/device","/ISA/System/time",
"/ISA/Syste/time/timeZ","/ISA/System/upgradeFlag",
"/ISA/Syste/Hardwar/capabilities","/ISA/System/Software/capabilities",
"/ISA/Syste/Vid/inputs/OSDLanguage","/ISA/System/Video/inputs/1/overlays",
"/ISA/Event/channels/capabilities","/ISA/PTZCtrl/channels/1",
"/ISA/Ctrl/channe/1/maxele/capabil","/ISA/Image/proportionalpan",
"/ISA/Image/channels/1/i","/ISA/Security/sessionHear"};
for(i = 0; i < URL_LEN;i++)
{
if(NULL != url[i])
{
InsertHashTable(url[i]);
}
}
ShowHashTable();
printf("请输入查找URL:\n");
scanf("%s",value);
if(!FindHashTable(value))
{
printf("没有找到这个数\n");
}
DestroyHashTable();
return 0;
}
总结
这段代码主要适用于新手小白,可以更加深刻的体会哈希表的概念,在这里面我对键值做了两次处理,虽然不算是引用了哈希地图,但是还是有一点其中的思想在里面。希望和大家一起学习,有什么问题,相互讨论。