Какой самый быстрый способ найти очень длинный список слов для поиска совпадений в ActionScript 3? - PullRequest
5 голосов
/ 16 мая 2010

Итак, у меня есть список слов (весь английский словарь).

Для игры на совпадение слов, когда игрок перемещает фигуру, мне нужно проверить весь словарь, чтобы увидеть, существует ли слово, которое создал игрок, в словаре. Мне нужно сделать это как можно быстрее. просто перебор словаря слишком медленный.

Какой самый быстрый алгоритм в AS3 для поиска в таком длинном списке совпадений и какой тип данных мне следует использовать? (т.е. массив, объект, словарь и т. д.)

Ответы [ 2 ]

5 голосов
/ 16 мая 2010

Сначала я бы пошел с Object, который является хеш-таблицей (по крайней мере, с точки зрения хранения).

Итак, для каждого слова в вашем списке сделайте запись в вашем словаре 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 и т. Д. Их всего несколько, но имейте это в виду.

Я бы попробовал что-то подобное с вашим реальным набором данных. Если это работает нормально, то у вас есть действительно простое решение. Пойди, выпей пива (или как пожелаешь).

Теперь, если вышесказанное на самом деле не работает после тестирования его с реальными данными (обратите внимание, я построил список с числами, приведенными в виде строк для простоты), тогда несколько вариантов, в верхней части моей головы:

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]. Существует несколько возможных вариантов этой идеи (вам также необходимо придумать стратегию, позволяющую справиться со словами из двух букв, например, «быть»).

2) Попробуйте бинарный поиск . Проблема в том, что сначала вам нужно отсортировать список заранее. Вы должны сделать это только один раз, так как не имеет смысла удалять слова из вашего слова. Но с миллионами слов это может быть довольно интенсивно.

3) Попробуйте некоторые причудливые структуры данных из библиотек с открытым исходным кодом, такие как:

http://sibirjak.com/blog/index.php/collections/as3commons-collections/

http://lab.polygonal.de/ds/

Но опять же, как я уже сказал выше, я сначала попробую самое простое и простое решение и проверим, работает ли оно с реальным набором данных.

Добавлена ​​

Простой способ работы с ключевыми словами, используемыми для встроенных свойств объекта:

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 голос
/ 16 мая 2010

Это не относится к ActionScript, но Trie - подходящая структура данных для хранения слов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...