数据结构基础——哈希表(散列表)查找算法(附C语言算法实现)

哈希表又称作散列表,是一种多用于查找的数据结构,其本质上是一种利用空间换时间的做法,其需要事先分配足够大的内存空间,这实际上是非常浪费空间的,理想化的哈希表所有的操作时间复杂度都为 O(1),这表明其效率非常高。
其根据key值来计算出其的存储位置,查找时也是用key来算出其所在位置,要实现一个哈希表,我们要做到以下两点:
(1)尽可能理想
(2)尽可能一一对应
尽可能理想:理想化的哈希表是不存在冲突情况的,当H(key1)=H(key2),这时表明发生了冲突,尽可能的少发生冲突就是我们要做的。
尽可能一一对应:一个key对应一个地址位置,这样可以使哈希表的效率达到O(1)级,此时哈希表的操作效率最高。

一.使用k来找存储位置的方法:

(1)直接定址法
例如:
H(k)=k-1;
简单直接的算式来计算出地址

(2)数字分析法
找值中任意几位不同的数字为哈希地址,尽可能使其不冲突:
例如:
123566890
123546890
123343890
123328890
我们可以看出中间三位数互不相同,则可以用中间三位作为地址

(3)平方取中法
关键字较短时,k取平方后在使用数字分析法得出结果。

(4)折叠法
例如:123456789
789+456+123=1368,去掉进位后取368作为地址

(5)除留余数法(最常用)
H(k)=k%m;
m大于我们分配的数组空间长度
m的限制:m最好为质数,这样可以尽可能避免冲突

二.处理冲突的方法

1.开放定址法(常用)
分为:
(1)线性探测再散列
根据余数定位置,若位置上已经有元素存在,则加上增量di,再次探测定位置,如此反复,直到发现我们需要找的值为止。
(2)二次探测再散列
双向探测,增一个减一个,增1,减1,增4,减4…

(3)伪随机探测再散列

2.链地址法
在这里插入图片描述
如上图所示,数据存储类似于链表,同位置可放多个元素,使用链表将其链起来。搜索时通过k找到地址后遍历这些链表即可。

3.公共溢出区法
在这里插入图片描述
如上图所示,设置一个公共溢出区,同一位置若有多个元素需要插入,则后来的元素放入公共溢出区即可。

哈希表的C语言实现:


#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
//设置一个数组分配空间大小
#define HASHSIZE 10
//设置最小int用于初始化
#define NULLKEY -32768 

int m = 0;

typedef struct
{
	int* elem;
	int count;
}HashTable;


//初始化哈希表
int Init(HashTable* H)
{
	m = HASHSIZE;
	H->count = m;
	H->elem = (int*)malloc(sizeof(int) * m);
	if (H->elem == nullptr)
	{
		printf("动态内存分配失败!");
		exit(-1);
	}
	for (int i = 0;i < m;i++)
	{
		H->elem[i] = NULLKEY;
	}
	return 1;
}

//哈希算法
int Hash(int k)
{
	//除留余数法
	return k % m;
}

//根据k插入元素
void Insert(HashTable* H, int k)
{
	int addr = Hash(k);
	while (H->elem[addr] != NULLKEY)
	{
		//开放定址法
		addr = (addr + 1) % m;
	}
	H->elem[addr] = k;
}

//搜索某个元素位置
int Search(HashTable* H, int k)
{
	int addr = Hash(k);
	while (H->elem[addr] != k)
	{
		//开放定址法
		addr = (addr + 1) % m;
		//addr==Hash(k)是指这个数组满了,无法再插入元素
		if (H->elem[addr] == NULLKEY || addr == Hash(k))
		{
			return -1;
		}
	}
	return addr;
}

//遍历哈希表
void Result(HashTable* H)
{
	for (int i = 0;i < m;i++)
	{
		printf_s("%d\n", H->elem[i]);
	}
}

//主函数调用
void main()
{
	int i, j, addr;
	HashTable H;
	int arr[HASHSIZE] = { NULL };
	Init(&H);
	printf("输入关键字集合:");
	for (i = 0; i < HASHSIZE; i++)
	{
		scanf_s("%d", &arr[i]);
		Insert(&H, arr[i]);
	}
	Result(&H);

	printf("输入需要查找的元素:");
	scanf_s("%d", &j);
	addr = Search(&H, j);
	if (addr == -1)
		printf("元素不存在\n");
	else
		printf("%d元素在表中的位置是:%d\n", j, addr);

}

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值