在我的Android应用中,我想要一个带自动完成功能的输入字段。项目数量约为300000.最佳解决方案似乎是将项目放入文件(在SD卡上),每行一个项目,每行将具有相同的字符数,以便我可以寻找特定的行号。如果用户在文本字段中输入内容,我将二进制搜索(通过RandomAccessFile)文件并显示建议。
我希望自动完成速度超快(理想情况下不到100毫秒,但我想这是不可能的),我可以做些什么优化?
更新1: 我将使用空格将用户输入转换为小写英文字符(a-z)。因此'A / b'将转换为'a b',然后进行搜索。
Uodate 2: 我现在意识到我需要额外的东西 - 搜索单词起始子串。
答案 0 :(得分:6)
为什么不使用SQLite数据库而不是文本文件? 在你的情况下,我认为你不能比便携式数据库更快地做任何事情。
答案 1 :(得分:6)
您所寻找的是一种TRIE
http://forums.sun.com/thread.jspa?threadID=5295936
在计算机科学中,trie或前缀树是一种有序树数据结构,用于存储关键数组,其中键通常是字符串。与二叉搜索树不同,树中没有节点存储与该节点关联的密钥;相反,它在树中的位置显示了与之关联的键。节点的所有后代都具有与该节点关联的字符串的公共前缀,并且根与空字符串相关联。值通常不与每个节点相关联,只与叶子和一些与感兴趣的键对应的内部节点相关联。
答案 2 :(得分:3)
Trie是一个明显的答案,已经提到了,但另外tr13 library可能就是你所看到的。它是垃圾收集器友好(单个原始字节数组或字节缓冲区),紧凑,绝对足够快你的情况。密钥通常是UTF-8字符串,但可以是任何字节序列。同样的值,尽管还有可变长度的int(vints)的替代方法,用于获得非常紧凑的String-to-int查找(特别是对于小的int组)。
答案 3 :(得分:2)
一种策略可能是使用RandomAccessFile
和二进制搜索缩小结果范围。然后,一旦可能的条目足够小,将该部分加载到内存中,并进行内存搜索。
这会提高性能,因为当人们输入时,您可以快速搜索已加载到内存中的文件的相同部分。
答案 4 :(得分:1)
查看http://en.wikipedia.org/wiki/Binary_search_algorithm
在排序文件中你有一个二进制搜索最坏情况的O(log(n)) 下一个最好的事情是某种哈希映射,即O(1),尽管这对于部分单词来说很复杂,并且会产生一个巨大的映射表。
答案 5 :(得分:1)
提前将您的可能性预处理到搜索树中,而不是在运行时进行。
答案 6 :(得分:1)
我建议您查看是否可以使用标准库来实现此目的。也许apache lucene可用于Android手机。如果是这样,你可以建立一个索引(单词前缀 - > android sql lite中单词的id)。这是a discussion about a kind of algorithm lucene is using。
答案 7 :(得分:1)
单行每字存储的一个主要问题是,在常量时间内没有随机访问行(访问行X包含计算从文件开头开始的X行换行符)所以你的二进制搜索会受到影响。
在此特定(自动完成)情况下您需要的是Prefix Tree或其变体(将多个节点合并为一个,或将小于特定大小的子树转换为普通的旧排序列表话)。
答案 8 :(得分:1)
100毫秒是充足的时间。最重要的担心是显示更新,我想。
如果您想要避开实际的数据库,除了主文件之外,这对于简单的索引文件也很容易。
您可以将每个32条记录左右的字符串和文件偏移量的前N个字节(4个可能?)存储在索引中的主文件中,并对其进行二进制搜索。然后,您可以在二进制搜索非常接近之后线性搜索最多32条记录。
根据您的平均字符串长度和媒体上单个读取的大小,您可以将索引频率从32条记录调整到任何有意义的记录。如果你有512字节的文件系统读取和8字节的平均字符串,那么你每64条记录都要做一个索引,等等。每个最小磁盘读取大小有多个索引记录没什么意义。
可以轻松生成索引文件,然后您可以使用简单的文本编辑器管理主文件。
答案 9 :(得分:1)
旧线程,但这是你需要的: Stringsearch library
我将它用于我的应用程序'Wordlist Pro'for Android,它非常快。
答案 10 :(得分:0)
我也可以这样做(下面是预处理文件):
aa - line 1
ab - line 17
.
.
zz - line 299819
如果用户输入以aa开头的内容,我会阅读第1 - 17行并按顺序搜索