Word文档中的单词拼写检查功能是如何实现的
什么是散列表
散列表用的是数组支持按照下标随机访问数据的时候,时间复杂度为 O(1)的特性。我们通过散列函数将元素的键值映射为下标,然后将元素存储在数组中对应下标的位置。查找元素的时候,通过散列函数将键值转化为数组下标,然后从数组中取出对应下标位置上的元素。
什么是散列思想
某校举办运动会,共有 100 名运动员,编号从 0 到 99。如果我们将运动员的编号与数组的下标一一对应,并把运动员的信息对号入座放入编号值对应下标值的数组中,那么获取运动员信息的时候,就可以依据编号随机访问数组中的元素,得到想要的信息,时间复杂度 O(1)。
依旧是上面的例子,但是这次运动员的编号是年级编号 + 班级编号 + 顺序编号。这次,我们就需要借助一个函数对运动员的编号进行转化:去除年级编号,去除班级编号,保留顺序编号。通过函数的转化,使得运动员编号依旧与数组下标一一对应。此时,查找运动员信息的时间复杂度依旧是 O(1)。
通过上述两个例子,已经体现了散列思想。运动员的编号叫做键(key)或者编号转化编号的函数叫散列函数(哈希函数,Hash函数),通过哈希函数转化得到的值叫散列值(哈希值,Hash值)。
对于散列函数有一下三点要求:
- 通过散列函数得到的散列值是一个非负整数。(数组下标不支持非负整数)
- 如果 key1 = key2 那么 hash(key1) = hash(key2)。(键值相同,那计算出来的散列值也应该相等)
- 如果 key1 != key2 那么 hash(key1) != hash(key2)。(这一点做到比较难,即便是MD5,SHA,CRC等哈希算法也不能保证不同的值对应的散列值不同,这就引发除了散列冲突。)
散列冲突的解决
1:开放寻址。如果出现了散列冲突,那就那就重新探测一个空闲的位置,将数据插入。探测方法有:
线性探测,发现冲突后,继续往后找,直到找到空闲位置。
二次探测,与线性探测相似,只是步长变为原来的二次方。
双重散列,使用两个散列函数,第一个函数冲突后,采用第二个函数。
2:链表法。散列表中,每个数组的元素就是一个头结点,后面跟着一个链表。当散列冲突后,就将元素直接放入链表后面。
Word文档中的单词拼写检查功能是如何实现的
将所有的单词存入散列表中,每次发现单词拼写的时候,去散列表查找,查不到就提示单词拼写错误。
总结
针对散列冲突的元素,如何在获取的时候准确的获取正确的对象呢?查找对象的时候,首先根据散列值进行查找,如果查找到多个元素,那再进行全量对比,判断查找到的元素是不是我们想要的元素。
本文创作灵感来源于 极客时间 王争老师的《数据结构与算法之美》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。
初入算法学习,必是步履蹒跚,一路磕磕绊绊跌跌撞撞。看不懂别慌,也别忙着总结,先读五遍文章先,无他,唯手熟尔~
与诸君共勉