python散列表 链地址法解决冲突 除留余数法散列 插入删除查找操作(详细注释)

散列是数据结构中较为重要的内容。两种基本方法之一的链地址法虽稍繁琐,但思路较简单,过程清晰。

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找速度。这个映射函数叫做散列函数,记录的数组叫做散列表。

散列函数:除留余数法(取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址)建立哈希表,并判断给定值是否在散列表中。

本代码使用链冲突法解决冲突,即散列到相同地址后以建立子链的方式解决元素冲突,因此不考虑总元素大于散列表大小而溢出的情况。重复元素只存一个。

输入
第一行数字表示要建立的散列表的大小,第二行表示要作为元素建立散列表的整数序列(注意:元素之间以空格分开,第一行散列表大小并不表示本行元素的数量),第三行表示要插入元素的数量n,接下来n行表示待插入元素值;下一行表示要删除元素的数量m,接下来m行表示待删除元素值;下一行表示要查找元素的数量r,接下来r行表示待查找元素值。

输出
插入无输出,对于每个待删除元素,元素若在散列表中,删除即可,若不在则输出 ‘Delete Error’,注意单词间空格;执行完插入删除后,查找元素是否在散列表中,若在则在相应行输出True, 否则输出False。

#散列表,通过链地址法解决冲突
#链表结点类,有数据域和指针域
class Node:
    def __init__(self,data = None):
        self.data = data
        self.next = None

class Hashtable:
    def __init__(self,size):#这种写法构建哈希表时需提供哈希表长度
        #创建空列表作为哈希表,列表每个元素都是node类型
        self.data = [Node()] * size
        self.size = size
    #哈希函数使用除留余数法。数据除以哈希表长然后取余
    def hash_function(self,key,size):
        return key % size
    #向哈希表中插入数据,通过逐一插入构建哈希表
    def put(self,key):
        #求待插数据的哈希值
        hash_value = self.hash_function(key,self.size)
        #若链表中下标为哈希值的位置还没有被其他数据占据,就直接把待插数据(key)放到那个位置
        if self.data[hash_value].data == None:
            self.data[hash_value].data = key
        #如果已被占据,就在以【哈希表中下标为哈希值的位置】为起点的链表中顺次检查,直到检查到空位置
        else:
            #上面链表起点位置空的情况已经帮忙建立好了结点,把数据域改变成key就好了。
            #链表起点已被占据时,需要新建一个结点存储数据
            temp = Node(key)
            #p指向以【哈希表中下标为哈希值的位置】为起点的链表的头节点。
            p = self.data[hash_value]
            #向后逐个检查
            while p.next != None:
                p = p.next
            #现在存p已经指向了链表的末尾,p的next连接上temp即可
            p.next = temp
    #判断某值(key)是不是在该哈希表里的函数
    def get(self,key):
        #获得要判断元素的哈希值
        hash_value = self.hash_function(key,self.size)
        #相同哈希值的元素在哈希表相应位置链表中的存储没有规律
        #简单情况,该哈希值下的链表头等于key就说明找到
        if self.data[hash_value].data == key:
            return True
        #哈希值对应的链表头存储的不是key时
        else:
            #p存储链表头
            p = self.data[hash_value]
            #只要没有碰到key,也没有到链表末尾,就一直向后寻找
            while p != None and p.data != key:
                p = p.next
            #退出了上方循环后,还没有到链表的末尾,说明已找到
            if p != None and p.data == key:
                return True
        #整个链表都未找到,说明整个哈希表里没有存储key的节点
        return False
    #在哈希表中删除数据为key的节点
    def delete(self,key):
        #如果输入的key在这个哈希表中根本没有,返回错误
        if not self.get(key):
            return 'Delete Error'
        #否则,哈希表中有存储此数据的节点。先找该数据对应的哈希值。
        hash_value = self.hash_function(key,self.size)
        #和get函数完全类似。若哈希表中对应哈希值的链表的头部数据就和要删除的数据相符合,直接将该节点(链表头)数据域改变为none。
        #空间有浪费,但不影响插入查找。
        if self.data[hash_value].data == key:
            self.data[hash_value].data = None
        #否则,要删除的数据就在那个对应的链表中    
        else:
            #p先指向那个位置的链表的头节点
            p = self.data[hash_value]
            #pre储存该链表当前节点之前的节点。设置pre,为了删除目标后将它上一个节点和后一个节点连接。初始时p指向头,pre为空即可。
            pre = None
            #找到要删除的位置,每一步更新p和pre
            while p != None and p.data != key:
                pre = p
                p = p.next
            #如果到末尾仍未找到(这种情况也可以去掉)
            if p == None:
                return 'Delete Error'
            else:
                pre.next = p.next
#按照要求建表、插入、删除、查找。
n = int(input())
#建表
h = Hashtable(n)
lst = list(set(input().split()))
slst = [int(i) for i in lst]
for i in slst:
    h.put(i)
#插入
n =  int(input())
for i in range(n):
    tmp = int(input())
    h.put(tmp)
#删除
n = int(input())
for i in range(n):
    tmp = int(input())
    tmp1 = h.delete(tmp)
    if tmp1 == 'Delete Error':
        print('Delete Error')
#查找
n = int(input())
for i in range(n):
    tmp = int(input())
    print(h.get(tmp))

在这里插入图片描述

首先,根据装载因子和元素个数,可以计算出散列表的大小为 `table_size = 500 // 3 = 167`。 接下来,我们需要实现一个散列函数。这里我们采用除散列,即将关键字除以散列表大小取余数。代码如下: ```python def hash_func(key, table_size): return key % table_size ``` 然后,我们定义一个散列表类,其中包含插入查找删除操作。在插入操作中,如果发生冲突,我们使用解决。代码实现如下: ```python class HashTable: def __init__(self, table_size=167): self.table_size = table_size self.table = [None] * table_size def insert(self, key, value): index = hash_func(key, self.table_size) if self.table[index] is None: self.table[index] = LinkList() self.table[index].append((key, value)) def find(self, key): index = hash_func(key, self.table_size) if self.table[index] is not None: for node in self.table[index]: if node.data[0] == key: return node.data[1] return None def delete(self, key): index = hash_func(key, self.table_size) if self.table[index] is not None: for node in self.table[index]: if node.data[0] == key: self.table[index].remove(node) return True return False ``` 在这个散列表类中,我们使用了一个长度为 `table_size` 的列表来存储链表。每个元素是一个链表节点,其中包含一个键值对 `(key, value)`。在插入操作中,我们首先计算出关键字的散列值,然后将其插入到对应的链表中。如果链表不存在,则创建一个新的链表。在查找删除操作中,我们也需要计算出关键字的散列值,然后遍历对应的链表找到相应的节点。如果找到了,我们就可以返回或删除节点。 现在我们可以创建一个散列表对象,然后测试插入查找删除操作了。代码如下: ```python hash_table = HashTable() # 插入操作 hash_table.insert(1, 'a') hash_table.insert(2, 'b') hash_table.insert(3, 'c') hash_table.insert(4, 'd') hash_table.insert(5, 'e') # 查找操作 print(hash_table.find(3)) # 输出:c print(hash_table.find(6)) # 输出:None # 删除操作 hash_table.delete(4) print(hash_table.find(4)) # 输出:None ``` 在这个例子中,我们向散列表插入了5个元素,然后分别查找了关键字为3和6的节点,最后删除了关键字为4的节点。运行结果如下: ``` c None None ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值