所以我有一个单词列表(整个英语词典)。
对于单词匹配游戏,当玩家移动一个棋子时,我需要检查整个词典,看看玩家所做的单词是否存在于词典中。我需要尽快做到这一点。简单地遍历字典太慢了。
AS3中最快的算法是搜索匹配的长列表,我应该使用哪种数据类型? (即数组,对象,字典等)
答案 0 :(得分:5)
我首先使用的是Object,这是一个哈希表(至少是存储方式)。
因此,对于列表中的每个单词,在您的字典对象中创建一个条目并将true存储为其值。
然后,你只需要检查一个给定的单词是否是你词典中的一个键,以便知道用户选择的单词是否有效。
在这个简单的测试(10,000,000个条目)中,这个工作非常快:
var dict:Object = {};
for(var i:int = 0; i < 10000000; i++) {
dict[i] = true;
}
var btn:Sprite = new Sprite();
btn.graphics.beginFill(0xff0000);
btn.graphics.drawRect(0,0,50,50);
btn.graphics.endFill();
addChild(btn);
btn.addEventListener(MouseEvent.CLICK,checkWord);
var findIt:Boolean = true;
function checkWord(e:MouseEvent):void {
var word:String;
if(findIt) {
word = "3752132";
} else {
word = "9123012456";
}
if(dict[word]) {
trace(word + " found");
} else {
trace(word + " not found");
}
findIt = !findIt;
}
构建字典需要更长的时间,但查找几乎是即时的。
唯一需要注意的是,您必须考虑通过支票的某些键,而不一定是您的单词列表的一部分。诸如toString,prototype等等的单词。只有少数几个,但请牢记这一点。
我会尝试使用您的真实数据集。如果它工作正常,那么你有一个非常简单的解决方案。去喝啤酒(或者你喜欢的任何东西)。
现在,如果在使用真实数据进行测试之后,上面的内容确实无效(请注意我为了简单起见,我已经构建了数字转换为字符串的列表),然后有几个选项,在我的脑海中:< / p>
1)将第一个dict
分区为一组词典。因此,不是在dict
中包含所有单词,而是使用以'a'开头的单词字典,为'b'表示另一个单词。然后,在查找单词之前,检查第一个字符以了解其中的位置查阅它。
类似的东西:
var word:String = "hello";
var dictKey:String = word.charAt(0);
// actual check
if(dict[dictKey][word]) {
trace("found");
} else {
trace("not found");
}
如有必要,您最终可以重新分区。即,使dict['a']
指向由前两个字符索引的另一组字典。所以,你将dict['a']['b'][wordToSearch]
。这个想法有很多可能的变化(你还需要提出一些策略来处理两个字母的单词,例如“be”)。
2)尝试binary search。它的问题是你首先必须预先对列表进行排序。你必须只做一次,因为从你的词典中删除单词是没有意义的。但有数百万字,可能会更加密集。
3)尝试从开源库中获得一些奇特的数据结构,例如:
http://sibirjak.com/blog/index.php/collections/as3commons-collections/
但是,正如我上面所说,我首先尝试最简单,最简单的解决方案,并检查它是否与真实数据集有效。
<强>加强>
处理用于Object的内置属性的关键字的简单方法:
var dict:Object = {};
var keywordsInDict:Array = [];
function buildDictionary():void {
// let's assume this is your original list, retrieved
// from XML or other external means
// it contains "constructor", which should be dealt with
// separately, as it's a built-in prop of Object
var sourceList:Array = ["hello","world","foo","bar","constructor"];
var len:int = sourceList.length;
var word:String;
// just a dummy vanilla object, to test if a word in the list
// is already in use internally by Object
var dummy:Object = {};
for(var i:int = 0; i < len; i++) {
// also, lower-casing is a good idea
// do that when you check words as well
word = sourceList[i].toLowerCase();
if(!dummy[word]) {
dict[i] = true;
} else {
// it's a keyword, so store it separately
keywordsInDict.push(word);
}
}
}
现在,只需在checkWords函数中添加对内置道具的额外检查:
function checkWord(e:MouseEvent):void {
var word:String;
if(findIt) {
word = "Constructor";
} else {
word = "asdfds";
}
word = word.toLowerCase();
var dummy:Object = {};
// check first if the word is a built-in prop
if(dummy[word]) {
// if it is, check if that word was in the original list
// if it was present, we've stored it in keywordsInDict
if(keywordsInDict.indexOf(word) != -1) {
trace(word + " found");
} else {
trace(word + " not found");
}
// not a built-in prop, so just check if it's present in dict
} else {
if(dict[word]) {
trace(word + " found");
} else {
trace(word + " not found");
}
}
findIt = !findIt;
}
答案 1 :(得分:1)
这不是特定于ActionScript的,但Trie是用于存储单词的合适数据结构。