哈希表(闭散列、拉链法--哈希桶)

本文介绍了哈希表的基本概念、多种哈希函数以及处理哈希冲突的方法,包括线性探测、二次探测和拉链法。重点讲解了闭散列的线性和二次探测解决冲突,并通过代码示例展示了闭散列的实现。同时,讨论了哈希桶(拉链法)在处理大量数据时的优势,并提出了使用红黑树优化链表过长的情况。
摘要由CSDN通过智能技术生成

       哈希表,也称散列表,是一种通过key值来直接访问在内存中的存储的数据结构。它通过一个关键值的函数(被称为散列函数)将所需的数据映射到表中的位置来访问数据。

关于哈希表,主要为以下几个方面:

一、哈希表的几种方法

1、直接定址法:取关键字key的某个线性函数为散列地址,如Hash(key) = key  或 Hash(key) = A*key+B;A,B为常数

2、除留取余法:关键值除以比散列表长度小的素数所得的余数作为散列地址。Hash(key) = key % p;

3、平均取中法:先计算构成关键码的标识符的内码的平方,然后按照散列表的大小取中间的若干位作为散列地址。

4、折叠法:把关键码自左到右分为位数相等的几部分,每一部分的位数应与散列表地址位数相同,只有最后一部分的位数可以短一些。把这些部分的数据叠加起来,就可以得到具有关键码的记录的散列地址。分为移位法和分界法。

5、随机数法:选择一个随机函数,取关键字的随机函数作为它的哈希地址。

6、数学分析法:设有N个d位数,每一位可能有r种不同的符号。这r种不同的符号在各位上出现的频率不一定相同,可能在某些位上分布均匀些,每种符号出现的机会均等;在某些位上分布不均匀,只有某几种符号经常出现。可根据散列表的大小,选取其中各种符号分布均匀的若干位作为散列地址。


在这里,我们建哈希表的方法用除留取余法为例。

尽管有这么多种方法,但是不同的key值可能会映射到同一散列地址上。这样就会造成哈希冲突/哈希碰撞


那么遇到哈希冲突我们该如何处理呢?


二、处理哈希冲突的闭散列方法

1、线性探测:当不同的key值通过哈希函数映射到同一散列地址上时,检测当前地址的下一个地址是否可以插入,如果可以的话,就存在当前位置的下一个地址,否则,继续向下一个地址寻找,地址++。

2、二次探测:是针对线性探测的一个改进,线性探测后插入的key值太集中,这样造成key值通过散列函数后还是无法正确的映射到地址上,太集中也会造成查找、删除时的效率低下。因此,通过二次探测的方法,取当前地址加上i^2,可以取到的新的地址就会稍微分散开。

如:此时的散列表长度为10:


看到以上的例子之后,我们只是存入int型的数据时,计算余数寻找地址是比较容易的。如果我们存入的是字典值(string类型),那么我们就要通过string类型来转化成数值来计算地址。这里用到了BKDR哈希算法(字符串哈希算法)。

同时,经研究表明,通过素数表作为哈希表的长度可以降低哈希冲突。


三、闭散列实现代码

主要实现如下:

#pragma once
#include<vector>
#include<iostream>
using namespace std;
#include<assert.h>
#include<string>

enum Status
{
	EXIST,
	DELETE,
	EMPTY
};

template<class K,class V>
struct HashTableNode
{
	K _key;
	V _value;
	Status _status;
	HashTableNode(const K&
  • 1
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值