双数组trie

来源:互联网 发布:java中空格怎么表示 编辑:程序博客网 时间:2024/05/17 23:31
1.概念:双数组的本质实际上就是一个有限状态的自动机。它能根据输入的字符转移到下一状态,最终到达终止状态。
2.用处:能够用o(n)的时间复杂度进行字符串识别,缺点是占用较多的内存,存储数组是一个稀疏数组。
2.双数组示意图

                          双数组trie的实现
                                            图一:双数组示意图
实例图说明:方框表示接受方框中的字符后到达的状态,椭圆表示终止状态。
可识别的字符串包括:北大荒,北大荒蜂蜜,北郊,程序员,潘丽芳程序员,潘丽芳

双数组使用两个数组表示:base数组,check数组,

双数组trie的实现
如果状态s接受字符c输入转化到状态t,这双数组必须满足
next[base[s]+c] = t;
check[base[s]+c] = s

上面的示意图用base,check数组存储得到下面的数组示意图
base_index: 0    1    7     10    15     16    17    19    20   21     22    24   25   27  28   33 base_con:        13   19    13     13    -16   -17   -19   25   13    -22    13  -13   13  -28  19
check_con:       0    0      0     1      15    1     21    25   16     27    10   24   7   33  20
字符串           北   程    潘   北大   北大荒 北郊 北大荒蜂蜜  北大荒蜂程序员潘丽潘丽芳 程序

北:1   大:2    荒:3  郊:4  蜂:5   蜜:6   程:7  序:8   员:9  潘:10 丽:11  芳:12

因为有12个不同的字符,所有我选取base[s] = 13;
北大荒的构造过程:北的index=1,并且base[s] = 13;所以base[1] = 13,check[1] = 0(北的前面是初始状态)
大的index=2.所以base[base[1]+2]=15,所以base[15]=13,check[15]=1(大的前面是北所在的index),
荒的index=3,所以base[base[15]+3]=16,所以base[16]=13,check[16]=15,但是由于‘荒’就一个结束状态。所以base[16] = -1*base[16];便于识别结束状态
程序员的构造过程:程的index=7,base[7]=13,check[7]=0;
序的index=8,base[base[7]+8]=21,base[21]!=0发生碰撞,调整base[s] = 13+6=19,所有base[7]=19,base[base[7]+8]=27, base[27]=13 check[27]=7,
员的index=9,base[base[27]+9]=22,员是结束状态,所以base[22]=-22,check[22]=27
几点感想:
base[s]的选举:根据自己的需要灵活选取,过大可能会造成base数组过于稀疏,过小可能会造成碰撞较多。
碰撞:指执行next[base[s]+c] = t后,base[base[s]+c]不为空,这是需要重新选取base[s],我选取的base[s] = base[s] +6
当发生碰撞时,要选择合适的base[s]使得以这个状态为当前状态的所有下一状态都能找到base中的空位子。比如北大荒,北郊,当输入'郊'以后到达的位置如果遇到碰撞,重新选取base[s],需要保证在新的base[i]下输入'大'到达的位置也为空。在最开始选择base[s]无法知道是否会产生碰撞,只有在发生碰撞时调整base[s],保证所有的输入c,base[base[s]+c]都为空。
base[i] < 0:比如“荒”是结束状态,但它同时是北大荒蜂蜜的中间状态,在寻找下一个位置时base[s] = 0-base[s]
北大荒和北大荒蜂蜜同时出现时,北大荒蜂蜜首先被识别。
我所实现的数据结构将词条插入看做词条增加。
实现的数据结构和可能有多种,对应有相应的算法,但算法思想大致如上。
按照构造算法即可推出查询算法。
0 0
原创粉丝点击