Vous êtes sur la page 1sur 20

Los Algoritmos

Una vez que tenemos un algoritmo que resuelve un problema y podemos decir que es de alguna manera
correcto, un paso importante es tener idea de la cantidad de recursos, como tiempo de procesador o espacio
en la memoria principal que requerir.
Los objetivos del anlisis de algoritmos son:

Conocer los factores que influyen en la eficiencia de un algoritmo.

Aprender a calcular el tiempo que emplea un algoritmo.

Aprender a reducir el tiempo de ejecucin de un programa (por ejemplo, de das o aos a

fracciones de segundo).

Factores que influyen en la eficiencia


de un algoritmo
Podemos tomar en cuenta muchos factores que sean externos al algoritmo como la computadora donde se
ejecuta (hardware y software) o factores internos como la longitud de entrada del algoritmo. Veamos algunos
de estos factores.

El Hardware. Por ejemplo: procesador, frecuencia de trabajo, memoria, discos, etc.

El Software. Por ejemplo: sistema operativo, lenguaje de programacin, compilador, etc.

La longitud de entrada. El enfoque matemtico considera el tiempo del algoritmo como una funcin
del tamao de entrada. Normalmente, se identifica la longitud de entrada (tamao de entrada), con el
nmero de elementos lgicos contenidos en un ejemplar de entrada, por ejemplo: en un algoritmo
que calcula el factorial de un nmero, la longitud de entrada sera el mismo nmero, porque no es lo
mismo calcular el factorial de 4 que calcular el factorial de 1000, las iteraciones que tenga que hacer
el algoritmo depender de la entrada. De igual manera se puede considerar como longitud de
entrada: al tamao de un arreglo, el nmero de nodos de una lista enlazada, el nmero de registros
de un archivo o el nmero de elementos de una lista ordenada). A medida que crece el tamao de un
ejemplar del programa, generalmente, crece el tiempo de ejecucin. Observando cmo vara el
tiempo de ejecucin con el tamao de la entrada, se puede determinar la tasa de crecimiento del
algoritmo, expresado normalmente en trminos de n, donde n es una medida del tamao de la
entrada. La tasa de crecimiento de un problema es una medida importante de la eficiencia ya que
predice cunto tiempo se requerir para entradas muy grandes de un determinado problema. Para
que un algoritmo sea eficiente, se debe optimizar el tiempo de ejecucin y el espacio en la memoria,
aunque se producir la optimizacin de uno a costa del otro.

Anlisis de Algoritmos
El anlisis de algoritmo que hacemos toca nicamente el punto de vista temporal (tiempo de ejecucin de un
algoritmo) y utilizamos como herramienta el lenguaje de programacin Java.
Es difcil realizar un anlisis simple de un algoritmo que determine la cantidad exacta de tiempo requerida
para ejecutarlo. La primera complicacin es que la cantidad exacta de tiempo depender de la
implementacin del algoritmo y de la mquina real en que se ejecuta. El anlisis normalmente debe ser
independiente de la computadora (hardware y software) y del lenguaje o mquina que se utilice para
implementar el algoritmo. La tarea de calcular el tiempo exacto requerido suele ser bastante pesado.
Un algoritmo es un conjunto de instrucciones ordenados de manera lgica que resuelven un problema. Estas
instrucciones a su vez pueden ser: enunciados simples (sentencias) o enunciados compuestos (estructuras de
control). El tiempo de ejecucin depender de como est organizado ese conjunto de instrucciones, pero
nunca ser constante.
Es conveniente utilizar una funcin T(n) para representar el nmero de unidades de tiempo (o tiempo de
ejecucin del algoritmo) tomadas por un algoritmo de cualquier entrada de tamao n. La evaluacin se podr
hacer desde diferentes puntos de vista:

Peor caso. Se puede hablar de T(n) como el tiempo para el peor caso. Se trata de aquellos
ejemplares del problema en los que el algoritmo es menos eficiente (no siempre existe el caso peor).
Ejemplos: insertar al final de una lista, ordenar un vector que est ordenado en orden inverso, etc.
Nos interesa mucho.

Mejor caso. Se habla de T(n) como el tiempo para el mejor caso. Se trata de aquellos ejemplares del
problema en los que el algoritmo es ms eficiente; por ejemplo: insertar en una lista vaca, ordenar
un vector que ya est ordenado, etc. Generalmente no nos interesa.

Caso medio. Se puede computar T(n) como el tiempo medio de ejecucin del programa sobre todas
las posibles ejecuciones de entradas de tamao n. El tiempo de ejecucin medio es aveces una
medida ms realista del rendimiento en la prctica, pero es, normalmente, mucho ms difcil de
calcular que el tiempo de ejecucin en el pero caso, ya que requiere definir una distribucin de
probabilidades de todo el conjunto de datos de entrada, el cul tpicamente es una tarea difcil.

Funcin de Complejidad
Definicin
La funcin de complejidad de un algoritmo es el nmero de operaciones elementales que utiliza un algoritmo
cualquiera para resolver un problema de tamao n. Matemticamente se define la Funcin de complejidad asi:
Sea A un algoritmo, la funcin de complejidad del algoritmo A T(n) se define como el nmero mximo de
operaciones elementales que utiliza el algoritmo para resolver un problema de tamao n.
T(n) = Max {nx: nx es el nmero de operaciones que utiliza A para resolver una instancia x de tamao
n}
Nota: Una operacin elemental es cualquier operacin cuyo tiempo de ejecucin es acotado por una

constante (que tenga tiempo constante). Por ejemplo: una operacin lgica, una operacin aritmtica,
una asignacin, la invocacin a un mtodo.

Operaciones elementales
Que es una operacin elemental? Una operacin elemental, tambin llamado operador bsico es cualquier
operacin cuyo tiempo de ejecucin es constante, es decir, es una operacin cuyo tiempo de ejecucin
siempre va a ser el mismo.
Tipos de Operaciones Elementales

Operacin Lgica: Son operaciones del tipo a > b, o por ejemplo los indicadores que se suelen
utilizar en los condicionales que si se cumpla esta condicin o esta otra haga esto. Ese o es una
operacin lgica.

Operacion Aritmetica: Son operaciones del tipo a + b, o a / b, etc.

Asignacin: Es cuando asignamos a una variable un valor, ejemplo: int a = 20+30, el igual (=) en este
caso es la operacin de asignacin.

Invocacin a un Mtodo: Como su nombre lo dice es cuando llamamos, cuando invocamos a un


mtodo.

Clculo del T(n)


Para hallar la funcin de complejidad (t(n)) de un algoritmo se puede evaluar el algoritmos desde tres puntos
de vista:

Peor Caso: Se puede hablar de T(n) como el tiempo de ejecucin para el peor de los casos, en
aquellos ejemplares del problema en el que el algoritmo es Menos Eficiente.

Caso Medio: Se puede comportar el T(n) como el tiempo medio de ejecucin del programa sobre
todas las posibles ejecuciones de entrada de tamao n. Es una medida ms realista del rendimiento
del algoritmo en la prctica, pero es mucho ms difcil del clculo, ya que requiere una distribucion de
probabilidades de todo el conjunto de entrada lo cual es una tarea difcil.

Mejor Caso: Se puede hablar de T(n) como el tiempo de ejecucin para el mejor de los casos, en
aquellos ejemplares del problema en el que el algoritmo es Ms Eficiente.

Lo ideal sera poder evaluar el algoritmo en el caso promedio, pero por el nivel de operaciones y dificultad que
conlleva este, el estudio de la complejidad de los algoritmos se evala en el peor de los casos.
Para calcular el T(n), se deben calcular el nmero de operaciones elementales de un algoritmo, las cuales
estan dadas por: Sentencias consecutivas, condicionales y ciclos.

Calcular T(n) para Sentencias


Consecutivas
Las sentencias consecutivas como su nombre lo dicen son aquellas que tienen una secuencia, que van una
detrs de otra, y se derivan en dos casos:
1. Si se tiene una serie de instrucciones consecutivas:
Sentencia 1
Sentencia 2
.
.
.
Sentencia k

n1 operaciones elementales
n2 operaciones elementales

nk operaciones elementales

2. Procedimientos:
Procedimiento 1
Procedimiento 2
.
.
.
Procedimiento k

f1(n)
f2(n)

fk(n)

Calcular T(n) para Ciclos


Para hallar la complejidad computacional de un ciclo existen, los siguientes casos:
Caso A: Cuando los incrementos o decrementos son de uno en uno y son constantes.
El ciclo While o Mientras es el bsico, a partir de l se analizan los dems ciclos.
Codigo base:
i1

mientras i <= n Haga


Proceso
# De Operaciones (Formula) = 1 + (n+1) * nc + n * np
Siendo:
nc: Nmero de operaciones de la condicin del ciclo.
np: Nmero de operaciones del ciclo.
Ejemplo: Hallar la funcin de complejidad del siguiente algoritmo:
lineas
1
2
3
4
5
6

Codigo

# De Operaciones

A= 0
---------------------------------- >
i=1
---------------------------------- >
Mientras (i <= n)
--------------- >
A= A+ i
--------------- >
i=i+1
--------------- >
imprima A
------------------------- >

1
1
nc = 1
2
2 np = (2+2) = 4
1

La complejidad se analiza por lineas, de la siguiente forma:


Lineas

Complejidad

de 2 a 5
+ ( n + 1 ) * 1 + (n * 4)

1 + ( n + 1 ) * nc + (n * np)

1 + n + 1 + 4n
5n + 2
de 1 a 6

5n + 2 + 2

Finalmente:
T(n) = 5n + 4
Ejemplo: Hallar la funcin de complejidad del siguiente algoritmo.
lineas
1
2
3
4
5

Codigo

# De Operaciones

x = 1 --------------------------------->
i = 1 ---------------------------------->
Mientras (i <= n) ----------------->
x = x * i ------------------->
i = i + 1 -------------------->

1
1
nc = 1
2
2 np = (2+2) =

4
6
7
8
Lineas
de 2 a 5

de 6 a 7

de 1 a 8

Si (x > 100) entonces ----------->


x = 100 -------------------->
imprima x -------------------------->
Complejidad
1 + (n+1)nc + n * np
1 + (n+1)1 + n * 4
1 + n + 1 + 4n
5n + 2
nc + max
1+1
2
(5n + 2) + (2) + 1 + 1

nc = 1
1
1

5n + 6
Finalmente:
T(n) = 5n + 6
Ciclo For o Para:
Codigo base:
Para (i1 ; i <=n ; i++)
Proceso
# De Operaciones (Formula) = 1 + (n+1) * nc + n * (np+1)
Siendo:
nc: Nmero de operaciones de la condicin del ciclo.
np: Nmero de operaciones del ciclo.
Ejemplo: Hallar la funcin de complejidad del siguiente algoritmo.
lineas
1
2
3
4

Codigo

# De Operaciones

f = 0 --------------------------->
Para (i = 1 ; i <=n ; i++) -->
f = f * i -------------->
imprima f ------------------->

Lineas

1
nc = 1
2 operaciones ---> np = 2
1

Complejidad

de 2 a 3

1 + (n+1)nc + n(np + 1)
1 + (n+1)1 + n(2 + 1)
1 + n + 1 + n(3)
1 + n + 1 + 3n
4n + 2

de 1 a 4

(4n + 2) + 2
4n + 4

Finalmente:
T(n) = 4n + 4
Ejemplo:
NOTA PARA TENER EN CUENTA:
Para ciclos ya sean MIENTRAS(while) O PARA(for), observamos que cada ciclo tiene un lmite superior que
define hasta donde va a iterar(repetir) ya sea definido estrictamente menor (<) que n, o en dado caso que n
sea una constante ; por consecuencia debemos usar la siguiente frmula, el cual nos permite aclarar el valor
real de n; es decir, cuantas veces itera el ciclo (# de veces que ingresa al ciclo)
FORMULA: n = Ls - Li + 1
Siendo:
Ls: Limite superior del ciclo. (Hasta donde itera)
Li: Limite inferior del ciclo. (Desde donde inicializa)
En este ejemplo tenemos el ciclo Para (i = 1 ; i < n ; i++).

Como observamos el lmite inferior(Li) del ciclo es 1 porque inicializa desde 1; el lmite superior(Ls) es (n-1)
porque va hasta i estrictamente menor (<) que n; es decir el ciclo ingresara n veces menos 1 por que es
estrictamente menor (<).
En los ejemplos anteriores, los ciclos tienen como limite superior n porque llegaba hasta i<=n, es decir
ingresaba las n veces al ciclo.
Para comprobar lo dicho en este caso, entonces usamos la frmula:
n = Ls - Li + 1
n = (n-1) - (1) + 1
n = n-1
En conclusin, como n = n-1 ; el nmero total de veces que se ingresa al ciclo es (n-1) veces; en
consecuencia reemplazamos el valor de n que es (n-1) en la complejidad.
lineas
1
2
3
4
Lineas

Codigo

# De Operaciones

f = 1 --------------------------->
1
Para (i = 1 ; i < n ; i++) -->
nc = 1
f = f * i -------------->
2 operaciones ---> np = 2
imprima f ------------------->
1
Complejidad

de 2 a 3

de 1 a 4

1 + (n+1)nc + n(np + 1) como n=(n-1) entonces


1 + ((n-1)+1)(1) + (n-1)(2 + 1)
1 + n + (n-1)(3)
1 + n + (3n - 3)
1 + n + 3n - 3
4n - 2
(4n - 2) + 2
4n

FInalmente:
T(n) = 4n
Caso B: Cuando los incrementos o decrementos dependen del valor que tome i.
While o Mientras:
Codigo base:
i1
mientras i <= n Haga
Proceso (i)

Siendo:
nc: Nmero de operaciones de la condicin del ciclo.

f(i): Funcin de complejidad del proceso.


For o Para
Codigo base:
Para (i1 ; i <=n ; i++)
Proceso (i)
Siendo:

nc: Nmero de operaciones de la condicin del ciclo.


f(i): Funcin de complejidad del proceso.
Ejemplo:
lineas
1
2
3
4
5
Lineas
de 3 a 4

de 2 a 4

Codigo

# De Operaciones

s = 0 ------------------------------------->
Para (i = 1 ; i <=n ; i++) -------------->
Para (j = 1 ; j<= i ; j++) ----->
s = s + 1 ------------->
imprima f -------------------------------->

1
nc = 1
nc = 1
2 operaciones ---> np = 2
1

Complejidad
1 + (n+1)nc + n(np + 1)
1 + (i+1)1 + i(2 + 1)
1 + i + 1 + i(3)
1 + i + 1 + 3i
4i + 2 -----> f(i)

Caso A n = i

4n + 2 + (2n^2) + 2n
(2n^2) + 6n + 2
de 1 a 5

(2n^2) + 6n + 2 + 2
(2n^2) + 6n + 4

En conclusion:
T(n) = 2n^2 + 6n + 4
CASO C: Cuando no sabemos cunto va a ser el incremento o decremento del proceso.
Codigo base:
mientras<Condicin> Haga
Proceso
# De Operaciones (Formula) = (nr + 1) * nc + (nr * np)
siendo:
nc: Nmero de operaciones de la condicin del ciclo.
np: Nmero de operaciones del ciclo.
nr: Nmero de veces que se repite el proceso, en s es una frmula que cumple las veces que se ejecuta el
proceso para todo nmero n.
Funcin Piso / Techo
Sabemos claramente que (5/4) es igual a 1.25
Funcion piso es aproximar el fraccionario a su ms cercano valor entero menor o igual a l, un ejemplo sera:

ahora bien si tomamos el mismo fraccionario y hallamos funcin techo sera aproximarlo a su ms cercano
valor mayor o igual a l, un ejemplo sera:

NOTA: Si tenemos un entero la funcin piso y techo es el mismo entero


Como hallar el nr?
Para permitirnos calcular t(n) o funcin de complejidad con un incremento no lineal ser incierto saber cual es
el nmero de veces que va a iterar el ciclo ya sea while o un for
Cuando un incremento por lo general no en todas las ocasiones sean de suma de 2 (contador=contador+2)
dentro del ciclo, el contador ir sumando de 2 en 2; el nr podra ser un fraccionario con numerador siempre n y
denominador la constante que se est sumando en este caso 2.
Ejemplo: Hallar la funcin de complejidad del siguiente algoritmo
lineas
1
2
3
4
5
6

Codigo

# De Operaciones

t = 0 ------------------------------------->
1
i = 1 ------------------------------------->
1
Mientras (i <= n)--------------------->
nc = 1
t = t + 1------------------------>
2
i = i + 2 ----------------------->
2
np = (2 + 2) = 4
imprima t ------------------------------>
1

Estudio para hallar nr se debe analizar la cantidad de veces que itera el bucle para cada valor de n:

Para para hallar nr se debe analizar la cantidad de veces que itera el bucle para cada valor de n. En este caso
es clave observar que la variable controladora del ciclo es i, y tiene incrementos de 2 en 2, por lo tanto,

Por tanto, la complejidad del algoritmo se calcula as:


Lineas

Complejidad

de 3 a 5

(nr + 1)nc + nr * (np)

de 1 a 6

Finalmente,

Ejemplo:
lineas
1
2
3
4
5
6

Codigo

# De Operaciones

t = 0 ------------------------------------->
1
i = 1 ------------------------------------->
1
Mientras (i <= n)--------------------->
nc = 1
t = t + 1------------------------>
2
i = i * 2 ----------------------->
2
np = (2 + 2) = 4
imprima t ------------------------------>
1

En este caso el ciclo mientras tiene incrementos en base 2 (i = i*2), por lo tanto nr es una expresin
logartmica dada por la formula:

Por tanto, la complejidad del algoritmo se calcula as:


Lineas
de 3 a 5

Simplificando la expresin,

de 1 a 6

Finalmente,

Complejidad
(nr + 1)nc + nr * (np)

Orden de Magnitud
(Notacin O Grande)
Cuando se trata de algoritmos, el clculo detallado del tiempo de ejecucin de todas las operaciones
primitivas llevara mucho tiempo. Adems, qu importancia tendra el nmero de instrucciones primitivas
ejecutadas por un algoritmo? Es ms til en el anlisis de algoritmos, ver la velocidad de crecimiento del
tiempo de ejecucin como una funcin del tamao de la entrada n, en lugar de realizar clculos detallados. Es
ms significativo saber que un algoritmo crece, por ejemplo, proporcionalmente a n, a razn de un factor
constante pequeo que depende del hardware o software y puede variar en un cierto rango, dependiendo de
una entrada n especfica. Esto lo que se conoce como orden de magnitud O(g(n)) o notacin asinttica o
notacin O grande. El orden de magnitud se utiliza para comparar la eficiencia de los algoritmos.
La notacin O grande es una tcnica utilizada para el anlisis de la complejidad computacional de un
algoritmo, este anlisis se centra en el trmino dominante (El trmino que ms aumenta), permitiendo as
ignorar constantes y trminos de orden menor.
Por ejemplo:

Definicin conceptual del Orden de


Magnitud
Sean f(n) y g(n) funciones definidas sobre enteros no negativos. Diremos que f(n) es O(g(n)) si existe un
nmero real constante c>0 y un entero constante n0>=1, tal que f(n)c*g(n) para todo entero n>=n0.
Por consiguiente, g(n) es un lmite superior para f(n), como se ilustra en la siguiente figura.

El orden de magnitud es ampliamente utilizado para caracterizar los tiempos de ejecucin en trminos de la
longitud de entrada n, el cual vara de problema en problema, pero es usualmente una nocin intuitiva del
tamao del problema.
Asimismo, el orden de magnitud nos permite ignorar factores constantes y trminos de orden menor y apuntar
a los componentes principales de una funcin que influyen en su crecimiento.
Cuando se dice que f(n) es del O(g(n)), se est garantizando que la funcin f(n) crece a una velocidad no
mayor que
g(n); as g(n) es una cota superior de f(n).

Propiedades del Orden de Magnitud


1. O( f(x) ) + k = O( f(x) )
2. O( k f(x) ) = O( f(x) )
3. O( f(x) ) * O( g(x) ) = O( f(x) * g(x) )
O( f(x) ) + O( g(x) ) = max ( O( f(x) ), O( g(x) ) )

Recursividad
Def: Es una tcnica de programacin en la cual un mtodo puede llamarse a s mismo, en la mayora de
casos un algoritmo iterativo es ms eficiente que uno recursivo si de recursos de la computadora se trata,
pero un algoritmo recursivo en muchos casos permite realizar problemas muy complejos de una manera ms
sencilla.
Reglas de la recursividad:
Para que un problema pueda resolverse de forma recursiva debe cumplir las siguientes 3 reglas:

Regla 1:Por lo menos debe tener un caso base y una parte recursiva.
Regla 2:Toda parte recursiva debe tender a un caso base.
Regla 3:El trabajo nunca se debe duplicar resolviendo el mismo ejemplar de un problema en llamadas
recursivas separadas.
Ejemplo: Calcular el factorial de un nmero.
FACTORIAL DE UN NMERO N
8! = 8 * 7!
7! = 7 * 6!
6! = 6 * 5!
.
.
En general,
n! = n * (n-1)!

Veamos un caso particular, calculemos el factorial de 5 ( 5! ):


factorial de 5 = 5 * 4! -------> factorial de 5 es igual 5 multiplicado por factorial de 4
factorial de 4 = 4 * 3! ------->factorial de 4 es igual 4 multiplicado por factorial de 3
factorial de 3 = 3 * 2!-------> factorial de 3 es igual 3 multiplicado por factorial de 2
factorial de 2 = 2 * 1!-------> factorial de 2 es igual 2 multiplicado por factorial de 1
factorial de 1 = 1 -------> factorial de 1 es 1 ------> caso base
Una implementacin en java seria:
public long factorial (int n){
if (n == 0 || n==1) //Caso Base
return 1;
else
return n * factorial (n - 1); //Parte Recursiva
}

Complejidad de un
Algoritmo Recursivo
Mtodo del rbol de recursin
Existen varios mtodos para calcular la complejidad computacional de algoritmos recursivos. Uno de me los
mtodos ms simples es el rbol de recursin, el cual esadecuado para visualizar que pasa cuando una
recurrencia es desarrollada. Un rbol de recursin se tienen en cuenta los siguientes elementos:
Nodo: Costo de un solo subproblema en alguna parte de la invocacin recursiva.
Costo por Nivel: La suma de los costos de los nodos de cada nivel.
*Costo Total: Es la suma de todos los costos del rbol.

Ejemplo. Utilizando el mtodo del rbol de recursin calcular la complejidad computacional del algoritmo
recursivo del factorial. Lo primero es calcular las operaciones elementales de cada linea:
public long factorial (int n){
#operaciones elementales
if (n == 0 || n==1) //Caso Base
3
return 1;
1
else
return n * factorial (n - 1); //Parte Recursiva
4
}

Para hallar la complejidad se debe resolver esta recurrencia:


T(n) = 7 + T (n - 1)
El rbol de recursin es el siguiente.

El costo total es la sumatoria de los costos de cada nivel:

Ejemplo
Utilizando el mtodo del rbol de recursin, calcular la complejidad computacional de la siguiente recurrencia:
T(n) = 2 T(n/2) + n

Para entender mejor el rbol de recursin anterior, ilustramos como sera cuando n = 8:

Finalmente, la complejidad de la recurrencia est dada por la suma de los costos de cada nivel del rbol:

nbsp;

Ejercicios Propues
Ca
1)
c=0
i=1
Mientras (i <
c=c
im
2)
a=0
i=1
Mientras (i <
a=a
im
3)
a=0
i=8
Mientras (i <
a=a
im
4)
a=0
i=3
Mientras (i <
a=a
im
5)
f=1
Para( i =
im
6)
f=6
Para(i =

imprima f
Respuestas:
1) T(n) = 5n +
2) T(n) = 5n 1
3) T(n) = 5n
4) T(n) = 5n 11

) T(n) = 2n 13
Ca
1)
s=0
Para( i = 1; i < n; i++)
Para( j = 1; j < i; j
P
im
2)
t=0
Para( i = 1; i <= n;
Para(
im
3)
t = 10
Para( i = 1; i <=
Para(
im
4)
t=0
Para( i = 1; i <= n; i++)
Para( j = 1; j <=
P
im
5)
t = 20
Para( i = 1; i <
Para(
imprima t
Respuestas:
1) T(n) = 6/5n3 21/2
2) T(n) = 5n2 + 4n + 4
3) T(n) = 2n2 2n + 4

) T(n) = 10n2 10
*E
Calcu
1)
i=0
s=0
Mientras (i <
s=s
im
2)
i=0
t=3
Mientras (i <
t=t
im
3)
i=n
t=0
Mientras (i
t=t

mprima t
*
Calcular la complejidad d
1) T(n) = 3T(n/4) +
2) T(n) = T(n/2) + 1
3) T(n) = 2T(n/2) + 1

Vous aimerez peut-être aussi