哈希表简介以及哈希挂链方法

哈希表简介

对于数据判重的问题,我们可以遍历所有数据,看看是否重复,那么复杂度是 O ( n ) O(n) O(n)。或者如果数据存储是有序性,那么可以用二分查找的方法来看是否重复,复杂度 O ( l o g n ) O(log n) O(logn),但是为了维护有序,要付出额外的复杂度。如果数据够小甚至能用桶排的下标法,复杂度为 O ( 1 ) O(1) O(1)

那么有没有一个能兼顾存储复杂数据,维护代价小且时间复杂度小的方法呢,那就是STL map 哈希表,来解决判重问题,复杂度通常也是 O ( 1 ) O(1) O(1)的常数复杂度。

定义
根据设定的哈希函数处理冲突的方法将查找表中各数据元素存储在一段有限的连续空间中(数组),既得哈希表。
(抄自互联网)

哈希函数
哈希函数是一个自定的函数,通过数据元素值,得到一个唯一的下标,必须是唯一,否则就无法判重了。
如果出现了下标不唯一,则是冲突,就要进行处理冲突。

最简单的情况
比如说有一些学号为10000,10001,10002,10003,…,100xx的学生,那么可以将学号减去10000得到一个0-99之间的下标。这个问题中没有冲突。

int hash(int num)
{
	return num-10000;
}

显然这种方法只是因为数据有特殊性,那么对于随机的 m m m个0到n的数据呢,这个 n n n可以是一个很大的值,这个方法就显得不适用了。但是因为数据 m m m通常来说小(相对n来说,但是经常也有好几万了,不可能用暴力),所以这里可以使用取余法来做哈希表。

因为可能有100个数据,我们把数据对m求余是不是就可以得到数值在0 到 m-1 的下标了呢(m通常是一个质数,这样可以减少冲突),便可以让他直接存储到数组中。显然这里是有冲突的,那么我们该怎么解决冲突呢?

处理冲突
我们这里假设m=100来举例子,那么我们设q为大于100的一个质数比如107。
引入一个哈希挂链方法

不用数组下标直接存数据,而是定义一个链表,每个数组下标都代表着一个链首。
就是说当你遇到这个下标已经被使用时,首先判断这个链里面的元素有没有重复,如果不重复则把数据挂在链表后面就行了。因为随机数据冲突比较少所以复杂度还是常数级别。

#include<cstdlib>
#define Q 107
struct link{
	int data;
	struct link *next;
}link_hash[Q];						
//每个结构体代表每个链首,是一个不存数据的空的head
void initialization()	//初始化函数
{
	const int non=-1;		
	//存储一个不存在的数,以免和实际数据重复
	int i;
	for(i=0;i<Q;i++){
		link_hash[i].data=non;	
		link_hash[i].next=NULL;
	}
}
int hash(int num)
{
	int ind=num%Q;					//求余
	struct link *t=&(link_hash[ind]);
	while(t->next!=NULL){			//如果该链已经有元素,冲突
		if(t->data==num) return 0;	//判重
		t=t->next;					//找到链尾
	}
	t->next=malloc(sizeof(struct link));
	t=t->next;
	t->data=num;
	//挂在链尾				
	t->next=NULL;
	//注意指向NULL
	return 1;						
	//这里与上面不同的是返回值代表是否重复
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值