Algoritmo de Ukkonen
En ciencias de la computación, el algoritmo de Ukkonen es un algoritmo online de tiempo de computación lineal, diseñado para la construcción eficiente de un árbol de sufijos para una cadena S. Propuesto por Esko Ukkonen en 1995, se distingue por su enfoque incremental y su relativa simplicidad en comparación con soluciones anteriores. Previamente, existían dos algoritmos capaces de construir árboles de sufijos en tiempo lineal: el algoritmo de Weiner (1973) y el algoritmo de McCreight (1976). No obstante, el algoritmo de Ukkonen destaca por su naturaleza *online*, permitiendo el procesamiento de la cadena de entrada de manera progresiva, carácter a carácter, sin requerir la totalidad de la cadena al inicio.
From Wikipedia, the free encyclopedia

En ciencias de la computación, el algoritmo de Ukkonen es un algoritmo online de tiempo de computación lineal, diseñado para la construcción eficiente de un árbol de sufijos para una cadena . Propuesto por Esko Ukkonen en 1995, se distingue por su enfoque incremental y su relativa simplicidad en comparación con soluciones anteriores.
Previamente, existían dos algoritmos capaces de construir árboles de sufijos en tiempo lineal: el algoritmo de Weiner (1973) y el algoritmo de McCreight (1976). No obstante, el algoritmo de Ukkonen destaca por su naturaleza *online*, permitiendo el procesamiento de la cadena de entrada de manera progresiva, carácter a carácter, sin requerir la totalidad de la cadena al inicio.
Reglas de Extensión
El algoritmo de Ukkonen se basa en la construcción iterativa de árboles de sufijos *implícitos*. Para una cadena , se define como el árbol de sufijos implícito que representa todos los sufijos de . El algoritmo, aplicado a una cadena de longitud , construye sucesivamente . La ejecución se divide en fases, donde la fase genera a partir de . La inclusión del carácter especial al final de garantiza que represente el árbol de sufijos completo de .
Cada fase se subdivide en extensiones. En la extensión *j*-ésima de la fase , el algoritmo busca el punto final del camino desde la raíz etiquetado con la subcadena y, si es necesario, extiende dicho camino con el carácter .
La extensión de los caminos se realiza según las siguientes reglas, aplicadas al sufijo de en la extensión *j*, donde es el carácter a agregar:
Reglas de Extensión
La extensión de los caminos se realiza según las siguientes reglas, aplicadas al sufijo de en la extensión *j*, donde es el carácter a agregar:
Regla 1: Extensión en Hoja
Si el camino para termina en una hoja, el carácter se añade al final de la etiqueta de la arista incidente en esa hoja.
- Explicación: Imagina que llegaste al final de una rama en el árbol. Esta regla dice que, si quieres añadir el nuevo carácter `c`, simplemente lo "pegas" al final de esa rama. Por ejemplo, si tienes la palabra "ana" representada en el árbol y quieres añadir la letra "n" para formar "anan", simplemente añades la "n" al final de la rama que representa "ana".
Regla 2: Extensión en Arista o Nodo Interno
Si el camino para no termina en una hoja y ningún camino desde el punto final de se inicia con el carácter , se crea una nueva arista etiquetada con desde el punto final de . Esta nueva arista incide en una nueva hoja etiquetada con . Si termina en el interior de una arista existente, se crea un nuevo nodo para dividir la arista en el punto final de .
- Explicación: Ahora imagina que no llegaste al final de una rama, sino que te encuentras en medio de una rama o en un punto donde se dividen varias ramas. Si no ves ninguna rama que empiece con el nuevo carácter `c`, entonces tienes que crear una nueva rama que salga desde ese punto y esté etiquetada con `c`. Si estás en medio de una rama existente, primero tienes que crear un nuevo punto de división (un nodo) para poder empezar la nueva rama con `c`.
Regla 3: Extensión Implícita
Si algún camino desde el punto final de ya se inicia con el carácter , no es necesario realizar ninguna acción, ya que el sufijo ya está representado en el árbol.
- Explicación: En este caso, ¡tienes suerte! El nuevo carácter `c` ya está presente en el árbol, saliendo desde el punto donde te encuentras. Esto significa que el sufijo que querías añadir ya está representado en el árbol, así que no tienes que hacer nada.
Enlaces de Sufijos (Suffix Links)
Los *enlaces de sufijos* son una estructura clave para la eficiencia del algoritmo:
Definición: Sea un nodo interno con etiqueta , donde es un carácter y es una cadena (posiblemente vacía). Si existe otro nodo con etiqueta , entonces se define un *enlace de sufijo* como un puntero de a .
Los enlaces de sufijos facilitan la localización rápida de sufijos en el árbol, optimizando las operaciones de extensión.
Optimización del Algoritmo
El algoritmo de Ukkonen incorpora técnicas de optimización para alcanzar un tiempo de ejecución lineal:
- Skip/Count Trick: Permite recorrer rápidamente las aristas del árbol cuando se conoce la existencia de un camino específico.
- Stop Trick: Detiene la fase actual cuando la Regla 3 se aplica, evitando extensiones innecesarias.
- Pointer Trick: Mantiene punteros a las hojas creadas, simplificando la aplicación de la Regla 1 en fases posteriores.
Complejidad Computacional
Gracias a las reglas de extensión y las técnicas de optimización, el algoritmo de Ukkonen logra construir el árbol de sufijos en tiempo y espacio , donde es la longitud de la cadena de entrada. Esta notación, conocida como "Big O", indica que tanto el tiempo que tarda el algoritmo en ejecutarse como la cantidad de memoria que necesita crecen linealmente con la longitud de la cadena de entrada. En otras palabras, si duplicamos la longitud de la cadena, el tiempo de ejecución y la memoria requerida también se duplicarán aproximadamente. Esta eficiencia es crucial para trabajar con textos extensos, ya que algoritmos con complejidades mayores (como o ) se volverían prohibitivamente lentos en estos casos. La complejidad lineal del algoritmo de Ukkonen se debe a la combinación inteligente de las reglas de extensión y las técnicas de optimización, que evitan la necesidad de realizar operaciones redundantes y permiten construir el árbol de sufijos de manera incremental y eficiente.