哈希表(hashtable)

由于多次查询有必要用哈希,所以今天来说说。

哈希表(c++里叫unordered_map),O(1)时间内完成,利用数组索引快速搜索的特性,哈希表依赖于数组。

再写哈希之前要解决这两个问题:

(1)定散列函数(按照什么方式分组):求整取余法index=value%M,M

是素数且>元素个数。

(2)哈希冲突(两个数据抢占同一个位置):开放定址法,拉链法(最常用的解法)。

     开放定址法:线性探测:沿着冲突地方一个一个向后找,有位置就放。二次探测:沿着冲突位置\pm 1\pm 4\pm 9\pm 16......(不希望产生冲突就得组多点,装载因子\alpha=元素个数/表长<0.8)。

     拉链法:和已有的数据构成链表,用头增法(因为头增法O(1))。

线性探测优化(闭散列):\alpha趋近于0.8扩容,旧表向新表分批次迁移,所以可能同时存在,查的时候先查新表,再查旧表。

拉链法优化(开散列):\alpha趋近1扩容,把对应的节点迁移过来,原来的节点没开辟新空间,如果某一个位置产生冲突特别多,链表很长,就需要扩桶(M),所有数据按新的规则重新分桶。

开放定址法,拉链法优缺点:

1.拉链法中各链表的节点空间是动态申请的,可以用于造表前无法确定表长。

2.开放定址法在数据规模较大时浪费很多空间,拉链法中可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计,节省空间。

3.用拉链法构造的散列表中,删除操作容易实现,开放定址法删除结点不能简单地将被删结点的空间置为空,否则将截断在它之后填入的数据的查找路径,只能在删除结点上做标记,不能真正删除。

4.数据规模较小,开放定址法节省空间,拉链法指针需要额外空间。

解决完这两个问题,我们就可以创建哈希表了,我们用拉链法创建。

由于链表知道表头就能访问,所以我们要创建的是指针数组。

步骤:

(1)定义一个链表结构体。

(2)申请指针数组并赋空。

(3)元素入组:元素根据散列函数对应相应组里,申请节点,单向链表表头添加。

(4)搜索:找到当前元素的组,链表的遍历。

#include<stdio.h>
#include<string.h>
#define M 13
typedef struct Node
{
	int val;
	struct Node* next;
}List;
List** CreateHashTable(int arr[], int len)
{
	if (arr == NULL || len == 0) return NULL;
	//申请表头
	List** phash = (List**)malloc(sizeof(List*) * M);
	//按字节赋值,多字节只能0或-1
	memset(phash, 0, sizeof(List*) * M);
	//元素入表
	int index;
	for (int i = 0; i < len; i++)
	{
		//获取索引位置
		index = arr[i] % M;
		//节点空间申请
		List* ptem = NULL;
		ptem = (List*)malloc(sizeof(List));
		ptem->val = arr[i];
		//头添加
		ptem->next = phash[index];
		phash[index] = ptem;
	}
	return phash;
}
void Hashserch(List** phash,int target)
{
	if (phash == NULL) return;
	//索引
	int index = target % M;
	List* thash = phash[index];
	while (thash)
	{
		if (thash->val == target)
		{
			printf("success\n"); return;
		}
		else
			thash = thash->next;
	}
	printf("fail\n");
}
int main()
{
	int arr[] = { 124,45,67,7,8,9,33,22,11,33,1};
	List** phash = CreateHashTable(arr, sizeof(arr) / sizeof(arr[0]));
	Hashserch(phash, 1);
	return 0;
}

  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值