Determinar si un Algoritmo es O (log n)

25

Estoy actualizando mi Teoría CS, y quiero saber cómo identificar la complejidad de un algoritmo O (log n). Específicamente, ¿hay una manera fácil de identificarlo?

Sé que con O (n), generalmente tienes un solo bucle; O (n ^ 2) es un doble bucle; O (n ^ 3) es un bucle triple, etc. ¿Qué tal O (log n)?

Atif
fuente
Ah, ese es el único lugar donde no miré :)
Atif

Respuestas:

32

Sé que con O (n), generalmente tienes un solo bucle; O (n ^ 2) es un doble bucle; O (n ^ 3) es un bucle triple, etc. ¿Qué tal O (log n)?

Realmente vas por el camino equivocado aquí. Estás tratando de memorizar qué expresión big-O va con una estructura algorítmica dada, pero en realidad solo debes contar el número de operaciones que requiere el algoritmo y compararlo con el tamaño de la entrada. Un algoritmo que recorre toda su entrada tiene un rendimiento O (n) porque ejecuta el bucle n veces, no porque tenga un solo bucle. Aquí hay un bucle único con rendimiento O (log n):

for (i = 0; i < log2(input.count); i++) {
    doSomething(...);
}

Entonces, cualquier algoritmo donde el número de operaciones requeridas esté en el orden del logaritmo del tamaño de la entrada es O (log n). Lo importante que le dice el análisis big-O es cómo cambia el tiempo de ejecución de un algoritmo en relación con el tamaño de la entrada: si duplica el tamaño de la entrada, ¿el algoritmo da un paso más (O (log n)) , el doble de pasos (O (n)), cuatro veces más pasos (O (n ^ 2)), etc.

¿Ayuda saber por experiencia que los algoritmos que particionan repetidamente sus entradas generalmente tienen 'log n' como componente de su desempeño? Seguro. Pero no busque la partición y llegue a la conclusión de que el rendimiento del algoritmo es O (log n); podría ser algo como O (n log n), que es bastante diferente.

Caleb
fuente
3
Tenga en cuenta que una forma más coloquial de decir "en el orden del logaritmo del tamaño" es decir "en el orden del número de dígitos en el tamaño".
@Caleb, la base real del logaritmo no es importante cuando se habla de escala.
@Caleb hablando absolutos no tiene sentido con big-O. Una redacción que quizás le guste más: cuando el número de dígitos se duplica, el número de pasos se duplica.
@Caleb hablando absolutos no tiene sentido con big-O. Una redacción que quizás le guste más: cuando el número de dígitos se duplica, el número de pasos se duplica.
@ ThorbjørnRavnAndersen Sí, eso es lo que significa "el logaritmo del tamaño". No estoy seguro de cuál es su problema con la frase, excepto que habría elegido decirlo de manera diferente. Fundamentalmente, creo que estamos de acuerdo.
Caleb
25

La idea es que un algoritmo es O(log n)si en lugar de desplazarse por una estructura 1 por 1, divide la estructura por la mitad una y otra vez y realiza un número constante de operaciones para cada división. Los algoritmos de búsqueda donde el espacio de respuesta se sigue dividiendo son O(log n). Un ejemplo de esto es la búsqueda binaria , donde sigue dividiendo una matriz ordenada por la mitad una y otra vez hasta que encuentre el número.

Nota: No es necesario que se divida en mitades pares.

Casey Patton
fuente
1
¿Qué sucede si divido la entrada en dos y luego repito 2 ^ (n / 2) veces en el resto antes de dividirla nuevamente? (Por supuesto, sé qué entonces, solo quería mostrar un ejemplo donde este enfoque simplista falla).
Tamás Szelei
@afish Eso es algo raro. Es espectacularmente raro cuando se busca.
Donal Fellows
1
@DonalFellows La teoría del algoritmo no es una ciencia empírica. Y la pregunta no era sobre la búsqueda, es solo la mención de log nreflejos de búsqueda binaria activados en las personas.
Tamás Szelei
2
La partición no crea el algoritmo O (log n), sino que (generalmente) agrega un factor de log n al límite big-O. Las clases recursivas, como heapsort y mergesort, son ejemplos perfectos: dividen la entrada, pero luego dividen recursivamente ambas particiones resultantes. El resultado es el rendimiento O (n log n).
Caleb
@afish: Buen punto. Mi objetivo con esta respuesta es mantenerlo lo más simple posible dada la naturaleza de la pregunta. Cambié la línea "divide la estructura a la mitad ..." a "divide la estructura a la mitad ... y realiza un número constante de operaciones para cada división" para tratar de transmitir este punto de manera simple.
Casey Patton el
2

Los ejemplos típicos son los que tratan con la búsqueda binaria. Por ejemplo, un algoritmo de búsqueda binaria suele ser O(log n).

Si tiene un árbol de búsqueda binario , buscar, insertar y eliminar son todos O(log n)complejos.

Cualquier situación en la que particiones continuamente el espacio a menudo implicará un log ncomponente. Esta es la razón por la cual muchos algoritmos de clasificación tienen O(nlog n)complejidad, porque a menudo dividen un conjunto y clasifican a medida que avanzan.

Kris Harper
fuente
1

Si lo desea tan simple como "bucle simple -> O (n), bucle doble -> O (n ^ 2)", entonces la respuesta es probablemente "Árbol -> O (log n)". Atravesar con mayor precisión un árbol desde la raíz hasta una hoja (¡no todas!) O al revés. Sin embargo, estas son todas simplificaciones excesivas.

Scarfridge
fuente
Entonces, ¿qué hay de malo en mi respuesta? Estoy abierto a la crítica constructiva.
scarfridge
0

Desea saber si hay una manera fácil de identificar si un algoritmo es O (log N).

Bueno: solo corre y cronometra. Ejecútelo para entradas de 1.000, 10.000, 100.000 y un millón.

Si ve un tiempo de ejecución de 3,4,5,6 segundos (o algunos múltiples), puede decir con seguridad que es O (log N). Si es más como: 1,10,100,1000 segundos, entonces probablemente sea O (N). Y si es como 3,40,500,6000 segundos, entonces es O (N log N).

Pieter B
fuente
Todos deberían dar a esta respuesta un voto a favor y uno a favor, ambos por razones obvias :-)
gnasher729