直接寻址表
- 直接寻址表,定义了一个所有关键字的域集合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表的简单实现(拉链法,单链表)
-
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))
-
-
Python中hash的使用,通过调用hashlib模块实现
-
通过hashlib调用不同的hash函数,实现不同数据的不同处理。
-
实例化hash对象,hash_obj = hash.hash函数类型() ,实例化过程中,可以通过添加参数,实现加盐操作
-
常见的hash函数类型有md5,sha1,sha224,sha256,sha384,sha512等
- hash_obj.update( 处理内容 ) 注意,需要进行处理的内容必须是bytes类型
- hash_obj.digest() ,返回当前已处理内容的hash值(内容摘要),返回值二进制数据
- hash_obj.hexdigest(),返回当前已处理内容的hash值(内容摘要),返回值是十六进制数据
-
-
MD5
- 曾是密码学中常用的hash函数
- 主要特点:
- 同样的消息MD5相同
- 可以快速计算出任意长度的消息的MD5
- 除非暴力美剧,否则基本不能从哈希值反推出消息本身
- 两条消息之间,即使是只有微笑差别,其MD5应该是完全不同,不相关的
- 在有限时间内,无法人工构建出MD5值相同的两个不同的信息
- 应用举例:
- 验证文件,例如是否是相同的文件,上传下载文件的完整性、云盘秒传等
SHA-1,SHA-2
- SHA-1和MD5都是曾经在密码学上经常用到的hash算法,但是目前,较为常用的是SHA-2
- SHA-2算法包含,SHA-224,SHA-256,SHA-384,SHA-512,SHA-512/224,SHA-512/256等算法,穷224,256,384与512代表的是哈希值的长度
贪心算法
- 贪心算法也叫做贪婪算法,基本思路是在求解过程中,只考虑当前步骤的最优选择,不从整体上进行考虑。贪心算法重点是放在了求解局部最优解,但是,很多情况下,贪心算法执行出来的结果也是整体上的最优解。
- 特点:解决的是部分最优化问题
- 实例:
- 找零问题
- 背包问题
- 数字拼接问题
- 活动选择问题
动态规划
- 动态规划关键点是找到关系到最优子结构的递推式,最优子结构
- 最优子结构,如果可以将最优解的规模为n的问题,划分为规模更小的最优解问题,这些子问题是独立求解的,通过组合子问题的最优解可以得到原整体问题的最优解,就可以称之为最优子结构。
- 动态规划特征
- 最优子结构,最优解问题中,原问题的最优解中涉及到多个子问题
- 重叠子问题
- 实例:
- 钢条切割问题
- 最长公共子序列
- 子序列与子串,子序列是在某个序列中删除若干元素后得到的序列,与子串的区别是,子序列的元素在原序列中,不一定是相邻的,而子串的元素在原序列中一定是相邻的
- 应用场景
- 字符串相似度(模糊查询)
- 内容相似比对
- 基因测序等