1. 哈希表的概念
哈希表:也叫做散列表。根据关键字和值(Key-Value)直接进行访问的数据结构。它通过关键字 key 和一个映射函数 Hash(key) 计算出对应的值 value,然后把键值对映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数(散列函数),用于存放记录的数组叫做 哈希表(散列表)。
2. 哈希函数
将哈希表中元素的关键键值映射为元素存储位置的函数。如h(k) = k % 10,设置10个长度空间,模相同的放在同一个下标空间
哈希函数的特征:
1. 哈希函数应该易于计算,并且尽量使计算出来的索引值均匀分布,这能减少哈希冲突
2. 哈希函数计算得到的哈希值是一个固定长度的输出值
3. 如果Hash(key1) 不等于 Hash(key2),那么 key1、key2 一定不相等
4. 如果 Hash(key1) 等于 Hash(key2),那么 key1、key2 可能相等,也可能不相等(会发生哈希碰撞)
3. 哈希冲突
1. 概念:不同的关键字通过同一个哈希函数可能得到同一哈希地址,即 key1 ≠ key2,而 Hash(key1) = Hash(key2),这种现象称为哈希冲突。
2. 解决哈希冲突的方法
1. 开发地址法:如果哈希函数返回的地方有值,则向后寻找新的空位置来存储该值
1. 线性探查法:如果H(i) 被占用,则探查i+1,i+2.....
2. 二次探查法:如果H(i) 被占用,则探查i+1²,i-1²,i+2²,i-2²......
3. 二度哈希法:使用N个哈希函数,当使用第一个哈希函数发生冲突时,尝试使用其他的H2,H3等哈希函数
2. 拉链法:将具有相同哈希地址的元素(或记录)存储在同一个线性链表中。
4. 实现哈希表的拉链插入法
# 链表 class LinkList: # 构建节点类 class Node: def __init__(self, item=None): self.item = item self.next = None # 构建迭代器,因为容器类对象不可迭代 class LinkListIterator: def __init__(self, node): self.node = node # 迭代器__iter__ def __iter__(self): return self # 迭代器__next__ def __next__(self): if self.node is not None: cur_node = self.node self.node = cur_node.next return cur_node.item else: raise StopIteration # 对象实例化 def __init__(self, iterator=None): self.head = None self.tail = None # 判断调用类的时候如果参数是一个可迭代对象,则循环插入链表 if iterator: self.extend(iterator) # 插入元素 def append(self, val): node = LinkList.Node(val) # 判断链表是否为空,为空则head和tail都指向插入元素 if not self.head: self.head = node self.tail = node # 不为空,则指针的next指向插入元素,并且更新指针尾插入元素 else: self.tail.next = node self.tail = node # 插入可迭代列表函数 我自己不会想到这个,默认调用的时候不传参数 def extend(self, iterator): for i in iterator: self.append(i) # 查找元素 def find_LinkList(self, val): for n in self: if n == val: return True else: return False # 链对象可迭代化 def __iter__(self, iterator=None): return self.LinkListIterator(self.head) # 输出字符串化,内置函数 def __repr__(self): return "<"+",".join(map(str, self))+">" # 类似于集合的结构 class HashTable: def __init__(self, size=100): self.size = size self.table = [LinkList() for i in range(self.size)] # 建立空链表 # 哈希函数,确定存储下标位置 def hash_function(self, k): return k % self.size # 查找元素 def find_HashTable(self, val): i = self.hash_function(val) # i为哈希函数返回值,即指向哪一个链表 return self.table[i].find_LinkList(val) # 在指定i的链表中调用find_LinkList函数查找插入元素是否存在该链表中 # 插入元素 def insert(self, val): i = self.hash_function(val) # 获取插入链表位置下标i if self.find_HashTable(val): # 查找插入元素是否存在 print("重复插入!") else: self.table[i].append(val) # 不存在则调用append函数
5. 扩展小知识
python中的集合和字典本质上就是哈希表,集合要求元素不能重复,字典要求键唯一不可变,是可以通过哈希函数计算出唯一地址的,键可以是数字、字符串和元组,但是元素内的元素要规定不能是列表,字典,集合等可变的对象。字典通过将键作为参数进行转换,得到唯一的地址,然后将值存放在该地址中,这是为什么当键相同的时候,值会被覆盖掉的原因
Python 的哈希算法对相同的值计算得到的结果是一样的,也就是说 314 和 314.0 的值相同,他们被认为是相同的键(Key)
标签:__,node,函数,self,哈希,def From: https://www.cnblogs.com/chf333/p/17036858.html