在数组和链表之上,还可以构建更复杂的数据结构,比如散列表、队列和栈。
定义
散列表是 数组 和 散列函数 结合而成的一种数据结构(其实也包括 链表 )。数组和链表都直接映射到内存,但散列表更复杂,使用散列函数来确定元素的储存位置。 散列表也被成为字典、散列映射、映射和关联数组。python中的dict()
应用
- 模拟映射关系,快速查找
- 防止重复
- 缓存
散列表的内部原理简介
- 散列表的基本思想是:
- 先分配一个大的数组空间,数组每个元素是一个链表的头
- 添加时,我们可以根据散列函数计算出一个key(可以是哈希值),这个key就是数组的位置,所以我们可以快速定位到元素的位置和链表,添加这个数据到链表。
- 查找时,同理,我们根据散列函数计算出key,快速找到数组和链表中的位置。
- 散列函数(也叫哈希算法): 简单说,就是把任意长度的输入,通过散列函数,压缩为某一固定长度的输出。Hash算法没有一个固定的公式,只要符合散列思想的算法都可以被称为是Hash算法。散列函数有这几个特点:
- 总是将相同的输入映射到相同的索引。
- 倾向于将不同的输入映射到不同的索引。(但无法绝对保证)
- 散列函数知道数组有多大,因此只返回有效索引
-
冲突(collision): 就是散列函数把不同的输入,计算成了同样的值。哈希冲突无法避免,所以有了需要链表的使用。但是,多个数据放入链表会导致效率太低。所以要尽量找一个更均匀分配的散列函数,减少冲突,提升效率。
-
散列函数的选择: 考虑两个因素:
- 填装因子 填装因子 = 已包含的元素数 / 散列表总位置。填装因子增大,意味着冲突的可能性升高,当填装因子>1时,一定发生冲突。所以一旦填装因子增大,就需要再散列表中添加位置,这叫做 resizing(调整长度)。一般以0.7位resizing的阈值。
- 良好的散列函数 良好的散列函数让数组中的值均匀分布
常用hash算法:取余, SHA, MD5, bcrypt
其他数据结构(待总结)
- 栈: 先进后出 函数递归 深度优先搜索
- 队列 广度优先搜索 消息队列
- 图的模型 二叉树,多叉树,有向图,无向图