Skip to content

Commit a1497a9

Browse files
committed
1 parent 98ed218 commit a1497a9

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
双数组Trie(Double-ArrayTrie)是trie树的一个简单而有效的实现,由两个整数数组构成,一个是base[],另一个是check[]。设数组下标为i,如果base[i],check[i]均为0,表示该位置为空。如果base[i]为负值,表示该状态为词语。Check[i]表示该状态的前一状态,t=base[i]+a,check[t]=i
2+
目录
3+
4+
1 简介
5+
2 基本构造
6+
7+
简介
8+
编辑
9+
Trie树是搜索树的一种,来自英文单词"Retrieval"的简写,可以建立有效的数据检索组织结构,是中文匹配分词算法中词典的一种常见实现。它本质上是一个确定的有限状态自动机(DFA),每个节点代表自动机的一个状态。在词典中这种状态包括"词前缀","已成词"等。
10+
基本构造
11+
编辑
12+
下面举例来说明用双数组Trie(Double-ArrayTrie)构造分词算法词典的过程。假定词表中只有“啊,阿根廷,阿胶,阿拉伯,阿拉伯人,埃及”这几个词。
13+
  首先对词表中所有出现的10个汉字进行编码:啊-1,阿-2,唉-3,根-4,胶-5,拉-6,及-7,廷-8,伯-9,人-10。。对于每一个汉字,需要确定一个base值,使得对于所有以该汉字开头的词,在双数组中都能放下。例如,现在要确定“阿”字的base值,假设以“阿”开头的词的第二个字序列码依次为a1,a2,a3……an,我们必须找到一个值i,使得base[i+a1],check[i+a1],base[i+a2],check[i+a2]……base[i+an],check[i+an]均为0。一旦找到了这个i,“阿”的base值就确定为i。用这种方法构建双数组Trie(Double-ArrayTrie),经过四次遍历,将所有的词语放入双数组中,然后还要遍历一遍词表,修改base值。因为我们用负的base值表示该位置为词语。如果状态i对应某一个词,而且Base=0,那么令Base=(-1)*i,如果Base的值不是0,那么令Base=(-1)*Base。得到双数组如下:
14+
  下标1234567891011121314
15+
Base-1 4 4 0 0 0 0 4 -9 4 -11 -12 -4 -14
16+
Check000000022238 10 13
17+
词缀啊阿埃阿根阿胶阿拉埃及阿根廷阿拉伯阿拉伯人
18+
用上述方法生成的双数组,将“啊”,“阿”,“埃”,“阿根”,“阿拉”,“阿胶”,“埃及”,“阿拉伯”,“阿拉伯人”,“阿根廷”均视为状态。每个状态均对应于数组的一个下标。例如设“阿根”的下标为i=8,那么check的内容是“阿”的下标,而base是“阿根廷”的下标的基值。“廷”的序列码为x=8,那么“阿根廷”的下标为base+x=base[8]+8=12。
19+
基本操作与存在问题
20+
1,查询
21+
trie树的查询过程其实就是一个DFA的状态转移过程,在双数组中实现起来比较简单:只需按照状态标志进行状态转移即可.例如查询“阿根廷”,先根据“阿”的序列码b=2,找到状态“阿”的下标2,再根据“根”的序列码d=4找到“阿根”的下标base+d=8,同时根据check[base+d]=b,表明“阿根”是某个词的一部分,可以继续查询。然后再找到状态“阿根廷”。它的下标为y=12,此时base[y]
22+
简单优化
23+
优化的基本思路是将双数组trie树构建为一种动态检索方法,从而解决插入和删除所存在的问题。
24+
1,插入优化
25+
在插入需要确定新的BASE值时,我们是只需要遍历空状态的。非空状态的出现意味着某个BASE值尝试的打败,我们可以完全不必理会。所以,我们可以对所有的空状态构建一个序列,在确定BASE值时只需要扫描该序列即可。
26+
对双数组中的空状态的递增结点r1,r2,…,rm,我们可以这样构建这一空序列:
27+
CHECK[ri]=−ri+1(1im−1),
28+
CHECK[rm]=−(DA_SIZE+1)
29+
其中r1=E_HEAD,为第一个空值状态对应的索引点。这样我们在确定BASE值时只需扫描这一序列即可。这样就省去了对非空状态的访问时间。
30+
这种方法在空状态并不太多的情况下可以很大程度的提高插入速度。
31+
2,删除优化
32+
1)无用结点
33+
对于删除叶结点时产生的无用结点,可以通过依次判断将它们置为空,使得可在插入新词时得以重用。例如,如果我们删除了上例中的"阿根廷",可以看到"阿根"这一状态没有子状态,因此也可将它置为空。而"阿"这一状态不能置空,因为它还有两个子状态。
34+
2)数组长度的压缩
35+
在删除了一个状态后,数组末尾可能出现的连续空状态我们是可以直接删除的。另外我们还可以重新为最大非空索引点的状态重新确定BASE值,因为它有可能已经由于删除的进行而变小。这们我们可能又得以删除一些空值状态。

0 commit comments

Comments
 (0)