一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天 点击查看活动详情。
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
hash算法在runtime中运用的还是比较频繁的,比如找cache_t 缓存列表里的函数等,下面就简单通过一个例子来说说,hash算法是如何运用的。
使用HASH算法找到字符串中第一个只出现一次的字符
比如有个字符串,aabbccddegh,如何去找到第一个只出现一次的字符 『e』?
废话先不多说,上代码!
char findFirstChar(char* cha){
char result = '\0';
//定义一个数组,用来存储各个字母出现的次数
int array[256];
//对数组进行初始化操作
for(int i = 0; i < 256 ; i++){
array[i] = 0;
}
//定义一个指针 指向当前字符串头部
char*p = cha;
// 遍历每个字符
while (*p != '\0'){
// 在字母对应存储位置,进行出现次数+1操作
// array['a'] = array['a'] + 1
array[*p]++;
p++;
}
// 将p指针重新指向字符串头部
p = cha;
// 遍历每个字母出现的次数
while(*p != '\0'){
// 遇到第一个出现次数为1的字符 打印结果
if (array[*p] == 1){
result = *p;
break;
}
// 反之继续向后遍历
p++;
}
return result;
}
接下来我们来详细说说
第一步
//定义一个数组,用来存储各个字母出现的次数
int array[256];
//对数组进行初始化操作
for(int i = 0; i < 256 ; i++){
array[i] = 0;
}
这个是定义一个长度为256的数组,并将数组的每一位初始化为0。
为什么是256的长度呢?
因为根据 ASCII码有128个,ASCII扩展码有128个,合计256个。
为什么要都初始化为0呢?
这个0是代表出现次数,初始化的时候,这些ASCII码出现的次数都是0次。
第二步
//定义一个指针 指向当前字符串头部
char*p = cha;
// 遍历每个字符
while (*p != '\0'){
// 在字母对应存储位置,进行出现次数+1操作
// array['a'] = array['a'] + 1
array[*p]++;
p++;
}
定义一个指针 指向当前字符串头部,开始循环找到ASCII码在数组中出现的位置,并将次数+1,然后移动指针。
其实这一步是关键。
举个栗子,
就像地上摆256个桶子,每个桶子上贴着ASCII码标签(比如 第65个桶贴着『A』标签,第66个桶贴着『B』标签),然后我们从左往右看给的字符串aabbccddegh,第一个『a』,所以应该在贴着『a』标签的桶里放一根箭,第二个也是『a』,然后再在贴着『a』标签的桶里方一根箭,以此类推。
这样子,就将给定字符串中,每个字符对应的桶里,都加上了箭,箭的个数就是这每个字符出现的次数。
p++就是表示,指针向后移动一位。
第三步
// 将p指针重新指向字符串头部
p = cha;
// 遍历每个字母出现的次数
while(*p != '\0'){
// 遇到第一个出现次数为1的字符 打印结果
if (array[*p] == 1){
result = *p;
break;
}
// 反之继续向后遍历
p++;
}
这一步比较好理解,就是重新循环这个数组array,看数组中哪个桶里箭的个数是1,就将这个桶找出来,并返回。
这样就完成了这个题的解法。
我们在结合文章开头的定义,
它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度
不难发现,前面的第二步就是完成关键码映射到数组动的动作。
结语
希望通过这个简单的算法,来加深大家对hash的了解。
大家可以下载一下,自己试试 用xcode写算法
大家觉得不错的话,不妨点个赞👍🏻