直接寻址表
- 直接寻址表,定义了一个所有关键字的域集合U,根据这个U生成一个包含所有域值的列表T
- 直接寻址技术优点:
- 当数据量较小时,相对简单有效
- 直接寻址技术缺点:
- 当U很大时,建立列表T,所消耗的内存空间非常大
- 如果U非常大,而实际出现的key非常少,这样就对空间造成了极大的浪费
- 当关键字key不是数字的时候就无法处理了
hash(哈希)
- 基本概念:hash,也称作散列、杂凑或者哈希,是一种线性表的存储结构。哈希表由一个直接寻址表和一个哈希函数组成,哈希函数h()将元素的关键字k处理得到唯一的存储元素的位置信息。能把任意长度的输入,通过hash算法转化为固定长度的输出,是一种压缩映射。最大的特点就是从无法从结果推算出输入内容,所以称之为不可逆算法。本质上是通过哈希函数计算数据存储位置的数据结构。
- hash表示对直接寻址表的改进,具体的
- 构建大小为m的寻址表T,[0,1,2,3,……,m-1]
- 将关键字为k的元素,放置在T中的h(k)所指定的位置上
- h() 是哈希函数,将U中的key映射到寻址表T中
- 哈希特性:
- 过程不可逆,即拿到结果也不能反解出输入值是多少
- 计算速度极快
- 哈希表存在的问题:
- 哈希冲突
- 由于关键字的数量是无限的,而hash创建的寻址表T是有限的,所以必定会出现存储位置冲突或重复,即当h(k)和h(k1)的值相同时,两个值的存储位置是冲突的。
- 哈希冲突的解决方式:
- 方式一:开放寻址法,如果哈希函数返回的位置已经有值,则继续向后探寻新的位置来存储这个值。而继续向下探寻位置的方法有
- 线性探查,如果位置i被占用,则向下探查i+1,i+2 ……直至空位置
- 二次探查,如果位置i被占用,则依次探查i+1^2,i+2^2……直至空位置
- 二度哈希:有n个哈希函数,等使用第一个哈希函数h1,发生冲突时,依次尝试使用h2,h3……
- 方式二:拉链法,哈希表每个位置都链接一个链表,当冲突发生时,冲突的元素被加到该位置链表后面
- 方式一:开放寻址法,如果哈希函数返回的位置已经有值,则继续向后探寻新的位置来存储这个值。而继续向下探寻位置的方法有
- 哈希冲突
- 常见的哈希函数:
- 除法哈希: h(k)=k%m
- 乘法哈希:h(k) = floor(m*(A*key%1))
- 全域哈希:h(k) = ((a*key+b) mod p) mod m a,b =1,2,……p-1
- hash表的基本操作:
- insert(key,value) 插入键值对
- get(key) 根据键取值
- delete(key) 删除键值对
- 主要的应用方向:
- python等语言的字典、集合等数据类型就是基于hash实现的
- 密码,很多密码都是基于hash构造出来的
- 可以用于检测文件的一致性
- 用于数字签名
- MD5,SHA-1,SHA-2
- hash表的简单实现(拉链法,单链表)
-
View Code
1 """ 2 使用链表,实现hash。构建一个类似于集合的hash表 3 """ 4 class LinkList(object): 5 """ 6 对链表的进一步封装 7 """ 8 class Node(object): 9 """ 10 链表的节点类 11 """ 12 def __init__(self,item): 13 self.item = item 14 self.next = None 15 16 class LinkListIterator(object): 17 """ 18 将链表转为迭代器类 19 """ 20 def __init__(self,node): 21 self.node = node 22 23 def __next__(self): 24 if self.node: 25 cur_node = self.node 26 self.node = cur_node.next 27 return cur_node.item 28 else: 29 raise StopIteration 30 31 def __iter__(self): 32 return self 33 34 def __init__(self,iterable = None): 35 self.head = None 36 self.tail = None 37 if iterable: 38 self.extend(iterable) 39 40 def extend(self,iterable): 41 for obj in iterable: 42 self.append(obj) 43 44 def append(self,obj): 45 """ 46 使用尾插法,进行插入 47 :param obj: 48 :return: 49 """ 50 s = LinkList.Node(obj) # 链表节点创建 51 if not self.head: 52 self.head = s 53 self.tail = s 54 else: 55 self.tail.next = s 56 self.tail = s 57 58 def find(self,obj): 59 for val in self: 60 if val == obj: 61 return True 62 else: 63 return False 64 65 def __iter__(self): 66 return self.LinkListIterator(self.head) 67 68 def __repr__(self): 69 return "<<"+",".join(map(str,self)) +">>" 70 71 72 class HashTable(object): 73 """ 74 实现集合的部分功能,不可重复,可查询 75 """ 76 def __init__(self,size=101): 77 self.size = size 78 self.T = [LinkList() for _ in range(self.size)] # 创建寻址表 79 80 def h_func(self,k): 81 """ 82 哈希函数 83 :param k: 84 :return: 85 """ 86 return k%self.size 87 88 def find(self,k): 89 """ 90 根据给定的k值在现有的范围中查找是否存在 91 :param k: 92 :return: 93 """ 94 hash_num = self.h_func(k) # 获取给定数值的hash值 95 return self.T[hash_num].find(k) 96 97 98 def insert(self,k): 99 """ 100 实现插入前去重 101 :param k: 102 :return: 103 """ 104 if self.find(k): 105 print('element is exist') 106 else: 107 hash_num = self.h_func(k) # 获取插入的值的hash值 108 self.T[hash_num].append(k) 109 110 111 my_set = HashTable() 112 my_set.insert(1) 113 my_set.insert(2) 114 my_set.insert(102) 115 print(my_set.T) 116 print(my_set.find(2))
-