算法导论学习之散列表(哈希表)

在一个域中存有一些关键字对应的元素的键值,一般情况下这些键值都是被转化成自然数集中的某些数字,当然是一一对应,举个例子来说,假如对于某些子的字符串来说,我们可以把它们对应到相应的ASCII值,相应的再做些操作就可以转化了。

1)散列表链接法

首先说的是直接寻址的方法,这里对于域中的元素是不是特别的大而言的。我们可以把键值直接的作为某个数组的下标,这个下标这里就叫做槽。当然了,可能有的人会问假如对于一个槽而言的话有多个元素对应着,这里叫做冲撞,怎么办呢?书上提出了一种叫做链接法的方法。就是对于那些元素的键值一样的,对应到相同的槽的时候,就直接在相应的槽的位置上面构建一个链表。这里我们得到的元素的个数设定为n,而相应的槽的个数是m.那么相应的每个操对应的平均长度就是a=n/m;根据书上的证明我们知道的就是这种方法下一次查找成功以及不成功的时间复杂度都是O(a+1)所以在元素的个数和槽的长度是成正比的情况下的时候查找一次成功的时间复杂度是O(1);

2)散列函数

下面给出的一种方法就是叫做散列函数的方法,通过给出一个函数,来对于键值在寻址表中的槽值有那么一个唯一的对应,要做到的就是每一个键值都有唯一一个槽值对应,且相互对应之间没有干扰,这里就叫做简单唯一性。书上给出了两大类方法,具体包括:启发法(乘法和除法),全域散列(未看,下次再看)。

乘法散列:

首先给出散列函数:h(k)=,这里给出式子中的参数的意思。书上的意思是m最好是2的整次幂,A=-1/2,而对于k而言的话随机的一个正整数键值好像就可以了。上面模1的意思就是去小树部分;

除法散列:

除法散列的函数就是h(k)=k mod m;这里的话k当然就是键值了,的话就是与2的整次幂不太接近的一个质数就可以了。

3)开放寻址方法

开放寻址方法要求的是对于数组中的一个槽有唯一的一个键值于之对应,那么这里的话我们还是需要一个寻址的排列来作为中介来对应的查找,这里的话我们把槽也考虑进去,把散列函数进行扩充,

h(k,j)->i,i(0-m-1);那么这里的话要求的就是一个对于散列函数的每一个对于的值,就是槽值了,这里就是要求这个槽值要具备简单唯一性,虽然基本上这是做不到的,但是还是极近的去近似了,书上提出了三种方法:线性探查,二次探查,双重散列。其中双重散列的效果最好,因为我们知道对于槽值为m的数组,它要是随机排列的话具有m!种可能性,但是线性查找和二次查找具有的只是o(m)级别的,而双重散列好点是O(m^2),下面给出各自的数字,那么就可以很直观的看出为什么是以上的级别的排序了:

1>线性查找

线性查找的散列函数:h(k,i)=(h'(k)+1)mod m

h'(k)也是散列函数,这里叫做辅助散列函数,下同。

2>二次探查

二次查找的散列函数:h(k,i)=(h'(k)+c1*i+c2*i^2)mod m

3>双重散列

双重散列的散列函数:h(k,i)=h1'(k)+h2'(k)*imod m

下面给出的是根据开放寻址方法对键值的查找以及插入的代码,他们的时间复杂度是还是O(1),这里只是为了说明问题,所以上面的散列函数(或者是叫做辅助散列函数我都是使用除法散列函数,简单点)下面是代码:

	
#include<iostream>
using namespace std;
#define N 100
int a[N];
int t[N];
int m,n,k;
	int h1()
	{
		return k%m;	
	}//第一个散列函数使用除法
	int h2()
	{
		return (1+k%(m-2));
	}
	int h(int i)
	{
		int b=h1()+i*h2();
		return b;
	}
	int hashinsert(int *a)
	{
		int j=0;
		for(int i=0;i!=m;++i)
		{
			int j=h(i);
			if(t[j]==NULL)
				t[j]=k;
		}
		return j;
	}
	bool hashsearch(int *a)
	{
		for(int i=0;i!=m;++i)
		{
			int j=h(i);
			if(t[j]!=NULL)
			return true;
		}
	}

	

int main()
{
		cout<<"输入寻址槽m,键值元素的个数n,以及处理的关键字k"<<endl;
		cin>>m;
		cin>>n;
		cin>>k;
		cout<<"输入各个键值元素a[i]"<<endl;
		for(int i=1;i<=n;++i)
		{
			cin>>a[i];
		}
	hashinsert(a);
	hashsearch(a);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值