Skip to content

哈希表工作原理与应用学习笔记 #28

Description

@boji123

近日遇到了青阳大神,和他聊起了微软研究院的面试。我没去试试还是有点后悔,不过机会总是留给有准备的人,建议大家平时多多学习算法吧,leetcode是个很好的平台。青阳谈到了哈希表,我觉得这十分有趣 / 我孤陋寡闻,因此特地学习了一下并写了这篇笔记。

哈希表即散列表(hash=散列),是一种提供了某种表映射关系的数据结构,哈希表算法则是一种以空间为代价换取时间的算法,在以前存储空间紧张的时候,哈希表算法难以进行,而随着现在内存空间越来越大,哈希表被越来越广泛地应用。特别地,哈希表算法尤其受到ACM(国际大学生程序设计竞赛)的欢迎,因为它具有极其优秀的效率,相比于队列O(n)的查找时间,他只需要O(1)就可以定位内存。

哈希表的原理。首先我们需要定义一种映射关系,例如从字符串到整形数据的映射(MD5也是一种映射),这种映射通常是稀疏的(并不是所有的字符串都是有意义的单词 / 频繁出现)因此,对于一对一的映射,映射后的整形也是稀疏的,为了提高空间利用率,我们对映射后的数据求余,把整形限制在一个区间内,如果这个区间足够大,那么可以认为不存在冲突。如果我们把整形数据作为内存数组的下标来寻址、访问内存空间,那么就实现了从字符串到内存地址的映射。假设我们维护的是一个结构类型,那么我们可以根据指针找回原字符串,实现双向的映射。

一些待解决的问题。由于哈希表做的是一种求余后的映射,所以必然会有许多地址从未被访问、有许多字符串具有相同的哈希值访问相同的地址,产生冲突。由于哈希表是一种以空间换时间的算法,所以空间浪费是可以牺牲的,而对于冲突的问题,我们可以在产生冲突后额外维护一个链表,在访问到内存后继续做一个小的链表查找。由于当内存大小足够大时,冲突是小概率事件,他不会对整个代码的运行效率有多少影响。

哈希表的应用。哈希表最优秀的地方在于其搜索时间,而缺点在于其实现复杂度,因此特别适用于需要巨量搜索的场合,例如微软面试中提到的一个题,假设电脑中所有文件都是文章,里面含有大量的英文单词,要求统计英文单词的出现频率(这里把无关的部分省略了)。那么我们就可以维护一个哈希表,然后每得到一个单词,就进行一次映射(哈希、求余),并把访问的地址里的数据加一。
(例:mapInt=hash(charArr)%10000;buff[mapInt]++)
最后我们再遍历哈希表,根据结构指针找回原来的字符串,然后再输出对应的频率即可(哈希映射后顺序会被打乱,如果需要按字典序输出,需要另外排序)。

设n为单词总量相对于队列O(n^2)、字典树O(nlogn)的复杂度,哈希表只有O(n)的复杂度。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions