You are on page 1of 11

Cul es el objetivo de un algoritmo?

Secuencia de instrucciones cuyo objetivo es la resolucin de un


problema. El trmino clave aqu es el de problema. Existen multitud de
problemas de computacin que se pueden resolver mediante un algoritmo
(aunque algunos pocos no tienen un algoritmo que los solucione)
Bueno... pues para resolver cada problema, podemos obtener ms de un
algoritmo que lo solucione... pero... Cul de ellos es el mejor? Sera
conveniente poder aplicar algn tipo de "puntuacin" a los algoritmos, y que
cuanta ms puntuacin sacara un algoritmo, pues supondremos que es
mejor. Eso es, en cierto modo, la complejidad.
Qu es la complejidad de un algoritmo?
Atacar el problema desde distintos puntos de vista, aplicando distintas
estrategias, y por tanto, llegando a soluciones algortmicas distintas.
Desde el punto de vista computacional, es necesario disponer de alguna
forma de comparar una solucin algortmica con otra, para conocer cmo
se comportarn cuando las implementemos, especialmente al atacar
problemas grandes.
La complejidad algortmica es una mtrica terica que se aplica a los
algoritmos en este sentido.
Introduccin
Entender la complejidad es importante porque a la hora de resolver muchos
problemas, utilizamos algoritmos ya diseados. Saber valorar su valor de
complejidad puede ayudarnos mucho a conocer cmo se va a comportar el
algoritmo e incluso a escoger uno u otro.
Nos vamos a dedicar a intentar exponer qu es la complejidad de un
algoritmo desde un punto de vista sencillo, intentado distinguir qu impacto
tiene el que un algoritmo tenga una u otra complejidad. Y, como de
costumbre, adoptamos grandes simplificaciones, con el nico nimo de
obtener una visin general de los conceptos.
Saber si un algoritmo es mejor que otro puede estudiarse desde dos puntos
de vista: un algoritmo es mejor cuanto menos tarde en resolver un
problema, o bien es tanto mejor cuanta menos memoria necesite.
A la idea del tiempo que consume un algoritmo para resolver un problema le
llamamos complejidad temporal y a la idea de la memoria que necesita el
algoritmo le llamamos complejidad espacial.
La complejidad espacial, en general, tiene mucho menos inters. El tiempo
es un recurso mucho ms valioso que el espacio.

As que cuando hablamos de complejidad a secas, nos estamos refiriendo


prcticamente siempre a complejidad temporal.
Bueno... pues ya hemos presentado de manera intuitiva esto de la
complejidad: la complejidad de un algoritmo es un "valor", por as decirlo,
que nos da una idea de cunto va a tardar un algoritmo en resolver el
problema para el que fue diseado.
El tamao de un problema
La idea que subyace tras el concepto de complejidad temporal de un
algoritmo es, bsicamente, medir cunto tarda en resolver el
problema.
Para resolver cualquier problema, son necesarios unos datos de entrada
sobre los que trabaja el algoritmo y que describen una ocurrencia concreta
del problema que queremos resolver. El algoritmo, finalmente obtiene una o
varias soluciones al problema (si es que el problema tiene soluciones).
Sin embargo, debemos tener en cuenta algunas consideraciones. Por
ejemplo, piensa en un tpico algoritmo para ordenar los elementos de un
vector. Seguro que conoces alguno. El algoritmo consta de una serie de
instrucciones que se repiten una y otra vez (bucles), y probablemente, de
una serie de selecciones (comparaciones) que hacen que se ejecute uno u
otro camino dentro del algoritmo.
Se hace necesaria una pregunta: Tardar lo mismo un algoritmo de
ordenacin en ordenar un vector con 100 valores que uno con 100000
valores?.... Obviamente no. Pues aqu es donde tenemos que empezar a
hablar del tamao o talla del problema.
Un algoritmo de ordenacin debera ser capaz de ordenar un vector con
cualquier nmero de elementos. Sin embargo, el tamao del vector incide
directamente en el tiempo que tarda el algoritmo en resolverse.
Pues cualquier problema tiene un tamao, que es un valor o un conjunto de
valores que se pueden obtener de los datos de entrada y que si varan,
normalmente tienen una repercusin en el tiempo que tardar el algoritmo
en finalizar (aunque en algunos casos no).
Por ejemplo, del problema de ordenar un vector, la talla del problema nos la
da el nmero de elementos del vector.
En un algoritmo que halle el trmino n-simo de la, la talla nos la da el
propio trmino nmero n que queremos hallar.
Cada problema tiene uno o varios valores que determinan su talla.
La complejidad se calcula en funcin de una talla genrica, y no concreta.
Por ejemplo, la complejidad de un algoritmo de ordenacin se calcula
pensando en un array de longitud n, y no 5, 120 o 100000.

La complejidad no es un nmero: es una funcin


Otra consideracin a tener en cuenta a la hora de tratar con la complejidad
es que si estamos contando el tiempo que tarda un algoritmo en resolver un
problema En qu ordenador lo ejecutamos? Parece obvio que el mismo
algoritmo ejecutado en un ordenador el doble de rpido que otro tardar la
mitad en encontrar la solucin. Cul debera ser entonces la unidad de
medida de la complejidad? Ninguna unidad de tiempo nos vale: ni segundos
ni milisegundos, porque el resultado variara de un ordenador a otro.
Adems... parece obvio tambin que el mismo algoritmo tardar ms o
menos en solucionar un problema de una talla u otra. Es decir, no puede
tardarse lo mismo en ordenar un array de 100 valores que uno de 100000.
La medida del tiempo tiene que ser independiente: de la mquina del
lenguaje de programacin del compilador de cualquier otro elemento
hardware o software que influya en el anlisis.
Para conseguir esta independencia una posible medida abstracta puede
consistir en determinar cuantos pasos se efectan al ejecutarse el
algoritmo.
Bueno... pues vamos a adoptar una simplificacin que nos permita no tener
en cuenta en qu ordenador se ejecutar el algoritmo: en lugar de medir
tiempos, vamos a contar las instrucciones que debe realizar el algoritmo.
Supondremos que cada instruccin se ejecuta en un tiempo
constante.
Nos podemos permitir esa simplificacin porque lo que realmente queremos
saber es cmo crece el nmero de instrucciones necesarias para
resolver el problema con respecto a la talla del problema. Eso es
realmente la complejidad.
Por ejemplo, observa sta funcin escrita en un pseudocdigo (da igual
cul sea su propsito).

En este algoritmo hay un par de bucles para que se ejecuten uno despus
del otro.
Observemos el primer bucle. Se ejecuta n veces, y en su interior hay una
instruccin (la de la lnea 5). Eso quiere decir que la lnea 5 se ejecuta n
veces. Despus se ejecuta el segundo bucle, que contiene en su interior dos
instrucciones (las de las lneas 8 y 9). Como ese segundo bucle se ejecuta
tambin n veces y tiene dos instrucciones, se realizan 2n instrucciones.
Finalmente hay una instruccin en la lnea 11 que se ejecuta una sola vez.
Bien.... el nmero de instrucciones que se ejecutan en total son n+2n+1...
Es decir, 3n+1
Todava no hemos llegado al fondo de la cuestin, pero vamos encaminados.
Podemos decir que la complejidad de ese algoritmo es 3n+1, porque ese es
el nmero de instrucciones que hay que realizar para solucionar el problema
cuando la talla del problema es n.
La idea que subyace es que podemos saber cmo se comporta el algoritmo
conforme la talla del problema va creciendo. En este caso, si representamos
3n+1 con respecto a n nos daremos cuenta de que esta funcin es una
recta. Para terminar de ver la importancia de esto, vamos a ver un par de
funciones ms de ejemplo.

La funcin ejemplo2 realiza siempre 3 instrucciones (las lneas 4, 5 y 6),


independientemente de lo que se le pase como parmetro. As pues, este
algoritmo siempre tarda lo mismo para cualquier valor de n. El nmero de
instrucciones se mantiene constante, a diferencia del ejemplo anterior, que
creca linealmente con respecto a n.
La funcin ejemplo3 tiene dos bucles para anidados. Cada bucle se ejecuta
n veces, y en el interior del segundo hay 2 instrucciones. Ej bucle interior
hace que las dos instrucciones se repitan n veces, y el bucle exterior hace
que todo eso se repita n veces ms. Despus hay una ltima instruccin (la
de la lnea 10). As pues, se hacen 2nn+1 instrucciones... es decir,
2n2+1.
Si representamos 2n2+1 con respecto a n en un grfico nos podemos dar
cuenta de que es una parbola... es decir, el tiempo crece muchsimo ms
rpido conforme crece n que en los ejemplos anteriores. En este caso, el
tiempo crece cuadrticamente. Igual que ocurra en los ejemplos
anteriores, si en una determinada mquina para n=100 se tardan 7
unidades de tiempo, con unas pocas operaciones podemos intuir cunto va
a tardar para un n=1000 o para cualquier otro valor.

Lo importante de la idea expuesta hasta ahora es que los distintos


algoritmos se comportan de forma distinta. Su tiempo de ejecucin vara de
manera muy distinta conforme aumenta la talla del problema.
Peor caso, mejor caso
En los tres ejemplos que hemos visto hasta ahora, la complejidad del
algoritmo es totalmente dependiente de la talla, pero no todos los
algoritmos se comportan de igual manera frente a un problema de la misma
talla.
En la mayor parte de los algoritmos, tambin influye el propio
contenido de los datos. Es posible que para un problema determinado de
tamao n, unas veces el algoritmo tarde ms y otras tarde menos,
dependiendo de los propios datos de entrada del problema de tamao
n.
Un ejemplo... ste algoritmo comprueba si un determinado valor x est
contenido en un array v, cuyos ndices van de 1 a n

Contiene en su interior un bucle mientras que no se ejecuta un nmero


determinado de veces (como ocurra en los ejemplos anteriores, que
utilizaban bucles for). Imagina que pasamos a esa funcin un vector de
n=100 enteros, y un entero x=17. Es evidente que la talla del problema es
n=100, ya que es lo que determina el nmero de instrucciones que se
ejecutarn. Sin embargo, es posible que el valor 17 est situado en la
posicin 30 del vector, con lo que el bucle se realizar 30 veces, o quiz en
la posicin 50, o quiz no est en el vector, con lo que el bucle se ejecutar
n=100 veces, recorriendo todo el vector.
En ste caso, nos conviene distinguir dos mtricas: qu es lo peor que nos
puede pasar para un problema de tamao n, y qu es lo mejor que nos
puede pasar para un problema de tamao n.

Vamos a echar unas pocas cuentas para el ejemplo de arriba. Vamos a


suponer que en el interior del bucle mientras hay 2 instrucciones (el si y el
incremento de i), y en el exterior hay 3, dos antes del mientras y una
despus.
Pues bien... lo mejor que nos puede pasar es que encontremos el valor x a
la primera. En ese caso, el bucle se ejecuta una sola vez.. El nmero de
instrucciones que realizamos son 3+2=5.
Lo peor que puede pasar es que el valor x no se encuentre en el vector, as
que el bucle se ejecutar n veces, recorriendo todo el vector. El nmero de
instrucciones que realizamos es 3+2n
Para expresar esto, se utiliza una notacin especfica, diremos que para este
algoritmo, su complejidad en el peor caso es O(2n+3) A esta notacin se le
denomina "O Grande" (del ingls "Big-O"), o simplemente "Complejidad en
el peor caso".
Anlogamente, diremos que para este algoritmo su complejidad en el mejor
caso es (5). A esta notacin se le denomina "Omega" (por la letra griega
omega mayscula ) o simplemente, "complejidad en el mejor caso".
En general, cuando decimos "complejidad" a secas, casi siempre nos
referimos a la complejidad en el peor caso. Es decir... cunto va a tardar el
algoritmo como mucho.
Asntotas y rdenes de complejidad
Ya tenemos una ligera idea informal de qu es la complejidad. Pero entonces
Cmo se comparan unos algoritmos con otros? Bueno... la idea de la
complejidad de un algoritmo, es conocer cmo se comporta el tiempo de
ejecucin conforme la talla del problema va creciendo.... especialmente
para valores muy grandes... lo ms grandes que podamos imaginar, y
especialmente en el peor de los casos.
En ese contexto de tallas muy grandes podemos hacer otra "simplificacin",
por as decirlo. El hecho es que podemos encontrar ciertas similitudes entre
las funciones que definen la complejidad de los algoritmos. Por ejemplo, si
comparamos todos los algoritmos cuya complejidad es lineal (es decir, una
recta... por ejemplo: 10n+3, 32n+12, 56n+1... o cualquier otro) y los
comparamos con todos aquellos cuya complejidad es cuadrtica (Por
ejemplo, 2n2+3, 4n2+n, 6n2+4n+3...) y dibujamos sus funciones de
complejidad en grfica. Observaremos que conforme n se va haciendo
grande, tienen un patrn de crecimiento bien diferenciado.
En ese contexto, podemos agrupar todas las complejidades que crecen igual
en el mismo saco. A ese saco le vamos a llamar orden de complejidad.
Hablando un peln ms formalmente, para todas las funciones que
agrupemos en un mismo orden, encontraremos una asntota que al

multiplicarla por un valor nos acote a nuestra funcin superiormente cuando


estemos tratando el peor caso.
Por ejemplo, todas las complejidades cuadrticas estn acotadas
asintticamente por n2. Eso quiere decir que para cualquiera de las
complejidades cuadrticas que hemos visto antes, por ejemplo 6n2+4n+3,
existe un valor real c que hace que 6n2+4n+3 cn2 cuando n se hace muy
grande, es decir, cuando n

De esta manera, la complejidad suele clasificarse en una serie de rdenes


comunes.
Como ves, finalmente el concepto de complejidad se nos simplifica mucho.
En lugar de hallar los tiempos exactos que tarda un algoritmo en solucionar
los problemas, con lo que nos quedamos en con una asntota que
representa a todos los algoritmos cuyo tiempo crece de igual forma cuando
la talla del problema tiende a infinito. Eso hace que el clculo de la
complejidad se simplifique mucho. Si no queremos hallar la funcin de
complejidad real (y casi nunca queremos), sino el orden al que pertenece la
complejidad del algoritmo, a la hora de hallarla, prcticamente ni siquiera
tenemos que contar las instrucciones... Cada secuencia de instrucciones se
cuenta como una sola instruccin. Lo que influye en la complejidad son
principalmente los bucles y las sentencias de seleccin que tienen efecto
sobre los bucles. En los algoritmos recursivos, la cosa se complica un poco
ms... Pero como hemos dicho al principio, el clculo de la complejidad de
un algoritmo queda fuera del alcance de ste artculo.
Cuando decimos que la complejidad de un algoritmo es de un orden
concreto, por ejemplo n2, podemos estar seguros de que para cualquier
valor de n, y por muy mal que nos vayan las cosas (peor) caso, el valor que
obtengamos nunca ser mayor que cn2, siendo c un real mayor que 1.
rdenes de complejidad ms comunes
Como ya hemos mencionado, la complejidad, digamos "real" en el peor caso
de los algoritmos puede enmarcarse en un "orden de complejidad". Dicho de
otra manera, la complejidad de un algoritmo "crece como" el representante
de su orden cuando la talla del problema se hace muy grande.
Bien... pues los rdenes de complejidad que se suelen manejar son stos, de
mejor a peor

Resumen, conclusiones y recomendaciones


Bueno... al final no ha sido tan dificil. Resulta que un algoritmo que resuelve
un problema con una determinada talla (por ejemplo, n) tarda un tiempo, en
general, mayor en obtener la solucin cuanto mayor es esa talla n (cosa que
resulta obvia). La complejidad es una medida que nos da una idea de cmo
es ese crecimiento, resultando que para la mayor parte de algoritmos, ese
crecimiento se puede enmarcar en un determinado "orden", ya que todas
las funciones que estn en un orden crecen de manera similar cuando los
valores de la talla se van haciendo grandes.
Para cada algoritmo, son interesantes un par de medidas de complejidad:
en el peor caso (que sealamos con la notacin O (Omicron, "Big-O"), y en
el mejor, para el que utilizamos la notacion (Omega). En especial, suele
ser ms imprescindible conocer el peor caso, ya que nos da una idea de qu
es lo que puede pasar cuando las cosas van realmente mal.
Toda esta teora de la complejidad, que tuvo un gran auge hace algunos
aos, ha sido criticada desde muchos puntos de vista. La verdad es que es

muy til en un nivel terico, pero un nivel prctico tampoco conviene


obsesionarse demasiado. Es necesario tener en cuenta que todo esto tiene
que ver con lmites cuando el tamao de los problemas es muy grande y
teniendo en cuenta el peor de los casos. A efectos prcticos, si estamos
seguros de que el tamao de nuestros problemas es pequeo, incluso un
algoritmo con una complejidad "intratable" puede obtener soluciones en un
tiempo razonable.
Adems, muchos algoritmos con una elevada complejidad en el peor caso,
resulta que no se comportan tan mal en la prctica, ya que muchas veces
los problemas que se resuelven con l no son el peor caso. A veces, incluso
se manipulan un poco los problemas para que nunca presenten el peor
caso, o se aplican tcnicas que ahorren trabajo al algoritmo (heursticas,
podas, etc). La complejidad del algoritmo es la misma, pero en promedio se
comportan mucho mejor que lo que cabra esperar vista su complejidad en
el peor caso, simplemente porque no se suele llegar al peor caso.
Por ltimo, comentar que existen otras medidas de complejidad que las
vistas hasta aqu, que son simplemente mximos y mnimos tericos cuando
la talla del problema tiende a un nmero muy grande. Y tambin, cuando un
algoritmo se quiere probar "en la prctica" se aplican otran tcnicas,
principalmente teniendo en cuenta la probabilidad que tiene un problema en
aparecer o no. Por ejemplo, los algoritmos de ordenacin de arrays ms
sencillos tienen una complejidad mxima terica de O(n 2). Uno de los peores
casos que se pueden presentar es que el array est ordenado
completamente al revs de cmo queremos... pero en una aplicacin real
es muy poco probable que esto ocurra... con lo que a veces la realidad no
es tan mala, especialmente cuando los problemas no tienen una talla muy
elevada.
Sobre la complejidad espacial que se mencionaba al principio podemos
actuar de la misma manera, solo que en lugar de contar instrucciones,
contamos las piezas de memoria dinmica que se utilizan. Esto es, las que
se solicitan del espacio del heap, de memoria secundaria, o las que que
quedan atrapadas en la. Sin embargo, su estudio suele tener menos inters,
porque el tiempo es un recurso mucho ms valioso que el espacio.
Este artculo est, con seguridad, repleto de incorrecciones formales. Lo
sabemos... pero como decamos al principio, no es nuestro objetivo describir
formalmente la complejidad, sino simplemente intentar transmitir una idea
intuitiva de lo que representa.

You might also like