存储大型词典的方法,内存占用量小+快速查找(在Android上)

我正在开发一个Android文字游戏应用程序,需要一个大型(约250,000个单词的字典)可用。我需要:

  • 相当快的查找速度,例如恒定时间更好,有时需要每秒进行200次查找以解决单词难题,也许在0.2秒内进行20次查找以检查用户刚刚拼写的单词。

编辑:查找通常会询问“在字典中吗?我也想在单词中支持最多两个通配符,但是通过生成通配符可能具有的所有可能的字母并检查生成的单词(即26 * 26查找具有两个通配符的单词)这很容易。

  • 由于它是一个移动应用程序,因此使用尽可能少的内存并且只需要少量的字典数据初始下载是重中之重。

我的第一次天真尝试使用了Java的HashMap类,这导致了内存不足异常。我已经考虑过使用Android上可用的SQL lite数据库,但这似乎有点过分了。

做我需要的事情的好方法是什么?


答案 1

您也可以通过更卑微的方法实现目标...如果这是一个文字游戏,那么我怀疑你正在处理27个字母的字母表。因此,假设字母表不超过32个字母,即每个字母5位。您可以使用5位/字母的琐碎编码将12个字母(12 x 5 = 60位)塞入单个Java长。

这意味着,实际上,如果你的单词长度不超过12个字母/单词,你可以把你的字典表示为一组Java长。如果你有250,000个单词,这个集合的简单表示为单个,排序的长数组应该需要250,000字x 8字节/字= 2,000,000〜2MB内存。然后通过二进制搜索进行查找,考虑到数据集的小尺寸,这应该非常快(少于20个比较,因为2 ^ 20将您带到100万以上)。

如果你的单词比12个字母长,那么我会将>12个字母的单词存储在另一个数组中,其中1个单词将以明显的方式由2个串联的Java长整车表示。

注意:这之所以有效,并且可能比trie更节省空间,并且至少实现起来非常简单,是因为字典是恒定的...如果需要修改数据集,搜索树是好的,但是如果数据集是常量,则通常可以使用简单的二进制搜索来运行一种方法。


答案 2

我假设你想检查给定的单词是否属于字典。

看看绽放过滤器

布隆过滤器可以执行“X是否属于预定义集”类型的查询,具有非常小的存储要求。如果查询的答案是肯定的,则错误的可能性很小(且可调整),如果查询的答案是否定的,则答案保证是正确的。

根据维基百科文章,您的字典可能需要不到4 MB的空间,其中包含250 000个单词,错误概率为1%。

如果单词实际包含在字典中,则 bloom 筛选器将正确回答“在字典中”。如果字典中没有单词,bloom过滤器可能会以一些小概率错误地给出“在字典中”的答案。