算法有趣的地方在于,能够用不一样的方式处理同一个问题,而且总有更好的方法。好比拼写检查。html
拼写检查大致是这样的,给出一个字典文件,给出一个比对文件。比对文件里的单词,若是某个单词不在字典文件里的话,就认为拼写错误。要作的就是找出比对文件里全部拼写错误的单词。git
最直观的方法,就讲文件里的单词一一同字典里的单词作比较,若是不在字典里,就输出。最简单,也最费时。github
假设字典文件一共有nd个字符,用于比对的文件有nt字符,复杂度则为O(nd * nt)。算法
具体实现数组
咱们看一下运行速度,测试用的字典里大约有14万个单词,用做比对的文件大约有12万个单词。
用时将近3分钟。显然速度太慢,须要优化。ruby
咱们知道,若是给出的单词以a开头,那么字典里以其余字母开头单词,就不须要咱们作比较了。就比如二叉树查找,每次查找,老是能够丢掉不符合要求的那一半。
收到二叉树的启发,咱们可使用一种叫作Trie的多叉树来实现。函数
假设字典里有ab, ac, c, d这四个单词,生成的trie会是以下形状(t一、t2只是表述,方便作讨论):post
root(t1) / \ \ a(t2) c(t3) d(t4) / \ b(t5) c(t6)
作检查的时候,须要从跟节点,一级一级的向下找。
假设咱们查找"ad",根节点的子节点t2的值就是a,第一个字母匹配成功了。咱们再匹配第二个字节'd',t2的子树里,没有'd'这个字母,匹配失败。则"ad"为一个错误的拼写。
只有当咱们匹配了单词的每个字母,而且最后一个字母是结尾字母,那么这个单词才是在字典中存在的。测试
具体实现优化
使用一样输入只花了不到1.3秒的时间,快了上百倍。
拼写查找,要求的是插入和查找速度快,Hash Table恰好符合要求。
一样的数据,只用了0.14秒,比trie的实现快了将近10倍。
具体实现
Hash Table 从速度上来讲,已是极限了,看起来是最适合的算法。但Bloom Filter某种程度上更合适!
Bloom Filter相对于Hash Table来讲,最大的优点就是,Bloom Filter不须要存完整的key(好比单词)。
Bloom Filter将一组key(好比单词)经过多个哈希方程映射到一个数组内,并能够根据这个数组来判断这个单词是否已经被插入了。
算法的大致思路以下:
初始化一个n个bit的数组arr,插入某个值时,咱们经过哈希方程,获得对应的index,将数组这个位置设为1.
假设咱们使用2个哈希方程h1, h2,咱们会获得两个index(多是1个),咱们就将数组的这两个位置设为1。
查找的时候,用全部的哈希方程,获得对应的index,而后检查数组在这些位置上,是否均为1,若是均为1,则认为这个值被插入过。
伪代码以下:
require 'bitarray' class BloomFilter attr_accessor :arr def initialize self.arr = BitArray.new(n) end def insert(key) arr[h1(key)] = 1 arr[h2(key)] = 1 end def include?(key) arr[h1(key)] == 1 && arr[h2(key)] = 1 end # BloomFilter会有多个哈希函数,2个只是为了说明算法的工做原理。 def h1(key) # xxx end def h2(key) # xxx end end
Bloom Filter虽然大大的节省了空间,但却有必定的几率出错(false positive),这种错误是,当查找时,一个值没有被插入,但却被误认为是插入过了。这是由于,哈希方程会产生冲突(collision)。
能够经过更长的数组和更多的哈希方程来解决这个问题,同事空间实用也不多,因此这是个颇有用的算法。
Bloom Filter还有一个弊端,就是不能作删除操做。不过能够经过给每一位加上个counter来解决,就是所谓的Counting Bloom Filter,具体看看这篇文章,就不详述了。
一样的输入,须要0.11秒。
SpellChecker user system total real brute_force 162.660000 1.560000 164.220000 (168.961906) by_trie 1.160000 0.100000 1.260000 ( 1.305419) by_hash_table 0.140000 0.000000 0.140000 ( 0.145828) by_bloom_filter 0.100000 0.010000 0.110000 ( 0.108583)
Problem Set 5: Mispellings
Bloom Filters: Heuristic Analysis
Bloom Filter概念和原理
A Look Into Bloom Filters with Ruby