一、哈希表
哈希表(Hash Table,又称为散列表),一个通过哈希函数来计算数据的存储位置的数据结构,是一种线性表的存储结构。
哈希表由一个直接寻址表和一个哈希函数组成,哈希函数 h(k) 将关键字 k 作为自变量,返回元素的存储下标。
1、哈希函数
哈希函数 h(k) 将关键字 k 作为自变量,计算并返回元素的存储下表。
2、直接寻址表
将 key 为 k 的元素放到 k 位置上,适用于关键字的全域U比较小时。
直接寻址表缺点:
当域U很大时,需要消耗大量的内存,不实际。
如果域U很大,而实际出现的 key 很少,则大量内存被浪费。
无法处理关键字不是数字的情况。
3、改进的直接寻址表--哈希(Hashing)
1、构造大小为m的寻址表T
2、key为 k 的元素放到 h(k) 位置上
3、h(k) 是一个函数,将其域映射到表T [ 0,1,2,3,···,m-1 ]
假设有一个长度为7的哈希表,哈希表函数 h(k) = k%7. 元素集合{14,22,3,5}的存储方式如下图:
4、哈希冲突
由于哈希表的大小是有限的,而要存储的值的总数量是无限的,因此对于任何哈希函数,都会出现两个不同的元素映射到同一个位置上的情况,这种情况叫做哈希冲突。
比如 h(k) = k%7. h(0)=h(7)=h(14)=···
5、解决冲突方法
方法一、开放寻址法
如果哈希函数返回值的位置已经有值,则可以向后探查新的位置来存储这个值。
线性探查:如果位置 i 被占用,则探查 i+1, i+2,···
二次探查:如果位置 i 被占用,则探查 i+1^2, i-1^2, i+2^2, i-2^2,···
二次哈希:有 n 个哈希函数,当使用第 i 个哈希函数h1发生冲突时,则尝试使用h2,h3,···
方法二、拉链法
哈希表的每一个位置都连接一个链表,当冲突发生时,冲突的元素将被加到该位置链表的最后。比如:h(k)=k%5
6、哈希表代码实现--拉链法
# 先写一个构建链表的函数,封装到类里面,尾插法,单个元素插入,元素查找。
class Node:
def __init__(self, item):
self.item = item
self.next = None
class Linklist:
def __init__(self):
self.head = None # 定义头结点
self.tail = None # 定义尾节点
def create_linklist(self, element): # 利用尾插法创建链表
node = Node(element)
if self.head == None: # 当链表为空时
# 使插入元素成为头结点和尾节点
self.head = node
self.tail = self.head
else:
self.tail.next = node # 当链表不为空时,使用尾插法
self.tail = node
return self.head
def linklist_find(self, obj): # 元素的查询
curnode = self.head
while curnode:
if curnode.item == obj:
return True
curnode = curnode.next
else:
return False
def linklist_print(self): # 链表打印
curnode = self.head
while curnode:
print(curnode.item, end=" ")
curnode = curnode.next
class Hash_table():
def __init__(self, size=101): # size哈希表长度
self.size = size
self.T = [Linklist() for _ in range(size)] # 定义一个size长度的列表,列表中每个位置都是空链表
# 哈希函数
def h(self, element):
return element % self.size # 返回哈希函数计算生成的下标
# 哈希表插入
def insert_hash(self,k):
i = self.h(k)
if self.T[i].linklist_find(k): # 在列表中对应的位置链表插入
print('Duplicated insert')
else:
self.T[i].create_linklist(k)
# 列表形式插入
def insert_hash_list(self, li):
for var in li:
self.insert_hash(var)
def print_hash(self): # 打印哈希表
for linklist in self.T:
linklist.linklist_print()
ht = Hash_table(5)
ht.insert_hash_list([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
ht.print_hash()