Está en la página 1de 16

UNIVERSIDAD NACIONAL DE TRUJILLO

FACULTAD DE CIENCIAS FÍSICAS Y MATEMÁTICAS


DEPARTAMENTO DE INFORMÁTICA

Algoritmia
Guía de Práctica para el Curso de Técnicas de
Construcción de Programas
SEMESTRE 2008 - I

Ms(c) Ricardo Manuel Guevara Ruiz


Docente del Curso

Jhon Anthony Alvarez Borja


Asistente de Cátedra del Curso
2

ALGORITMIA

1. INTRODUCCION
Es necesario, antes de comenzar el estudio de la algoritmia, entender que es lo que significan
y son los algoritmos. El termino algoritmo proviene del matemático persa al-Khowârizmî. Un
algoritmo puede ser definido como un conjunto finito de pasos finitos y bien establecidos
para la resolución de un problema. Los algoritmos pueden ser usados en diversas áreas
científicas en la actualidad, como la medicina, ingeniería, etc.; sin embargo, nosotros
estaremos interesados solo en los algoritmos que son implementados en un computador.

La ejecución de un algoritmo no debe implicar, por lo general, ninguna decisión subjetiva, ni


tampoco se debe hacer uso de la intuición. Para describir mejor lo anteriormente dicho, en
el caso de una receta de cocina, no podemos colocar indicaciones como: “agregar un poco de
sal”, o “hervir un tiempo prudente”, debido a la ambigüedad del lenguaje natural. Sin
embargo existen algoritmos que hacen uso de este tipo de instrucciones, pero que se
encuentran basados en niveles de probabilidad, estos algoritmos son llamados algoritmos
probabilísticos.

2. CONCEPTOS FUNDAMENTALES
Antes de adentrarnos más en el estudio de la algoritmia y la eficiencia de los algoritmos,
debemos conocer algunos conceptos los cuales son necesarios para comprender el contenido
de esta unidad
2.1. Algoritmia
Según Brassard y Bratley, quienes acuñaron el término “algoritmics” en 1988, “es el
estudio sistemático de las técnicas fundamentales utilizadas para diseñar y analizar
algoritmos eficientes”. Este estudio ha sido posteriormente ampliado en 1997,
considerando además que la determinación de la eficiencia de un algoritmo se podía
expresar en el tiempo requerido para la realización de la tarea computacional en
función del tamaño de la muestra e independientemente del ambiente en el que se
efectue.
2.2. Problemas y Ejemplares
a. Problema: Definimos como problema a lo que se trata de resolver mediante un
algoritmo. Por lo general, el problema objeto de un algoritmo, se encuentra en el
último nivel del diseño descendente de un problema más grande.
Ejm: Determinar los múltiplos de dos números positivos determinado.
b. Ejemplar: Un ejemplar es un caso particular dentro del dominio del problema.

Multiplos(4512,7411)    

Ejm: Según el ejemplo anterior:

Multiplos(-8541,-4885)     

Uno de los aspectos importantes entre las técnicas de construcción de programas es la
correctitud, y en base al cual tenemos que construir algoritmos que funcionen de
manera correctas con todos los casos del problema que queremos resolver. Para mostrar
que un algoritmo no es correcto solo basta con encontrar un ejemplar del problema
para el cual, el algoritmo no es capaz de encontrar una respuesta correcta. En base a lo
anterior podemos decir que un algoritmo puede rechazarse tomando como base un caso

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


3

de prueba. Sin embargo, a veces las limitaciones de hardware en un computador


(memoria, procesador, tamaño de registros, etc.) hacen que opere de manera incorrecta
y se arrojen resultados erróneos; y lo cual no debe ser confundido con la correctitud de
un algoritmo.
2.3. Operación elemental: Una operación elemental es aquella cuyo tiempo de ejecución se
puede acotar superiormente por una constante que solo dependerá de una
implementación en particular, así como de la maquina en la que se implemento, el
lenguaje de programación, etc. Por lo tanto, este tiempo no depende del tamaño del
ejemplar que se este considerando. En función de ello, para lograr determinar el tiempo
de ejecución de un algoritmo T(n), solamente contabilizaremos el número de
operaciones elementales ejecutadas y no el tiempo exacto requerido por cada una de
ellas. Esto permite que T(n) sea independiente del hardware del computador y del tipo
de implementación utilizada.
2.4. El tamaño de un ejemplar: El tamaño de un ejemplar, es representado por cualquier
entero positivo que mida de alguna forma el número de componentes de un ejemplar.
Por ejemplo:
o Cuando hablamos de algoritmo de ordenación, mediremos normalmente el
tamaño de un ejemplar por el número de elementos del arreglo que tenemos que
ordenar.
o En un algoritmo de búsqueda, el tamaño del ejemplar es el tamaño del vector
sobre el que se va a realizar la búsqueda.
o Si realizamos procesamiento en archivos, el tamaño del ejemplar sería el número
de registros que contiene dicho archivo.
o Cuando nos referimos a problemas que impliquen el trabajo con números
enteros, en este caso el tamaño del ejemplar estará representado por el valor de
dicho número en lugar del tamaño en bits que este ocupa. En otros casos, el
tamaño de un ejemplar podría ser la cantidad de dígitos de un número, como
por ejemplo en el algoritmo de inversión de cifras de un número, etc.

Debemos tener presente que, mientras el tamaño del ejemplar crezca, el computador
tardará mas tiempo en resolver el problema. Es decir, el tamaño del ejemplar afecta
directamente a la eficiencia de un algoritmo dado. El análisis de eficiencia, en
general se hace para valores altos de tamaño de ejemplar.

3. EFICIENCIA Y COMPLEJIDAD DE LOS ALGORITMOS


Cuando tenemos que resolver un problema y tenemos varios algoritmos que proporcionan
una solución al mismo, es lógico que deseemos utilizar el mejor de ellos, pero entre todos
ellos ¿como podemos elegir el mejor? La importancia de elegir el mejor algoritmo se
acrecienta cuando el problema a resolver es un problema complejo con alta incidencia sobre
su entorno, mas si el algoritmo que queremos desarrollar es de corta duración y sencillo tal
vez no sea considerable hacer un análisis profundo del algoritmo, y por tanto, elegiríamos el
algoritmo que sea más fácil de programar o con el que estamos mas familiarizados.

La eficiencia de un algoritmo indica la adecuada utilización de los recursos computacionales,


lo cual debe estar plasmado en el menor tiempo de procesamiento y en la adecuada
utilización del espacio de almacenamiento.

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


4

Respecto al uso eficiente de los recursos computacionales, este suele medirse en función de
dos parámetros: El espacio, es decir, memoria que se utiliza, y el tiempo, lo que tarda en
ejecutarse. Ambos representan los costes que supone encontrar la solución a un problema
planteado mediante el desarrollo de un algoritmo. Dichos parámetros nos servirán además
para comparar algoritmos entre sí, permitiendo entre ellos determinar el más adecuado para
la solución del problema. Solo nos basaremos en la eficiencia temporal.

El tiempo de ejecución de un algoritmo va a depender de diversos factores como son: Los


datos de entrada que se suministran, la calidad del código generado por el compilador para
crear el programa objeto, la naturaleza y rapidez de las instrucciones máquina del procesador
concreto de un determinado hardware, y la complejidad intrínseca del algoritmo. Hay dos
estudios posibles sobre el tiempo:

 El enfoque Teórico o a Priori: Este enfoque nos permite seleccionar el algoritmo


adecuado para la solución a un problema estudiando matemáticamente la cantidad
de operaciones elementales que realiza el algoritmo en cuestión entre un juego de
algoritmos candidatos. En función de este enfoque mediremos la eficiencia de los
algoritmos.
 El enfoque Empírico o a Posteriori: En el cual, para poder seleccionar el algoritmo
adecuado debemos implementar los algoritmos en un computador y luego evaluar su
eficiencia en función de los recursos que consume, para nuestro caso particular y
objetivos del curso, en función del tiempo de procesamiento.

Ambas medidas son importantes, puesto que, si bien la primera nos ofrece estimaciones del
comportamiento de los algoritmos de forma independiente del ordenador en donde serán
implementados y sin necesidad de ejecutarlos, la segunda representa las medidas reales del
comportamiento del algoritmo. Estas medidas son funciones temporales de los datos de
entrada.

La unidad de tiempo a la que debe hacer referencia estas medidas de eficiencia no puede ser
expresada en segundos o en otra unidad de tiempo concreta, puesto a que no existe un
ordenador estándar al que puedan hacer referencia todas las medidas. Denotaremos por
T(n) el tiempo de ejecución de un algoritmo para una entrada de tamaño n.

Teóricamente, T(n) debe indicar el número de instrucciones ejecutadas por un ordenador


idealizado. Debemos buscar por tanto medidas simples y abstractas, independientes del
ordenador a utilizar. Para ello es necesario acotar de alguna forma la diferencia que se puede
producir entre distintas implementaciones de un mismo algoritmo, ya sea del mismo código
ejecutado por dos máquinas de distinta velocidad, como de dos códigos que implementen el
mismo método. Esta diferencia es la que acota el siguiente principio:

Principio de Invarianza
Dado un algoritmo y dos implementaciones suyas I1 e I2, que tardan T1(n) y T2(n)
segundos respectivamente, el Principio de Invarianza afirma que existe una constante real c >
0 y un número natural n0 tales que para todo n ≥ n0 se verifica que T1(n) ≤ cT2(n).

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


5

Es decir, el tiempo de ejecución de dos implementaciones distintas de un algoritmo dado no


va a diferir en más que una constante multiplicativa.

Con esto podemos definir sin problemas que un algoritmo tarda un tiempo del orden de T(n)
si existe una constante real c>0 y una implementación I del algoritmo que tarda menos que
cT(n), para todo n de tamaño de entrada.

Dos factores a tener en cuenta siempre son la constante multiplicativa y el n0 para los que se
verifican las condiciones, pues si bien a priori un algoritmo de orden cuadrático es mejor que
un algoritmo de orden cubico, en el caso de tener dos algoritmos cuyos tiempos de ejecución
son 106n2 y 5n3, el primero solo sería mejor que el segundo para tamaños de la entrada
superiores a 200 000.

A su vez, es importante también resaltar que el comportamiento de un algoritmo puede


cambiar notablemente para diferentes entradas (por ejemplo, en el caso de ordenación
cuando ingresamos datos que se encuentren ya ordenados). De hecho, para muchos
programas el tiempo de ejecución es en realidad una función de la entrada específica, y no
solo del tamaño de esta. En función de ello se suelen estudiar tres casos particulares para un
mismo algoritmo: caso peor, caso mejor y caso medio.

El caso mejor corresponde a la traza (secuencia de sentencias) del algoritmo que realiza
menos instrucciones. Análogamente, el caso peor corresponde a la traza del algoritmo que
realiza más instrucciones. Respecto al caso medio, corresponde a la traza del algoritmo que
realiza un número de instrucciones igual a la esperanza matemática de la variable aleatoria
definida por todas las posibles trazas del algoritmo para un tamaño de la entrada dado, con
las probabilidades de que éstas ocurran para esa entrada.

Es muy importante destacar que esos casos corresponden a un tamaño de la entrada dado,
puesto que es un error común confundir el caso mejor con el que menos instrucciones realiza
en cualquier caso, y por lo tanto contabilizar las instrucciones que hace para n = 1.

A la hora de medir el tiempo, siempre lo haremos en función del número de operaciones


elementales que realiza dicho algoritmo, entendiendo por operaciones elementales (en
adelante OE) aquellas que el ordenador realiza en tiempo acotado por una constante. Así,
consideraremos OE las operaciones aritméticas básicas, asignaciones a variables de tipo
predefinido por el compilador, los saltos (llamadas a funciones y procedimientos, retorno
desde ellos, etc.), las comparaciones lógicas y el acceso a estructuras indexadas básicas,
como son los vectores y matrices. Cada una de ellas contabilizará como 1 OE.

Resumiendo, el tiempo de ejecución de un algoritmo va a ser una función que mide el


número de operaciones elementales que realiza el algoritmo para un tamaño de entrada
dado.

En general, es posible realizar el estudio de la complejidad de un algoritmo sólo en base a un


conjunto reducido de sentencias, aquellas que caracterizan que el algoritmo sea lento o

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


6

rápido en el sentido que nos interesa. También es posible distinguir entre los tiempos de
ejecución de las diferentes operaciones elementales, lo cual es necesario a veces por las
características específicas del ordenador (por ejemplo, se podría considerar que las
operaciones + y ÷ presentan complejidades diferentes debido a su implementación). Sin
embargo, en este texto tendremos en cuenta, a menos que se indique lo contrario, todas las
operaciones elementales del lenguaje, y supondremos que sus tiempos de ejecución son
todos iguales.

Para hacer referencia a los tres casos citados analizaremos un ejemplo concreto:

FUNCION Buscar (A : Vector, c : Entero)


j=1 (1)
mientras (A[j]<c y j<n) hacer (2)
j = j+1 (3)
fin mientras (4)
si (A[j]= c) entonces (5)
retornar j (6)
en caso contrario (7)
retornar 0 (8)
fin si (9)
fin Buscar

Para determinar el tiempo de ejecución, calcularemos primeramente el número de


operaciones elementales (OE) que se realizan:
- En la línea (1) se ejecuta 1 OE(una asignación)
- En la línea (2) se ejecuta la condición del bucle, con un total de 4 OE(dos
comparaciones, un acceso al vector y una operación lógica)
- En la línea (3) se realiza un incremento y una asignación(2 OE)
- En la línea (5) se realiza una condición y un acceso a un vector (2 OE)
- En la línea (6) se ejecuta un RETORNAR (1 OE) si es que la condición se cumple.
- En la línea (7) se ejecuta un RETORNAR (1 OE) si es que la condición del “SI”
anterior es falsa
En función de lo anterior podemos decir:
 En el caso mejor para el algoritmo, se efectuará la línea (1) y de la línea (2) sólo la
primera mitad de la condición, que supone 2 OE (suponemos que las expresiones se
evalúan de izquierda a derecha, y con “cortocircuito”, es decir, una expresión lógica
deja de ser evaluada en el momento que se conoce su valor, aunque no hayan sido
evaluados todos sus términos). Tras ellas la función acaba ejecutando las líneas (5) a
(7). En consecuencia, T(n)=1+2+3=6
 En el caso peor, se efectúa la línea (1), el bucle se repite n–1 veces hasta que se
cumple la segunda condición, después se efectúa la condición de la línea (5) y la
función acaba al ejecutarse la línea (7). Cada iteración del bucle está compuesta por
las líneas (2) y (3), junto con una ejecución adicional de la línea (2) que es la que
ocasiona la salida del bucle. Por lo tanto podemos decir:

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


7



  1  4  2  4!  2  1  6  2


 En el caso medio, el bucle se ejecutará un número de veces entre 0 y n–1, y vamos a


suponer que cada una de ellas tiene la misma probabilidad de suceder. Como existen
n posibilidades (puede que el número buscado no esté) suponemos a priori que son
equiprobables y por tanto cada una tendrá una probabilidad asociada de 1/n. Con
esto, el número medio de veces que se efectuará el bucle es de:


1 $1
# 
 2
%
Tendríamos pues, que:


)
( +
  1  '( 4  2+  2,  2  1  3  3

& *
& *

Es importante observar que no es necesario conocer el propósito del algoritmo para


analizar su tiempo de ejecución y determinar sus casos mejor, peor y medio, sino que
basta con estudiar su código. Suele ser un error muy frecuente el determinar tales casos
basándose sólo en la funcionalidad para la que el algoritmo fue concebido, olvidando
que es el código implementado el que los determina.

En este caso, un examen más detallado de la función (¡y no de su nombre!) nos muestra
que tras su ejecución, la función devuelve la posición de un entero dado c dentro de un
vector ordenado de enteros, devolviendo 0 si el elemento no está en el vector. Lo que
acabamos de probar es que su caso mejor se da cuando el elemento está en la primera
posición del vector. El caso peor se produce cuando el elemento no está en el vector, y el
caso medio ocurre cuando consideramos equiprobables cada una de las posiciones en las
que puede encontrarse el elemento dentro del vector (incluyendo la posición especial 0,
que indica que el elemento a buscar no se encuentra en el vector).

3.1. REGLAS GENERALES PARA EL CALCULO DE OPERACIONES


ELEMENTALES
La siguiente lista presenta un conjunto de reglas generales para el cálculo del número
de operaciones elementales (OE en adelante) siempre considerando el peor caso. Estas
reglas definen el número de OE de cada estructura básica del lenguaje, por lo que el
número de OE de un algoritmo puede hacerse por inducción sobre ellas.
- Vamos a considerar que el tiempo de una OE es, por definición, de orden 1. La
constante c que menciona el principio de invarianza dependerá de la
implementación particular, pero nosotros supondremos que vale 1.
- Las operaciones elementales son:
o Las asignaciones de valores a variables

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


8

o El acceso a elementos de un arreglo o vector


o Operaciones Aritméticas (suma, resta, multiplicación, modulo, etc.)
o Operaciones lógicas (comparaciones, and, or, etc.)
o Retorno de valores por una función.
- El tiempo de ejecución de una secuencia consecutiva de instrucciones se
calcula sumando los tiempos de ejecución de cada una de las instrucciones.
- El tiempo de ejecución de una sentencia condicional múltiple:

SWITCH(C){
CASE a: S1; break
CASE b : S2; break;
DEFAULT : Sn; break;
}

Es de T(n) = T(C) + max{T(S1),T(S2),T(S3),…,T(Sn)}. Obsérvese que T(C)


incluye el tiempo de comparación con v1,v2,…,vn.
- El tiempo de ejecución de la sentencia

IF (C)
S 1;
ELSE
S 2;

Es de T(n) = T(C) + max{T(S1),T(S2)}.


- El tiempo de ejecución de un bucle de sentencias, ya sea FOR, WHILE :

SENTENCIA_REPETITIVA(C){
S;
}

Es T(n) = T(C) + (nº iteraciones)*(T(S) + T(C)). En el caso del FOR, la


condición se analiza dentro y debe tenerse en cuenta el tiempo de inicialización
de la variable, el tiempo de comparación y el incremento que realiza cada vez
que itera el bucle. Obsérvese que tanto T(C) como T(S) pueden variar en cada
iteración, y por tanto habría que tenerlo en cuenta para su cálculo.
- El tiempo de sentencias en un bucle DO-WHILE es similar al anterior, a
diferencia de la sentencia repetitiva WHILE no se considera la evaluación
inicial antes de ingresar al bucle: T(n) = (nº iteraciones)*(T(S) + T(C)).
- El tiempo de ejecución de una llamada a un procedimiento o función es 1, mas
el tiempo que tarda en ejecutarse es T(F), esto es: T(n) = 1+T(F)
- El tiempo de ejecución de las llamadas a procedimientos recursivos va a dar
lugar a ecuaciones en recurrencia, las cuales se verán posteriormente.

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


9

4. NOTACION ASINTOTICA
Una vez que hemos visto la forma de calcular el tiempo de ejecución T de un algoritmo,
nuestro propósito es intentar clasificar dichas funciones de forma que podamos compararlas.
Para ello, vamos a definir clases de equivalencia, correspondientes a funciones que “crecen
de la misma forma”.

4.1. COTA SUPERIOR : NOTACION O


Dada una función f, queremos estudiar aquellas funciones g que a lo sumo, crecen tan
deprisa como f. Al conjunto de tales funciones se le llama cota superior de f y lo
denominamos O(f). Conociendo la cota superior de un algoritmo podemos asegurar
que, en ningún caso, el tiempo empleado será de un orden superior al de la cota.

Sea .: 0  10, 4. Se define el conjunto de funciones de orden O(Omicron) de f


Definición:

como:

5.  67: 0  10, ∞|:; < =, > ? 0, :% < 0 @ 7 A >.B C % D

Diremos que una función E: 0  10, ∞ es de orden O de f si E < 5..

Intuitivamente, E < 5. indica que t está acotada superiormente por algún múltiplo
de f Nosotros estaremos interesados por la menor función f tal que t pertenezca a O(f).

En otros términos, dado un polinomio T(n) que representa la cantidad de operaciones


elementales en función de un tamaño de ejemplar n, podríamos decir que es de orden

  5F.G H :> C 0 B ? 0/ A >F.G, > < =


f(n) siempre y cuando cumpla con las siguientes condiciones:

a) Para cualquier función f, se tiene que . < 5.


Propiedades de O

b) . < 57  5. J 57


c) 5.  57 H . < 57 K 7 < 5.
d) L# . < 57 K 7 < 5M  . < 5M
e) L# . < 57 K . < 5M  . < 5min7, M
f) Regla de la suma: L# . < 57 K .) < 5M  .  .) < 5max7, M
g) Regla del producto: L# . < 57K .) < 5M  . . .) < 57. M

4.2. COTA INFERIOR : NOTACION Ω


Dada una función f, queremos estudiar aquellas funciones g que a lo sumo crezcan tan
lentamente como f. Al conjunto de tales funciones se le llama cota inferior de f y lo
denominamos Ω(f). Conociendo la cota inferior de un algoritmo podemos asegurar que,
en ningún caso, el tiempo empleado será de un orden inferior al de la cota.

Sea .: 0  10, 4. Se define el conjunto de funciones de orden Ω(Omega) de f como:


Definición:

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


10

5.  67: 0  10, ∞|:; < =, > ? 0, :% < 0 @ 7 C >.B C % D

Diremos que una función E: 0  10, ∞ es de orden Ω de f si E < Ω..

Intuitivamente, E < Ω. indica que t está acotada inferiormente por algún múltiplo de
f. Normalmente estaremos interesados en la mayor función f tal que t pertenezca a
Ω(f), a la que denominaremos su cota inferior.

4.3. ORDEN EXACTO : NOTACION U


Con esta cota asintótica, definiremos los conjuntos de funciones que crecen
asintóticamente de la misma forma.

Sea .: 0  10, 4. Se define el conjunto de funciones de orden Θ(Theta) de f como:


Definición:

Θ.  5. W Ω.

O lo que es igual a:

5.  67: 0  10, ∞|:; < =, ;, X ? 0, :% < 0 @ ;. A 7 A X.B C
% D

Diremos que una función E: 0  10, ∞ es de orden Θ de f si E < Θ.

Intuitivamente, E < Θ. indica que t está acotada tanto superior como inferiormente
por múltiplos de f, es decir, que t y f crecen de la misma forma.

5. RESOLUCION DE ECUACIONES EN RECURRENCIA


Anteriormente hemos descrito como encontrar determinar el tiempo de ejecución de un
algoritmo en función del número de operaciones elementales que se realizan en el
computador. Sin embargo, ocurre una dificultad en el análisis de algoritmos recursivos,
debido a que la ecuación para describir el numero de operaciones del algoritmo es una
ecuación de recurrencia, es decir, T(n) = E(n), en donde en la expresión E aparece la
misma función T.

Para poder resolver este tipo de ecuaciones debemos encontrar una expresión no recursiva
de T, lo cual en algunos casos es algo complicado. Lo que trataremos en esta sección es
como podemos resolver algunos tipos de ecuaciones en recurrencia que se dan con mayor
frecuencia.

5.1. Recurrencias homogéneas


EL caso más sencillo será el de ecuaciones lineales homogéneas de coeficientes
constantes

% E   E $ 1  ) E $ 2  Y  Z E $ >  0

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


11

Donde los coeficientes  son constantes. Se llama lineal porque la ecuación es lineal y
homogénea porque no tiene término independiente y homogéneo porque no tiene
término independiente de t.

Buscamos una solución de la forma E  [  con x constante. De este modo:

% [    [   Y  Z [ Z  0

Con lo que habrá que resolver la ecuación característica:

% [ Z   [ Z  Y  Z [ %  0

(s1,s2,…,sk), en cuyo caso, toda combinación lineal E  ∑Z;   es una solución
Puede ocurrir que las soluciones de la ecuación característica sean todas distintas

de la recurrencia, y para determinar los valores de las constantes habrá que resolver el
sistema formado interponiendo las condiciones iniciales.

Ejemplo 1: Como ejemplo, veamos cual es la solución de la recurrencia  $


3 $ 1 $ 4 $ 2  0, cuando n>2, con condiciones iniciales T(0) = 0 y
T(1) = 1.

La ecuación característica es [ ) $ 3[ $ 4  0, que tiene soluciones -1 y 4, por lo que


  ; $1  ;) 4 , e imponiendo las condiciones iniciales tenemos:
;  ;)  0
$;  4;)  1

De donde ;  $ ] y ;)  ], con lo que la solución es


 

  4 $ $1 .



]

Raíces con multiplicidad mayor que 1


Supongamos que alguna de las raíces tiene multiplicidad m>1. Entonces, la ecuación
característica puede ser escrita de la siguiente forma:

[ $  ^ [ $ )  … [ $ Z^` 

En cuyo caso la solución de la ecuación en recurrencia viene dada por la expresión:

^ Z

   ;  
   ; ^`
 

 ^`

Donde los coeficientes ; se determinan a partir de las condiciones iniciales.

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


12

Este caso puede ser generalizado de la siguiente forma. Si  , ) , a, … , Z son las raíces
de la ecuación característica de una ecuación en recurrencia homogénea, cada una de
multiplicidad mi, esto es, si la ecuación característica puede expresarse como :

[ $  ^b [ $ ) ^c … [ $ Z ^d  0

Entonces, la solución a la ecuación de recurrencia viene dada por la expresión:

^b ^b ^b

   ;     ;)  )  …   ;Z  Ze


  

  5 $ 1 $ 8 $ 2  4 $ 3 cuando n>3, con condiciones iniciales


Ejemplo 2: Como un siguiente ejemplo, veamos cual es la solución de recurrencia

T(0) = 0, T(1) = 1 y T(2) = 2.

La ecuación característica es [ a $ 5[ )  8[ $ 4  0, que se descompone como


[ $ 1[ $ 2)  0, por lo que la solución general de la recurrencia es  
; 1  ;) 2  ;a 2 , e imponiendo las condiciones iniciales tenemos el sistema de

;  ;)  0
ecuaciones:

;  2;)  2;a  1
;  4;)  8;a  2

  $2  2` $ 2


Y resolviendo el sistema de ecuaciones tenemos:

Este ejemplo de resolución de recurrencia no puede corresponder a un caso real de


cálculo de tiempo de ejecución, pues el término del mayor orden en T(n) aparece como
coeficiente negativo, lo que corresponde a un tiempo de ejecución negativo cuando el
tamaño de la entrada aumenta.

5.2. Recurrencias No Homogéneas

%     $ 1  Y  Z  $ >  h 



Consideremos una ecuación de la forma:

Donde los coeficientes  y b son números reales, y p(n) es un polinomio en n de grado


d. Una primera idea para resolver la ecuación es manipularla para convertirla en
homogénea, como muestra el siguiente ejemplo:

Ejemplo 1: Sea la ecuación   2 $ 1  3


 ? 1, con las condiciones
iniciales T(0) = 0 y T(1) = 1. En este caso b = 3 y p(n) = 1, polinomio en n de grado
0.

Podemos escribir la ecuación de dos formas distintas. En primer lugar, para n+1

  1 $ 2  3`


tenemos que:

Pero si multiplicamos por 3 la ecuación original obtenemos:

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


13

3 $ 6 $ 1  3`

  1 $ 5  6 $ 1  0


Restando ambas ecuaciones tenemos:

Que resulta ser una ecuación homogénea cuya solución, aplicando lo visto

  3 $ 2
anteriormente, es:

Esta técnica se aplica cuando n es potencia de un numero real a, esto es   Z . Sea


5.3. Cambio de Variable

por ejemplo, para el caso a = 2, la ecuación T(n) = 4T(n/2) + n, donde n es una


potencia de 2(n>3), T(1) = 1, y T(2) = 6

Si   2Z podemos escribir la ecuación como:

F2Z G  4F2Z G  2Z

Haciendo el cambio de variable EZ  2Z  obtendremos la ecuación:

EZ  4EZ  2Z

Que corresponde a una de las ecuaciones estudiadas anteriormente, cuya solución

EZ  ; 2Z )  ;) 2Z
viene dada por la expresión:

  ; )  ;) 
Deshaciendo el cambio que realizamos al principio, obtenemos que:

  2) $ 
Calculando entonces las constantes a partir de las condiciones iniciales tenemos:

5.4. Recurrencias no Lineales


En este caso, la ecuación que relaciona T(n) con el resto de los términos no es lineal.
Para resolverla intentaremos convertirla en una ecuación lineal como las que hemos
estudiado hasta el momento.

Por ejemplo, sea la ecuación    ) /2 para n potencia de 2, n>1, con la
condición inicial T(1) = 1/3. Llamando EZ  2Z , la ecuación quedaría así:

EZ  F2Z G  2Z  ) F2Z G  2Z EZ


)

Que no corresponde a ninguno de los tipos estudiados. Necesitamos hacer un cambio

cambio Z  log EZ obtenemos:


más para transformar la ecuación. Tomando logaritmos a ambos lados y haciendo el

Z $ 2Z  >
Ecuación de recurrencia no homogénea, cuya ecuación característica asociada es (x-

Z  ; 2Z  ;)  ;a >
2)(x-1)2 = 0. Por tanto:

Necesitamos ahora deshacer los cambios hechos. Primero Z  log EZ


EZ  2lb )
d `l `l Z
c m

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


14

Y después EZ  2Z . En consecuencia:


  2lb `lc `lm nop 
Para calcular las constantes, necesitamos las condiciones iniciales. Como sólo
disponemos de una y tenemos tres incógnitas, usamos la ecuación en recurrencia
original para obtener las restantes.
T(2) = 2T2(1) = 2/9
T(4) = 4T2(2) = 16/81

Con esto llegamos a que c1 = log(4/3) = 2-log(3), c2 = -2, c3 = -1 y por consiguiente:

2)
 
43

6. EJERCICOS PROPUESTOS

Recursividad
a. Implemente de forma recursiva e iterativa y obtenga la complejidad del algoritmo
del MCD recursivo e iterativo mediante notación asintótica O.
b. Implemente de forma recursiva e iterativa y obtenga la complejidad del algoritmo de
inversión de una cadena, mediante notación asintótica O.
c. Implemente de forma recursiva e iterativa y obtenga la complejidad de un algoritmo
que verifique que una si una cadena es simétrica o no, mediante notación O.
d. Obtener el T(n) y la complejidad usando notación asintótica O del siguiente
algoritmo:

Recurrencias: Desarrollar las recurrencias y obtener el grado de cada T(n) según se


muestra a continuación:
e. T(n) = 3T(n-1) + 4T(n-2) si n>1; T(0) = 0; T(1) = 1
n
f. T(n) = 2T(n-1) – (n+5)3 si n>0; T(0) = 0
2
g. T(n) = 4T(n/2)+n si n>4, n potencia de 2; T(1) = 1; T(2) = 8
h. T(n) = 2T(n/2) + nlog(n) si n>1, n potencia de 2
i. T(n) = 3T(n/2) + 5n + 3 si n>1, n potencia de 2
j. T(n) = 2T(n/2) + log(n) si n>1, n potencia de 2
si n = 2) ; T(2) = 1
d
k. T(n) = 2T(n1/2) + log(n)
l. T(n) = 5T(n/2) + (nlogn)2 si n>1,n potencia de 2, T(1) = 1
m. T(n) = T(n-1) + 2T(n-2) – 2T(n-3)
si n>2, T(n) = 9n2-15n+106 si n = 0,1,2.
n. T(n) = (3/2)T(n/2) – (1/2)T(n/4)-(1/n)
si n>2; T(1) = 1; T(2) = (3/2)
1/2
o. T(n) = 2T(n/4) + n si n>4, n potencia de 4

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


15

p. T(n) = 4T(n/3) + n2 si n>3, n potencia de 3

q. Resolver la ecuación

1
   #  ;

%
Siendo T(0) = 0
Resolver la ecuación recurrente E  E q s  ;Z , #  ? % siendo h C

r
r.
2, % C 1, > C 0, a y c reales positivos y n una potencia de b

Análisis de complejidad
s. Hacer un algoritmo recursivo para el calculo del n-ésimo numero de Fibonacci y
calcular el orden de su complejidad usando la notación O.
t. Encontrar el orden O del algoritmo :
max = 0
for i=1 to n
cont = 1

while 1#t A 1t


j = i+1

j = j+1
cont = cont+1
endwhile
if cont>max
max = cont
endif
endfor
u. Calcular el tiempo de ejecución en función del valor de n, del siguiente algoritmo:
procedure algoritmo(x: array[1..max, 1..max]de enteros, n:entero)
if n>1
for i=1 to n/2
for j=1 to n/2
a[i,j] = x[i,j]
b[i,j] = x[i,j+n/2]
c[i,j] = x[i+n/2,j]
endfor
endfor
algoritmo(a,n/2)
algoritmo(b,n/2)
algoritmo(c,n/2)
endif
end procedure
v. Dado el programa
i=1

while(# A  X  A )
j=1

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia


16

if 1#,   1t u 1#  1, t
j = j+1
else
i = i+1
endif
endwhile
Calcular su O(f(n))

Guevara Ruiz, Ricardo; Alvarez Borja, Jhon Algoritmia

También podría gustarte