《算法笔记》学习笔记(7):散列

散列(hash)是常用算法之一。简单来说,散列就是将一个元素通过一个函数转换为整数,使得该整数可以尽量唯一的代表这个元素。将这个函数成为散列函数H,元素转换前为key,转换后为H(key)。
key为整数时,常用的散列函数有直接定址法、平方取中法、除留余数法等。
直接定址法有恒等变换H(key)=key和线性变换H(key)=a*key+b;
平方取中法是指取key平方中间若干位作为hash值,很少使用。
除留余数法是H(key)=key%mod,表长TSize必须不小于mod,而mod一般取素数,因此为了方便起见,把TSize取成一个素数,而mod与TSize相等。
通过除留余数法,可能会有两个不同的值和H(key)会相同,这时会发生“冲突”。要解决冲突,有以下三种方法:
1.线性探查法
发生冲突时往表中下一个位置查找,若未被占有,则是用这个位置;若被占有,则继续向下一个位置查找。若超过表长,则回到表的首位继续查找。缺点是容易扎堆。
2.平方探查法
向H(key)+12,H(key)-12,H(key)+22,H(key)-22这些位置查找,若超过表长,则对其取模。若出现H(key)-k2<0,则将
(H(key)-k2%TSize+TSize)%TSize作为结果(等价于H(key)-k2不断加上TSize直到出现第一个非负数)。若想避免负数,可以只进行正向的平方探查。
3.链地址法
在表的同一位置创建一个链表

字符串hash
字符串hash是指将一个字符串S映射为一个整数,使得该整数可以尽可能唯一地代表字符串S。
假设全是大写字母A-Z,可以将A-Z看做0-25,这样就将26个字母对应到二十六进制中,然后再将二十六进制转换为十进制,代码如下:

//全为大写字母
int hashFunc1(char S[], int len)
{
	int id = 0;
	for (int i = 0; i < len; i++)
	{
		id = id * 26 + (S[i] - 'A');
	}
	return id;
}

如果还出现了小写字母,那么可以将A-Z看做0-25,a-z看做26-51,这样就变成了五十二进制转换为十进制的问题,代码如下:

//有大小写字母
int hashFunc2(char S[], int len)
{
	int id = 0;
	for (int i = 0; i < len; i++)
	{
		if (S[i] >= 'A' && S[i] <= 'Z') 
		{
			id = id * 52+ (S[i] - 'A');
		}
		else if (S[i] >= 'a' && S[i] <= 'z')
		{
			id = id * 52 + (S[i] - 'a')+26;
		}
	}
	return id;
}

如果出现数字,则有两种做法:
1.按照小写字母的处理方法,将进制数增加到六十二
2.如果能确保在字符串末尾出现各位数字,则可以在前面英文字母部分的后面拼接上数字,代码如下:

//末尾数字
int hashFunc3(char S[], int len)
{
	int id = 0;
	for (int i = 0; i < len-1; i++)
	{
			id = id * 26 + (S[i] - 'A');
	}
	id = id * 10 + (S[len - 1] - '0');
	return id;
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值