Preguntándose cuál es la forma más eficiente de hacer un árbol de búsqueda binaria en un corrector ortográfico, lea en un archivo de diccionario de 1000 palabras y luego haga que verifique otro documento que diga que tiene un par de párrafos.
Usar un árbol de búsqueda binaria como un corrector ortográfico
un árbol ternario trie sería más eficiente
Si necesita realizar una búsqueda automática de sugerir / prefijar también, vale la pena mirar un árbol patricia o un árbol de raíces.
Con el ejemplo que proporcionó, es probable que el rendimiento sea irrelevante, ya que en una PC toda la operación tomará aproximadamente el 1% del tiempo que le toma al usuario leer el primer resultado que muestre, siempre que no use un algoritmo completamente estúpido. . Pero aun así, asumiré que el problema es lo suficientemente grande como para que el rendimiento sea un problema.
Si el archivo de diccionario está ordenado previamente (como la mayoría), y si el texto es pequeño en relación con el diccionario tal como lo describe, me sentiré tentado de ordenar el texto, quizás eliminar duplicados, y luego repetir iterativamente ambas listas. -side utilizando el mismo procedimiento que una ordenación por fusión, excepto que informa si cada palabra de texto está en el diccionario en lugar de mostrar una lista fusionada.
Esto hace el trabajo en aproximadamente las comparaciones M log M para el género, más a lo sumo las comparaciones N + M para la iteración (posiblemente menos, pero no la complejidad). Eso es bastante cercano a la complejidad óptima para una operación única: para deshacerse del término lineal en N, necesita encontrar formas de no leer todo el diccionario desde el disco. Estoy bastante seguro de que es posible bsearch en el archivo, especialmente teniendo en cuenta que las palabras son bastante cortas, pero para pequeñas N nadie sabe si buscar el lugar en realidad será más rápido que acceder en serie a los datos.
Tiene las siguientes características:
- No es necesario mantener el diccionario en la memoria, solo el texto.
- Sin embargo, solo haces una pasada sobre el archivo de diccionario.
- No hace ningún procesamiento costoso del diccionario.
Por supuesto, si el archivo de diccionario no está previamente ordenado, entonces esto no funciona, y si puede mantener el diccionario en la memoria para la siguiente operación de revisión ortográfica, entonces puede amortizar el costo de E / S y procesarlo en un árbol en varios textos diferentes, que será una victoria a largo plazo.
Si el diccionario es realmente enorme, entonces puede beneficiarse de almacenarlo en el disco en una forma preprocesada equivalente a un árbol desequilibrado ponderado de acuerdo con las frecuencias relativas de las diversas palabras en su idioma. Entonces puede hacer menos de O (N) acceso al disco para textos pequeños, y en la mayoría de los sistemas operativos no molesta cargarlo en la memoria, simplemente mmap el archivo y deje que el sistema operativo se preocupe por ello. Para un diccionario grande, los conglomerados que contienen palabras que comienzan con "dimetilo" no necesitan ser tocados.
Otra consideración es un árbol desplegable para el diccionario. Un árbol desplegable se desequilibra a medida que busca cosas en él, con el fin de hacer que los valores utilizados con frecuencia sean más rápidos de encontrar. La mayoría de los textos utilizan una pequeña cantidad de palabras repetidas veces, de modo que si el texto es lo suficientemente extenso como para justificar la sobrecarga, eventualmente ganará.
Ambas cosas están sujetas al punto de Steven A Lowe de que, para cuerdas, un trie pega a un árbol normal. Sin embargo, no sé si encontrarás un trie splay disponible en el mercado.
Si solo está tratando de ver si existe una palabra en particular en su diccionario (es decir, está escrita correctamente), entonces no creo que un árbol de búsqueda binaria sea lo que está buscando. Una mejor manera de almacenar esa información sería en un árbol de estilo, donde cada nodo sucesivo en su árbol es un carácter, y leer la ruta al nodo final le da la ortografía de esa palabra. También necesitaría agregar un marcador para indicar un final de palabra.
Por ejemplo, supongamos que tu diccionario tiene estas palabras: carro, carro, gato, copa, corte
- C
- A
- R
- end
- T
- T
- end
- U
- P
- end
- T
- end
Comprobar si existe una palabra es una cuestión de mirar cada letra individualmente, y que existe en los hijos del nodo actual.
Check for "cat"
Does "C" exist at the root level? Yes, move to the next letter.
Does "A" exist underneath C? Yes, move on.
Does "T" exist underneath A? Yes, move on.
Is there a word ending after the T? Yes. Word exists.
Check for "cu"
Does "C" exist at the root level? Yes, move to the next letter.
Does "U" exist at the root level? Yes, move to the next letter.
Is there a word ending after the U? No. Word does not exist.
Cómo almacena esta información depende de usted. Como Steven señaló, un Trie de búsqueda ternaria podría ser el camino a seguir: cada nodo tendría 27 posibles nodos secundarios.
¿Estás decidido a usar un árbol de búsqueda binario? Un filtro Bloom probablemente sea una estructura de datos más eficiente.
Al ver que esto es una cuestión tareas Voy a suponer que usted tiene que utilizar un árbol viejo y simple binario (no hay árboles rojo-Negro, árboles AVL, árboles Radix, etc.). La respuesta es, pues, para tratar de mantener el árbol de equilibrado a medida que construye desde la lista de palabras. Un método consiste en aleatorizar la lista antes de leer en ella, esto da resultados razonables. Pero se puede obtener mejores resultados si se ordena la secuencia de entrada (utilizando la misma comparación que lo utiliza el árbol), y luego subdividir de forma recursiva la entrada de regresar al punto medio hasta que no queden elementos. El resultado es un árbol de equilibrado.
Toqué tres maneras diferentes de hacerlo en C #:
private static IEnumerable<T> BinaryTreeOrder<T>(IList<T> range, int first, int last)
{
if (first > last)
{
yield break;
}
int mid = (first + last) / 2;
yield return range[mid];
foreach (var item in BinaryTreeOrder(range, first, mid - 1))
{
yield return item;
}
foreach (var item in BinaryTreeOrder(range, mid + 1, last))
{
yield return item;
}
}
private static void BinaryTreeOrder<T>(IList<T> range, int first, int last,
ref IList<T> outList)
{
if (first > last)
{
return;
}
int mid = (first + last) / 2;
outList.Add(range[mid]);
BinaryTreeOrder(range, first, mid - 1, ref outList);
BinaryTreeOrder(range, mid + 1, last, ref outList);
}
private static void BinaryTreeOrder<T>(IList<T> range, int first, int last,
ref BinaryTree<T> tree) where T : IComparable<T>
{
if (first > last)
{
return;
}
int mid = (first + last) / 2;
tree.Add(range[mid]);
BinaryTreeOrder(range, first, mid - 1, ref tree);
BinaryTreeOrder(range, mid + 1, last, ref tree);
}
Este sitio le ayudará a que tiene la implementación en Java.
Como se ha sugerido un trie sería más eficiente que un árbol binario, pero se puede utilizar un HashMap y croquetas de cada palabra. Tiene un pequeño diccionario (1000 entradas). A medida que atraviesan el documento, comprobar si las palabras están en el mapa hash. Si no lo son, se supone que está mal escrita la palabra.
Esto no le dará posible corrección de una palabra mal escrita. Simplemente le dice sí o no (correcta o no).
Si desea sugerencias de ortografía de las palabras incorrectas se puede empezar de la palabra en el archivo, a continuación, generar todas las palabras 1 edición distancia y añadirlos como hijos de la palabra inicial. De esta manera usted está construyendo un gráfico. Go 2 niveles de profundidad para obtener la máxima velocidad vs exactitud. Si genera un nodo palabra que está en el diccionario, se puede añadir a una lista de posibles sugerencias. Al final, devolver la lista de posibles sugerencias.
Para una mejor corrección ortográfica, también tratar de añadir en coincidencia fonética.
Yuh mar -> ver yah
Este método (de creación de gráficos de cuerdas 1 edición de distancia) es "lento". Pero es un buen ejercicio académico. Tiempo de ejecución es O (n ^ ramas).
Si está interesado aquí es un enlace a uno construí yo mismo (por diversión): https://github.com/eamocanu/spellcheck.graph
Algunos ejemplos de gráficos: https://github.com/eamocanu/spellcheck.graph/tree/master/graph%20photos
También he añadido un componente de interfaz de usuario a la misma que genera los gráficos. Se trata de una biblioteca externa.













