0% encontró este documento útil (0 votos)
2 vistas10 páginas

Python_Tema6_Parte1_Complejidad-algoritmo_v1

El documento presenta una introducción a la complejidad algorítmica en Python, explicando qué es un algoritmo y cómo medir su eficiencia en términos de tiempo y recursos. Se discuten diferentes órdenes de complejidad, como constante, lineal, polinómico, logarítmico y exponencial, así como su impacto en el rendimiento de los algoritmos. Además, se enfatiza la importancia de categorizar algoritmos mediante la notación Big-O para facilitar su comparación y optimización.

Cargado por

Aklre Kigo
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
2 vistas10 páginas

Python_Tema6_Parte1_Complejidad-algoritmo_v1

El documento presenta una introducción a la complejidad algorítmica en Python, explicando qué es un algoritmo y cómo medir su eficiencia en términos de tiempo y recursos. Se discuten diferentes órdenes de complejidad, como constante, lineal, polinómico, logarítmico y exponencial, así como su impacto en el rendimiento de los algoritmos. Además, se enfatiza la importancia de categorizar algoritmos mediante la notación Big-O para facilitar su comparación y optimización.

Cargado por

Aklre Kigo
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 10

IBM SkillsBuild | Introducción a Python

Programando en Python
Complejidad de los algoritmos

1
IBM SkillsBuild | Introducción a Python

Índice
Introducción 3
¿Qué es un algoritmo? 4
¿El tamaño importa? 4
La complejidad algorítmica no es un número. Es una función 4
Código y Complejidad 5
Escenario de peor caso 6
Órden de Complejidad 6
Órden de Complejidad más conocidas 7

Constante: 7

Lineal: 8

Polinómico: 8

Logarítmico: 8

Enelogarítmico: 9

Exponencial: 9
Comparación 10

2
IBM SkillsBuild | Introducción a Python

Introducción

Cuando hablamos de la complejidad de un algoritmo,


nos referimos en realidad a una métrica teórica que
mide la eficiencia computacional de un algoritmo. Si
tenemos varios algoritmos que solucionan un mismo
problema, entonces esta métrica nos ayudará a
definir cuál de los algoritmos es mejor en términos
computacionales.

Aunque no es un concepto difícil de entender, la


obtención y el estudio de la complejidad requieren
ciertas destrezas matemáticas. En esta sección
vamos a exponer de manera sencilla la complejidad
algorítmica, los tipos de complejidad y ejemplos en
código Python.

3
IBM SkillsBuild | Introducción a Python

¿Qué es un algoritmo?
De todas estas características las que podemos
variar para medir nuestra complejidad serían los
datos de entrada. Ya que no es lo mismo, en un
algoritmo de ordenamiento, ordenar 10 elementos
En primer lugar, hablemos de Algoritmo. Un
que ordenar 1.000.000 de elementos. El algoritmo
algoritmo es una secuencia de instrucciones cuyo
debería poder ordenar los elementos sin importar el
objetivo es la resolución de un problema. Existen
tamaño del vector, pero sí incide directamente en el
muchos problemas que tiene algoritmos que los
tiempo en resolver el problema.
solucionen. Además, un mismo problema puede
tener varias soluciones (¿o no tener ninguna?). Si Con esto podemos empezar a medir los distintos
tenemos varias soluciones de un mismo problema, algoritmos de ordenamiento. Si ordenamos un vector
¿Cuál sería la mejor solución? Para eso necesitamos de diez millones con varios algoritmos y vemos cuál
evaluar dicho algoritmo, al resultado de la evaluación se demora menos, podríamos decir cuál tiene mayor
lo llamaremos complejidad algorítmica. o menor complejidad algorítmica.

Para medir un algoritmo podemos tratarlo desde dos


puntos de vista. Bien sea quien resuelva el problema La complejidad algorítmica
en menos tiempo o quien utilice menos recursos del
sistema. A la idea del tiempo la no es un número. Es una
llamaremos complejidad temporal y a la de recursos
del sistema la llamaremos complejidad espacial.
función
De los dos tipos mencionados, la de menos
Ahora, consideremos que hacemos experimentos del
relevancia es la de complejidad espacial debido a los
algoritmo con 10.000.000 de entradas. Si lo
altos recursos que puede tener una máquina.
realizamos en un ordenador muy potente la
Además, el tiempo es mucho más valioso. Podemos
respuesta del programa sería obviamente mucho
decir que, de los dos, el tiempo es el único que no se
más rápido que en un ordenador con pocos recursos.
puede comprar. Así que simplemente cuando nos
Así que el algoritmo va a tener siempre un tiempo de
referimos a complejidad algorítmica, nos estamos
respuesta diferente para cada ordenador.
refiriendo a la complejidad temporal.
Para solucionarlo no mediremos el tiempo que se
Básicamente la medición del algoritmo consiste en
tarda en responder un algoritmo. Más bien vamos a
medir cuánto tarda en resolver un problema.
contar el número de instrucciones, suponiendo que
cada instrucción se ejecuta en un mismo tiempo
¿El tamaño importa? constante. De esta manera mediremos cuántas
instrucciones necesarias se toma el algoritmo para
resolver el problema con respecto al tamaño del
Hablemos de algunos conceptos que poseen todos
problema.
los algoritmos.

Durante su proceso, digamos un algoritmo de


ordenamiento, posee una serie de instrucciones que
se repiten, se le conocen como bucles. También una
serie de elecciones o comparaciones, (if.. else..) que
hacen que siga ciertas instrucciones o no siga otras.
Todos estos elementos forman parte del algoritmo.
Poseen, también, datos de entrada y datos de salida.
4
IBM SkillsBuild | Introducción a Python

Analicemos el siguiente código escrito en Python: Lo que interesa es saber cómo puede crecer en
unidades de tiempo la resolución de un problema. En
este ejemplo es claro que el tiempo crece
def codigo_1( number ):
linealmente con respecto al valor de entrada.
a = 0
for j in range(1, number+1):
a += a + j Código y Complejidad
for k in range(number, 0, -1):
a -= 1 Es posible calcular visualmente la complejidad de
a *= 2 algunos algoritmos sencillos. Veamos algunos
return a ejemplos:

def codigo_2():
En este algoritmo tenemos unas instrucciones y a = 0
varios bucles. Empecemos con contar las a -= 1
instrucciones. a *= 2

Tenemos una asignación de la variable a, así que


tenemos 1 instrucción.
En el Código 2 la complejidad sería:
Instrucciones = 1
F(x) = 3
El siguiente es un bucle con una instrucción dentro.
Dependiendo del valor de la variable $number, se
realiza una instrucción n veces. Por ejemplo, def codigo_3( number ):
si $number tiene el valor de 3 entonces las a = 0;
instrucciones que se realizan son 3 veces. Entonces
for j in range(1, number+1):
tenemos:
for k in range(1, number+1):
Instrucciones = (1)+(n) a += a + ( k*j )

Instrucciones = n+1 return a

En el segundo bucle sucede lo mismo. Pero esta vez


son 2 instrucciones dentro del ciclo de código. El
número de instrucciones quedaría:
En el código 3 tenemos un bucle anidado. Cada vez
que ejecute un ciclo el otro se ejecuta n veces
Instrucciones = 2n+n+1 también. Lo cual sería n veces n. La complejidad
quedaría:
Instrucciones = 3n+1
F(x) = n2+1
Entonces la complejidad algorítmica
sería 3n+1 porque es el número de instrucciones que
tiene que realizar para solucionar el problema.

5
IBM SkillsBuild | Introducción a Python

Si graficamos estas 3 funciones, el código 1, 2 y 3. Dependiendo de los valores que se guarden en el


Podemos ver exactamente cuál sería el que posee vector, así será el tiempo que dure el algoritmo en
menor complejidad algorítmica: resolver el problema. Si el array es una secuencia de
números enteros, entonces solo hará falta una
iteración. Si es una lista de números impares,
entonces recorrerá todas las iteraciones.

En el mejor de los escenarios el número par será el


primero de la lista, lo que concluiría el algoritmo. En
el peor caso ni siquiera tenga un número par, porque
recorrería todas las instrucciones.

Para el mejor caso tendríamos una complejidad


algorítmica:

F(x)=1

Para el peor de los casos la complejidad algorítmica


sería:
Esto nos deja que independientemente de los
valores, resulta evidente que, cuantos más datos, la F(x)=n
curva se va haciendo cada vez más grande. Esto es lo
Para expresar el peor caso usaremos una notación
que realmente nos interesa ver en una complejidad
conocida como “O Grande” y se escribe:
algorítmica, cómo se comporta el algoritmo con
volúmenes de entradas grandes en el tiempo.
O(n)
Escenario de peor caso
Que significa complejidad en el peor caso. Se
Algunos algoritmos pueden tener distintos tiempos escribe como “O” pero en realidad es la letra griega
de ejecución, teniendo el mismo tamaño de los datos Omicron.
y los mismos recursos computacionales. Esto es
debido a que, dependiendo de los datos, a veces se
llegue a una solución en la primera iteración, o bien
Órden de Complejidad
tener que recorrer todos los datos.
Hasta aquí, es posible medir cualquier algoritmo.
El siguiente código tiene como fin encontrar el primer
Pero incluso así es complicado comparar unos
número par de una lista de números:
algoritmos con otros. Además, se requiere poder
categorizar lo complejo que es un algoritmo con
def codigo_4(array): respecto a otros. Para esto recurriremos al orden de
for k in range(len(array)): complejidad.
if( array[k] % 2 == 0 ):
return k Como vimos antes. Para medir un algoritmo
necesitamos recurrir al escenario de peor caso y con
return null un gran volumen de datos.

6
IBM SkillsBuild | Introducción a Python

Viéndolo de esta manera podríamos simplificar las Cuando nos advierten de una complejidad
ecuaciones de Big-O eliminando algunas algorítmica de un algoritmo podemos tener una idea
características que en ingreso masivo de datos son de cómo será su comportamiento.
irrelevantes.
Si por ejemplo tenemos un algoritmo de
Si comparamos varios algoritmos tales como: orden , entonces podemos
definir su orden de cualquiera de las siguientes
O(3n+1)
formas:
O(20n)

O(15n+150)

O(n)
Orden de complejidad más
conocidas
Podemos ver en sus gráficas que, sin importar la
variable que corta al eje Y o la pendiente de la curva, Constante:
todas crecen con la misma inclinación. Todas estas
Es la más sencilla y siempre presenta un tiempo de
de ecuaciones podemos agruparlas y referirnos a
ejecución constante. Ejemplo:
ellas como orden Lineal.

Lo mismo podemos hablar de las funciones


def constante():
cuadráticas, veamos el siguiente grupo:
x = 50
O(n2+27) ++x
return x
O(20n2+3)

O(n2+n+45)

O(100n2+101n)

A pesar de que sus correspondientes gráficas tengan


inicios y posiciones diferentes, todos son una
parábola y tendrán un comportamiento similar con
respecto al aumento de la cantidad de entradas.
Estas presentan un comportamiento muy diferente al
conjunto anterior. Este grupo de O grandes las
llamaremos de orden cuadrática. También las
podemos expresar como:

O(100m2+101n+) € O(n2)

De esta manera podemos clasificar a un algoritmo en


un grupo concreto y resultará mucho más fácil y
rápido ver la complejidad de un algoritmo.

7
IBM SkillsBuild | Introducción a Python

Lineal: Ejemplos:

El tiempo crece linealmente mientras crece los datos.


Ejemplo: def polinomico(number):
x = 0
for i in xrange(1,number):
def lineal(number): for j in xrange(1,number):
result = 0 x += i + j
for x in range(0, number):
++result for i in xrange(1,number):
for j in xrange(1,number):
return result for k in xrange(1,number):
x += i * j * k

return x

Polinómico:
Son los algoritmos más comunes. Cuando c es 2 se Logarítmico:
le llama cuadrático, cuando es 3 se le llama cúbico, y
No suelen ser muchos. Estos algoritmos indican que
en general, polinómico. Cuando n es muy grande
el tiempo es menor que el tamaño de los datos de
suelen ser muy complicados. Estos algoritmos suelen
entrada. No importa indicar la base del logaritmo. Un
tener bucles anidados. Si tienen 2 bucles anidados
ejemplo es una búsqueda dicotómica.
sería un cuadrático.

8
IBM SkillsBuild | Introducción a Python

Este algoritmo busca un elemento en un array No se incluye el código debido a las distintas
ordenado dividiendo el array en 2 mitades, identifica versiones, estudios y discusiones de este algoritmo.
en cuál de las mitades se encuentra, luego divide esa Pero compartiremos el comportamiento de este
parte en 2 mitades iguales y busca nuevamente hasta orden de complejidad:
encontrar el elemento, es un algoritmo recursivo:

def bin(a,x,low,high):
ans = -1
if low==high: ans = -1
else:
mid = (low+((high-low)//2))
if x < a[mid]: ans = bin(a,x,low,mid)
elif x > a[mid]: ans =
bin(a,x,mid+1,high)
else: ans = mid
return ans

Exponencial:
Es una de las peores complejidades algorítmicas.
Sube demasiado a medida que crece los datos de
entrada. Puede verse en la Figura como crece una
función de este tipo. Un ejemplo de este código es la
solución de Fibonacci, el cual genera bucles 2
recursividades en cada ejecución. Ejemplo:

Enelogarítmico:
def exponencial(n):
Tan bueno como el anterior, en este orden
if n==1 or n==2:
encontramos el algoritmo QuickSort. El ejemplo
return 1
podemos verlo en Wikipedia en este return exponencial(n-1)+exponencial(n-
enlace https://en.wikipedia.org/wiki/Quicksort. 2)

9
IBM SkillsBuild | Introducción a Python

Si nos encontramos con una función con complejidad


cuadrática (O(n2)) o exponencial (O(2n)) por regla
general será señal de que el algoritmo necesita una
revisión urgente, y mejor no utilizarlo.

Lo interesante de esta notación es que nos permite


comparar varios algoritmos equivalentes sin
preocuparnos de hacer pruebas de rendimiento que
dependen del hardware utilizado. Es decir, ante
resultados equivalentes podemos elegir el algoritmo
de mayor rendimiento, que lo será siempre
independientemente del hardware si el conjunto de
datos es lo suficientemente grande (en conjuntos
pequeños un hardware más rápido puede dar
resultados más rápidos para un algoritmo menos
eficiente, pero a medida que el conjunto crece ya no
será así).

Comparación Por eso, a partir de ahora, cuando veamos que una


función documenta explícitamente su complejidad
usando la notación Big-O, prestaremos mucha
Para resaltar el nivel de importancia de categorizar atención y deberemos tener en cuenta las
un algoritmo en un orden de complejidad, tenemos implicaciones que puede tener en nuestra aplicación
que ver en realidad hasta qué punto pueden ser el hecho de utilizarla. Del mismo modo, cuando
complejos los algoritmos. Para compararlos entre sí creemos un algoritmo para resolver un problema en
supongamos que todos ellos requieren 1 hora de nuestra aplicación, es interesante anotar en la
ordenador para resolver un problema de tamaño documentación del mismo (aunque sea en los
N=100. comentarios de la cabecera) cuál es la complejidad
algorítmica del mismo en notación Big-O. Eso
O(f(n)) N=100 t=2h N=200 ayudará a cualquier programador que venga detrás,
log n 1h 10000 1.15 h tanto a usarlo como a tener que optimizarlo, y sabrá
n 1h 200 2h cuál es la lógica a batir.
n log n 1h 199 2.30 h
Aquí tenemos una tabla muy completa con la
n 2
1h 141 4h
complejidad de los principales algoritmos para
n3 1h 126 8h estructuras de datos, ordenación de matrices,
2n 1h 101 1030 h operaciones en grafos y operaciones de montón
(heap).

Como podemos observar, a medida que aumenta la


complejidad, el tiempo necesario para completar la
tarea crece mucho, pudiendo llegar a aumentar
enormemente en algunos casos en cuanto hay más
datos a manejar.

10

También podría gustarte