从0实现哈希表

1 哈希表的定义

哈希表(hashtable),⼜称散列表,是根据关键字直接进⾏访问的数据结构。
哈希表建⽴了⼀种关键字和存储地址之间的直接映射关系,使每个关键字与结构中的唯⼀存储位置相对应。理想情况下,在散列表中进⾏查找的时间复杂度为 ,即与表中的元素数量⽆关。因此哈
希表是⼀种存储和查找⾮常快的结构。

1.2 哈希函数
将关键字映射成对应的地址的函数就是哈希函数,也叫作散列函数,记为 Hash(key) = Addr 。
哈希函数的本质也是⼀个函数,它的作⽤是,你给它⼀个关键字,它给你⼀个该关键字对应的存储位置。

1.3 哈希冲突
哈希函数可能会把两个或两个以上的不同关键字映射到同⼀地址,这种情况称为哈希冲突,也称散列冲突。起冲突的不同关键字,称它们为同义词。

2.处理哈希冲突

2.1 线性探测法
从发⽣冲突的位置开始,依次线性向后探测,直到寻找到下⼀个没有存储数据的位置为⽌,如果⾛到哈希表尾,则回绕到哈希表头的位置。
2.2 链地址法
链地址法中所有的数据不再直接存储在哈希表中,哈希表中存储⼀个指针,没有数据映射这个位置
时,这个指针为空,有多个数据映射到这个位置时,我们把这些冲突的数据链接成⼀个链表,挂在哈希表这个位置下⾯

3. 哈希表的模拟实现

3.1线性探测法
(1)创建

#include<iostream>
#include<cstring>
using namespace std;
const int N = 23;//创建一个模数
const int INF = 0x3f3f3f3f;
int h[N];

void init()
{
	memset(h, INF, sizeof h);
}


int main()
{
	init();
	return 0;
}

(2) 哈希函数以及处理哈希冲突
除留余数法: hash(key) = key % N
但是要注意, key 有可能是负数,取模之后会变成负数。
• 负数补正的操作为:加上模数即可。
• 但是正数加上模数会变⼤,所以统⼀再取⼀次模。
最终就是 (key % N + N) % N

int f(int x)
{

	int idx=(x % N + N) % N;
	// 处理冲突
	while (h[idx] != INF && h[idx] != x)
	{
		idx++;
			if (idx == N)
			{
				idx = 0;
			}
			// 如果⾛到头了,就拐个弯
	}
	return idx;
}

(3)添加元素

void insert(int x)
{
	int id = f(x);
	h[id] = x;
}

(4)查找元素

bool find(int x)
{
	int id = f(x);
	return h[id] == x;
}

3.2链地址法
(1)创建

#include<iostream>
using namespace std;
const int N = 23;
int h[N];
int e[N], ne[N], id;

(2) 哈希函数

int f(int x)
{
return (x % N + N) % N;
}

(3)查找函数

bool find()
{
	int idx = h[x];
	for (i = h[idx]; i; i = ne[i])
	{
		if (e[i] == x;)
		{
			return true;
		}
	}
	return false;
}

(4)添加元素以及处理哈希冲突

  1. 先判断是否已经在哈希表中;
  2. 如果不在,就头插在哈希值所对应的链表后。
void insert(int x)
{
	if (find(x))
	{
		return;
	}
	int idx = f(x);
	id++;
	e[i] = x;
	ne[id] = h[idx];
	h[idx] = id;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值