[size=large]Suffix Array[/size]
最近在做模式匹配方面的东西,看了一些关于后缀数组的资料。后缀数组真的很巧妙很博大精深,在字符串方面的应用很广,基本可以应付绝大部分的字符串处理:文本匹配,文本压缩(bwt),文本索引等等。
后缀数组的资料很多啦,简单说说自己的理解吧
[size=medium]关于匹配[/size]
把字符串切成后缀(suffix),然后排序。由于是有序的,如果想匹配字符串,简单一点的方法是:二分搜索
ex:在字符串"atgc"查找模式"tg"
1.input:text="atgc",pattern="tg"
2.切后缀:suffix[0]="atgc",suffix[1]="tgc",suffix[2]="gc",suffix[3]="c"
3.排序:"augc" < "c" < "gc" < "tgc"
4.二分搜索:"tg"和"gc"比较,"tg" > "gc", "tg"和"tgc"比较,匹配,"tg"在suffix[1]被找到,也就是在text的下标1处匹配成功
上面这个是比较直观简单的方法,而事实上,由于后缀是排好序的,也就是说:具有相同前缀的后缀一定排在一起。如果模式和后缀i(suffix[i])的前k个字符相同,但是第k+1字符不同,导致匹配失败,如果按照二分思想,那么模式后会和suffix[i]比较大小,然后决定是以suffix[i]为起点还是为终点的区域进行搜索,下一次尝试匹配的点离suffix[i]比较远,而事实上答案应该离suffix[i]很近才对,因为和模式的前k个字符一样的后缀和suffix[i]后缀排在一起。
ex:在后缀aa,ab,ac,ad,ae,af,ag,af,ccccccca,cccccccbaa,ta,tb,tc,td,te,tf,tg搜索cccccccb。先尝试跟ccccccca,然后跟tc比,然后跟ta比,最后跟cccccccbaa,匹配成功,比了很多次,殊不知答案就在第一次比的ccccccca附近
如果要更快速的搜索到结果,有一个很好的数据结构叫后缀树,利用这棵树就可以避免刚才二分搜索的那种尴尬了,其实本质上这棵后缀树也是分治的思想,只不过这棵树不止二分,这棵树可以多分,当前节点有多少子树就可以多少分,然后选择最适合的子树往下搜索,这样就快很多了。
但是后缀树有一个缺点就是很费空间。那么能不能用后缀数组来实现这样的功能呢,当然是可以的,那就是增强后缀数组(enhanced suffix arrays)。增强后缀数组能模拟后缀树的大部分的结构,所谓增强后缀数组就是在后缀数组的基础上加了一些额外的信息,那就是child table。这个child table包括up,down,和next域,通过这些域就可以模拟后缀树的树形结构,请参考[url]http://veronika.platon.sk/projekty/Vyhladavanie_v_texte_referat.pdf[/url]。
[size=medium]关于构造[/size]
那么如何构造后缀数组呢,这个可以参考许智磊和罗穗骞论文,不过现在有出现了好多不同的构造算法,请参考[url]http://www.techfak.uni-bielefeld.de/~stoye/cpublications/alenex2005final.pdf[/url],这里面有一个不同算法的比较。当然这些算法比较高深,小弟不才,自认为肯定看不懂O(∩_∩)O~,所以也没去怎么看算法怎么去搞,所幸的是,有开源的代码可以参考[url]http://labs.carrotsearch.com/jsuffixarrays.html[/url],这个项目提供了很多的构造后缀数组的java源码,大家可以参考一下。
最近在做模式匹配方面的东西,看了一些关于后缀数组的资料。后缀数组真的很巧妙很博大精深,在字符串方面的应用很广,基本可以应付绝大部分的字符串处理:文本匹配,文本压缩(bwt),文本索引等等。
后缀数组的资料很多啦,简单说说自己的理解吧
[size=medium]关于匹配[/size]
把字符串切成后缀(suffix),然后排序。由于是有序的,如果想匹配字符串,简单一点的方法是:二分搜索
ex:在字符串"atgc"查找模式"tg"
1.input:text="atgc",pattern="tg"
2.切后缀:suffix[0]="atgc",suffix[1]="tgc",suffix[2]="gc",suffix[3]="c"
3.排序:"augc" < "c" < "gc" < "tgc"
4.二分搜索:"tg"和"gc"比较,"tg" > "gc", "tg"和"tgc"比较,匹配,"tg"在suffix[1]被找到,也就是在text的下标1处匹配成功
上面这个是比较直观简单的方法,而事实上,由于后缀是排好序的,也就是说:具有相同前缀的后缀一定排在一起。如果模式和后缀i(suffix[i])的前k个字符相同,但是第k+1字符不同,导致匹配失败,如果按照二分思想,那么模式后会和suffix[i]比较大小,然后决定是以suffix[i]为起点还是为终点的区域进行搜索,下一次尝试匹配的点离suffix[i]比较远,而事实上答案应该离suffix[i]很近才对,因为和模式的前k个字符一样的后缀和suffix[i]后缀排在一起。
ex:在后缀aa,ab,ac,ad,ae,af,ag,af,ccccccca,cccccccbaa,ta,tb,tc,td,te,tf,tg搜索cccccccb。先尝试跟ccccccca,然后跟tc比,然后跟ta比,最后跟cccccccbaa,匹配成功,比了很多次,殊不知答案就在第一次比的ccccccca附近
如果要更快速的搜索到结果,有一个很好的数据结构叫后缀树,利用这棵树就可以避免刚才二分搜索的那种尴尬了,其实本质上这棵后缀树也是分治的思想,只不过这棵树不止二分,这棵树可以多分,当前节点有多少子树就可以多少分,然后选择最适合的子树往下搜索,这样就快很多了。
但是后缀树有一个缺点就是很费空间。那么能不能用后缀数组来实现这样的功能呢,当然是可以的,那就是增强后缀数组(enhanced suffix arrays)。增强后缀数组能模拟后缀树的大部分的结构,所谓增强后缀数组就是在后缀数组的基础上加了一些额外的信息,那就是child table。这个child table包括up,down,和next域,通过这些域就可以模拟后缀树的树形结构,请参考[url]http://veronika.platon.sk/projekty/Vyhladavanie_v_texte_referat.pdf[/url]。
[size=medium]关于构造[/size]
那么如何构造后缀数组呢,这个可以参考许智磊和罗穗骞论文,不过现在有出现了好多不同的构造算法,请参考[url]http://www.techfak.uni-bielefeld.de/~stoye/cpublications/alenex2005final.pdf[/url],这里面有一个不同算法的比较。当然这些算法比较高深,小弟不才,自认为肯定看不懂O(∩_∩)O~,所以也没去怎么看算法怎么去搞,所幸的是,有开源的代码可以参考[url]http://labs.carrotsearch.com/jsuffixarrays.html[/url],这个项目提供了很多的构造后缀数组的java源码,大家可以参考一下。