Ajuda para entender algoritmo

Bom galera, encontrei na net um algoritmo de correção ortografica e gostaria de entender ele mais afundo para poder implentar algo para uso próprio, pois o conceito que eu usaria seria praticamente o mesmo, procurar uma palavra em um banco de dados e retornar a palavra que tiver o maior ‘score’ de acerto.

Vou colocar o código que eu encontrei e dizer um poco do que eu entendi, o problema é que ele usa de algumas classes que eu nunca tinha nem visto, então estou com dificuldade de entender o que ele realmente faz.

    private final HashMap<String, Integer> nWords = new HashMap<String, Integer>();

    public Spelling(String file) throws IOException {
        BufferedReader in = new BufferedReader(new FileReader(file));
        String temp = null;
        Pattern p = Pattern.compile("\w+");
        while ((temp = in.readLine()) != null) {
            Matcher m = p.matcher(temp.toLowerCase());
            while (m.find()) {
                //System.out.println(nWords.containsKey(temp) ? nWords.get(temp) + 1 : 1);
                nWords.put((temp = m.group()), nWords.containsKey(temp) ? nWords.get(temp) + 1 : 1);
            }
        }
        in.close();
    }

    private final ArrayList<String> edits(String word) {
        ArrayList<String> result = new ArrayList<String>();
        for (int i = 0; i < word.length(); ++i) {
            result.add(word.substring(0, i) + word.substring(i + 1));
        }
        for (int i = 0; i < word.length() - 1; ++i) {
            result.add(word.substring(0, i) + word.substring(i + 1, i + 2) + word.substring(i, i + 1) + word.substring(i + 2));
        }
        for (int i = 0; i < word.length(); ++i) {
            for (char c = 'a'; c <= 'z'; ++c) {
                result.add(word.substring(0, i) + String.valueOf(c) + word.substring(i + 1));
            }
        }
        for (int i = 0; i <= word.length(); ++i) {
            for (char c = 'a'; c <= 'z'; ++c) {
                result.add(word.substring(0, i) + String.valueOf(c) + word.substring(i));
            }
        }
        return result;
    }

    public final String correct(String word) {
        if (nWords.containsKey(word)) {
            return word;
        }
        ArrayList<String> list = edits(word);
        HashMap<Integer, String> candidates = new HashMap<Integer, String>();
        for (String s : list) {
            if (nWords.containsKey(s)) {
                candidates.put(nWords.get(s), s);
            }
        }
        if (candidates.size() > 0) {
            return candidates.get(Collections.max(candidates.keySet()));
        }
        candidates.clear();
        for (String s : list) {
            for (String w : edits(s)) {
                if (nWords.containsKey(w)) {
                    candidates.put(nWords.get(w), w);
                }
            }
        }
        return candidates.size() > 0 ? candidates.get(Collections.max(candidates.keySet())) : word;
    }

    public static void main(String args[]) throws IOException {
        Spelling spel = new Spelling("C:\big.txt");
        for (int i = 0; i < args.length; i++) {
            System.out.println(spel.correct(args[i]));
        }
    }
}

Bom, o que eu entendi é, ele cria uma HashMap com todas as palavras encontradas nesse arquivo de base(o arquivo big.txt contém a maioria das palavras em ingles existentes) só que eu nao entendi o que significa aquele inteiro dentro do HashMap.
Depois de carregar todo o arquivo dentro de uma HashMap, ele pega os argumentos passados, que seriam as palavras para se corrigir e cria uma ArrayList com as possibilidades de escrita dentro de cada argumento, tendo um anagrama gigante de cada entrada.
E no método correct ele procura a palavra dentro da ArrayList que tenha um maior score, certo? Porém eu nao sei ao certo como ele faz isso, ou se é isso mesmo que ele está fazendo.

Uma das coisas que eu acabei nao entendo muito bem, foram os if’s ternarios que eles usaram, eu ainda tenho uma dificuldade pra entender o que está sendo feito dentro de um if ternário =/

Quero poder entender direito o que esse programa faz para poder implentar o meu, achei a ideia muito boa e um conceito muito legal de estatistica.
Se alguém ai puder dar uma ajuda, obrigado!

acredito q este codigo faça algo parecido com o q escrevi abaixo o ideal seria testar o mesmo
para ter certeza

operador ternario é simples:

(condição) ? retorno se a condição for true : retorno se a condição for false

main recebe parametros pela linha de comando
executa o construtor da classe que le todas as linhas do arquivo big.txt
procura por caracteres em cada linha e armazena em uma String adiciona a um map os caracteres encontrados e a quantidade de vezes que eles aparecem no arquivo de texto
em seguida executa o metodo correct e imprime as Strings retornadas por ele
o metodo edits vai no primeiro for adicionar cada uma das letras a um list
no segundo adicionar ao list a palavra ao contrario
no terceiro for uma letra todo o alfabeto e a proxima letra isso para todas as letras
no ultimo uma letra todo o alfabeto e o restante da palavra tambem para todas as letras
o metodo correct verifica se a palavra q recebeu existe no map criado pelo construtor se existir retorna este
se nao existir pega o list do metodo edits e cria um map contendo cada uma das palavras q lexistem no list e no primeiro map e a qtde de vezes q aparecem e em seguida retorna a palavra q mais se repetir
se o map ficar vazio é criada uma nova lista pelo metodo edits para cada palavra da primeira lista restornada e criado um novo map e deopis é retornado a que mais se repetir

Obrigado tiago, estava dando uma olhada aqui e dei uma melhorada no código.

Não estou mais utilizando Patterns nem Matcher pois creio eu que seja um gargalo, os troquei por verificações simples de if verificando se o caracter é uma letra ou não e caso nao seja uma letra ele me coloca um token apenas para mostrar onde começa e acaba uma linha.

Troquei as concatenações de + nas strings por StringBuilders e consegui uma performance muito melhor.
O conceito desse algorotimo é muito bom, incrivel mesmo. Quiser eu ter pensado nisso antes haha.

O que eu ainda nao consegui entender, foi porque utilizar

Collections.max

No retorna do candidates. Como ele sabe que a ultima aparição dentro do Candidates foi a que obteve maior ‘score’ na palavra e é a que se aproxima mais da palavra que o usuario quis digitar?

Ola , acho que acontece mais ou menos o que eu escrevi abaixo , espero que ajude

nesta linha
nWords.put((temp = m.group()), nWords.containsKey(temp) ? nWords.get(temp) + 1 : 1);

estamos adicionando objetos ao hashmap a chave é a string e o valor é um inteiro que representa o numero de vezes que esta String foi incluida no map
veja que o operador ternário verifica se a chave ja existe ou nao
se nao existir recebe 1 ou seja esta sendo incluida pela primeira vez se ja existir pega o valor ou seja o 1 e soma mais 1 o que resulta 2 indicando que estaria sendo incluida pela segunda vez e isto se repete para todas as incusoes

nesta linha
HashMap<Integer, String> candidates = new HashMap<Integer, String>();
o hashmap é invertido entao a chave passa ser o numero de repeticoes depois criamos um Set que contem apenas as chaves do HashMap atraves do comando KeySet e entao o colections.max retorna o maior valor presente na coleção no caso deste algoritmo o maior numero de repetiçoes

Muito bom este algoritmo

Baseado nesse não?
http://norvig.com/spell-correct.html

Eu fiz uma versão em gawk bem curtinha, menor que a do Norvig, pena q ele não publicou no seu site :frowning:

Sim, baseado nele.
Legal que ele passou toda a parte de estatisca dentro das palavras.

Pois ele diz que o erro pode estar entre uma palavra a mais, uma a menos ou má escrita da palavra em si.
Ai o porque daqueles for’s todos.

Eu dei uma boa melhorada nele, no quesito de performance.
Adiconei alguns StringBuilder, só passo para toLowerCase quando a palavra é realmente maiscula, pois o algoritmo do toLowerCase é monstruoso haha, da até medo.
Mudei tb a forma como adiconar linha por linha, usando um iterator e split, melhoro a perofrmance em uns 40%.

Agora to dando uma lida em um artigo que fala de performance em lists:
http://www.onjava.com/pub/a/oreilly/java/news/javaperf_code.html?CMP=AFC-ak_article&ATT=Optimizing+a+Query+on+a+Collection%3A+Table+and+Full+Test+Code+Listing

Tem um site sobre performance em java que é muito legal:
http://www.javaperformancetuning.com/tips/index.shtml

Na faculdade eu implementei uma vez o algoritmo de Boyer-Moore em C. É bastante eficiente e razoavelmente simples de implementar.