Monografias.com > Sin categoría
Descargar Imprimir Comentar Ver trabajos relacionados

Introducción al diseño y análisis de los algoritmos (página 2)




Enviado por sar



Partes: 1, 2, 3

Estos hechos han dado lugar al desarrollo de dos direcciones
en el estudio de los algoritmos: el
diseño
(determinar los procedimientos adecuados para
resolver el problema con el agente de cómputo de que
disponemos) y la teoría de la complejidad
algorítmica
(estudio de la eficiencia, costo en tiempo y recursos con que el agente de
cómputo ejecuta un algoritmo que resuelve el
problema).

En principio, dado un problema puede determinarse un algoritmo
que lo resuelva, si este puede ser formulado de manera lógica, tal que el agente
de cómputo sea capaz de comprenderlo y controlar su
ejecución paso a paso. Un  algoritmo responde  a
la ecuación ALGORITMO = LOGICA + CONTROL. ésta es una idea
importante, según la cual la tarea fundamental del
programador es formular lógica y apropiadamente el problema
para que la solución sea buscada mediante un algoritmo.

¿Cómo debe el programador formular el problema? Esta
es realmente una tarea de gran complejidad, siendo necesario
realizar investigaciones teóricas y
experimentales que permitan desarrollar metodologías y
formalismos para enfrentar con éxito problemas de gran importancia
práctica.

I.2   Los alfabetos, las palabras, los
lenguajes:

La información se transmite por
los canales mediante  palabras (sucesión finita
de elementos de un alfabeto:conjunto finito no vacío
de símbolos). El número de símbolos de la
información se llama longitud de la información.
 

 Ejemplo 1: Como alfabeto podemos tener el
sistema decimal D, sistema binario B, los
alfabetos de los distintos idiomas en que nos comunicamos.

D = {0, 1, 2, 3, 4, 5, 6, 7, 8,
9};       B = {0, 1}

Palabras representadas mediante los elementos de los alfabetos
D y B:

wD = 21654,     wB =
0101.

Dado un alfabeto A = {a1, a2,…,
an}, denotemos por W(A) el conjunto de todas las
palabras formadas con los elementos de A. W(A) es un conjunto
infinito numerable, es decir existe  una biyeccion entre
W(A) y el conjunto de los números naturales (N).

Sea w una palabra no vacía (las palabras vacías son
asociadas con el cero), tal que w€W(A), numeremos la
posición de cada carácter (símbolo)
de w comenzando por la derecha, 0, 1, 2,…; entonces si el
carácter ar de w se encuentra en la posición
s le asignamos un peso igual a r x ks, por k
tomamos el numero de elementos del alfabeto (por ejemplo
para  el alfabeto D, k = 10; para B, k = 2), r expresa el
cardinal del símbolo del alfabeto. Entonces a w le
corresponde un número natural que es igual a la suma de los
pesos de los caracteres que lo componen. Esta correspondencia se
llama numeración k-ádica.

Ejemplo 2:

Sea   B = {a1, a2} un
alfabeto, donde, a1=0,  a2=1; r =
{r1, r2} = {1,2}, sea w = 0101 una palabra
formada por los caracteres del alfabeto B. Numeremos los
caracteres de w con los números enteros no negativos
(comenzando por el cero), de derecha a izquierda,  s =
{s3, s2, s1,s0} = {3,
2, 1, 0}.

Determinemos el número natural que le corresponde a la
palabra w, es decir, la numeración  2-ádica 
para la palabra w:

r1xkS3 +
r2xkS2 +
r1xkS1 +
r2xkS0 =1×23+
2×22+ 1×2+ 2×20=20.

La numeración k-adica asocia a cada palabra un único
número entero no negativo, lo que, la hace diferente  a
la  representación usual en la base  k (por
ejemplo en la base usual 2 las palabras  0101 y 101
responden ambas al número 5). 

0101=0x23+ 1×22+ 0x2+
1×20=5

101=1×22+ 0x2+ 1×20=5

El conjunto de las palabras definidas sobre un alfabeto se
llama lenguaje sobre este alfabeto. Dado un alfabeto A,
sobre el pueden definirse como lenguajes particulares: el
vacío O, que no contiene palabra alguna, y W(A), el lenguaje completo, que
contiene todas las posibles palabras sobre A.

Dado un conjunto discreto de símbolos no vacío M,
una representación de M sobre el alfabeto A, es una función inyectiva R: M
® W(A), que asocia a cada símbolo s€M una
palabras w€W(A). La función R asocia al conjunto M el
lenguaje 
 LM   sobre   A, es decir,
LM = Im(R) Í W(A),    

LM= {w: w€W(A) y w =R(s) para algún
s€M}

Ahora podemos dar una definición rigurosa  (formal)
de algoritmo:

Definición 1: Un algoritmo A no es más
que una terna (M; LM; gL), donde M es un
conjunto discreto no vacío de símbolos,
 LM Í W(A), un lenguaje asociado a M,
gL: LM ® LM una
función que transforma las palabras w€LM en
otras palabras de LM.

En otras palabras, el algoritmo proporciona al agente de
cómputo un método sistemático
(función) que transforma las palabras w€LM
en otras palabras de LM.

 I.3   Requisitos básicos de los
algoritmos:

El requisito básico que debe cumplir un algoritmo, es que
el mismo debe ser eficaz, las reglas deben ejecutarse de modo
preciso sin ambigüedades.

Asumamos que existe algún agente de cómputo eficaz,
es decir, su tarea es realizada mediante un número finito de
pasos elementales (instrucciones), en un tiempo prudencial. El
procedimiento de cómputo
a ejecutar por el agente de cómputo puede contener cualquier
número de instrucciones, pero siempre tiene que ser una
sucesión finita, que proporcione una notación formal
conveniente, mostrando de forma precisa las instrucciones que el
agente de cómputo debe ejecutar, y en que orden deben
realizarse. La sucesión de instrucciones del procedimiento
de cómputo puede depender de los datos de la entrada, según
las reglas especificadas; pero nunca se determinarán de
manera aleatoria o arbitraria. No se definirá  a priori
límite en el tamaño de los datos de la entrada e
intermedios a procesar, así como de los resultados.
Sólo requeriremos que  todos sean finitos. En resumen
todos los elementos del procedimiento de cómputo (datos,
sucesión de instrucciones) a ejecutar por el agente de
cómputo tienen que  ser finitas.

Como hemos planteado los algoritmos deben ser escritos de
forma clara, sin ambigüedades, para que los mismos sean
ejecutados de manera eficaz por el agente de cómputo.
mputoue los mismos sean ejecutados por el agente de come forma
clara ebe ejecutar e los caracteres  

Cualquiera que sea la representación que se adopte para
escribir un algoritmo, la misma debe cumplir los requisitos
siguientes:

      a)   El algoritmo
debe ser comprensible para el agente de cómputo

b)   La longitud del algoritmo es finita.

c)     Cada paso del algoritmo indica una
operación, ejecutable sin ambigüedad en un tiempo
finito. 

 d) El algoritmo recibe los datos de entrada, los procesa
y produce los resultados como datos de salida.

e)     El algoritmo debe terminar para
todos los datos de entrada aceptados, en un tiempo finito.

En la práctica, la condición de terminación no
es suficiente, para definir cuan eficaz es un algoritmo, la
eficacia de un algoritmo
significa que el agente  de cómputo transforma los valores de la data inicial
haciendo uso de los recursos y el tiempo de ejecución
de  forma eficaz, hasta obtener los valores de la data final.

I.4  Estructuras de los
algoritmos:

La representación (escritura) de los algoritmos
está directamente relacionada con el agente de cómputo
que va a ejecutarlo: gráfico, seudo-código, lenguaje de
programación, etc.
Nosotros emplearemos el seudo-código, una
representación intermedia entre el lenguaje natural y los
leguajes de programación, este queda definido por un sistema
de reglas (instrucciones) para la escritura  de los
algoritmos.

Las instrucciones definen la unidad estructural, designa un
paso del tratamiento o la representación de la
información de cualquier algoritmo.

Como se ha expresado, al ejecutar un algoritmo, este
transforma los valores de algunas magnitudes (vamos a considerar
la magnitudes definidas en el conjunto de los números
reales), con las cuales opera el algoritmo. Estas magnitudes
tienen un nombre identificador: secuencia de símbolos
que comienza con una letra que las identifica. Las magnitudes se
clasifican en constantes  y variables (simples y
dimensionales). Los valores de las constantes permanecen
invariables, mientas que los valores de las variables cambian. El
valor de una variable se puede
cambiar con ayuda de una instrucción de asignación,

           
 [identificador] =
[expresión]

 [expresión] define una función o constante

Ejemplo 3: Perímetro de un triángulo dados
sus lados.

                    
P = a +b +c

                    
P = 20

A la variable puede asignarse un valor con ayuda de la
instrucción de entrada que transmite el valor de las
variables a partir de cierta fuente exterior.

           
Entrada [variable 1], [
variable 2], [ variable
3
]

Ejemplo 4:

           
Entrada a, b, c

También existe la instrucción análoga de
salida.

           
Salida [variable 1], [
variable 2], [ variable
3
]

Ejemplo 5:

           
Salida P

Un elemento útil es el uso de comentarios dentro del
algoritmo,

           
// [ comentario]

Ejemplo 6: Calcular el perímetro de un
triángulo, dado sus lados:

      //Cálculo  el
perímetro de un triángulo.

           
Entrada a, b, c   // lados del triángulo

           
P = a + b + c

           
Salida P   // perímetro de un triángulo

    //Fin del algoritmo

Analicemos ahora el siguiente problema: Dados los lados de un
triángulo, se desea clasificarlo en: equilátero,
isósceles, escaleno.

Como es conocido un triángulo solamente admite una
clasificación de acuerdo a la dimensión de sus lados,
por lo que estamos en presencia de la selección de alternativas:
Un triángulo se define como equilátero si la
dimensión de sus lados son iguales, es decir, a = b = c, por
la propiedad de transitividad

a = c; un triángulo es isósceles si dos de sus lados
son iguales, es decir, a = b o b = c o a = c; es escaleno si sus
lados son diferentes a ≠ b y b ≠c y a ≠ c.

Para expresar la anterior situación se emplea la
instrucción de bifurcación (condicional), la cual
efectúa la elección de las instrucciones a ejecutar en
función del cumplimiento de un conjunto de condiciones (en
general estos pueden ser relaciones de orden (≤, ≥,
<, >, ≠, =) unidos con los operadores
 lógicos: y, o, no), como se expresa a
continuación,

Si [relación de oprden1]
(operador lógico) [ relación de orden
2
]

                                  
Entonces

                                      
[ instrucción 1]

                                      
[ instrucción 2]

                                                
:

                                
Sino      

                                 
  
[ instrucción
1
],

                                  
 
[ instrucción 2]

                                              
:

          Fin
Si

Cuando se ejecuta la instrucciones de bifurcación se
realiza solamente un bloque de instrucciones: si las condiciones
se cumplen se ejecutan las instrucciones que aparecen
después de la palabra reservada Entonces, en caso de no
cumplirse la condición se ejecutan las instrucciones que
aparecen después de la palabra reservada Sino. Dentro de las
instrucciones pueden aparecer otras instrucciones de
bifurcación, como se presenta en el ejemplo siguiente.

Ejemplo 7: Dados los lados de un triángulo se
desea clasificarlo en: equilátero, isósceles,
escaleno.

// Clasificar un triángulo en: equilátero,
isósceles, escaleno.

      Entrada a, b, c   //
lados del triángulo

         Si a = b y b
= c

                       
Entonces

           
              
Clas = triángulo equilátero

           
           Sino
Si a = b o b = c o a = c

                                              
Entonces

                                             
Clas = triángulo isósceles

                                           
Sino

                  
                         Clas
= triángulo escaleno

                           
 Fin Si

         
      Fin Si

         Salida 
Clas      // clasificación del
triángulo.

 //Fin del algoritmo

Veamos una nueva situación:

Se tiene un conjunto que contiene los lados de n
triángulos, se desea conocer cuantos triángulos
equiláteros, isósceles y escalenos contiene el
conjunto.

Hasta el momento fuimos capaces de clasificar un
triángulo dado sus lados. La nueva situación nos
presenta un conjunto finito o lista determinada de elementos (se
conoce de antemano la cantidad de elementos que la componen).

Lo anterior puede ser representado de la forma siguiente: sea
un conjunto finito T, cuyos elementos son ternas (vectores de
R3),

T= { (a1, b1, c1),
(a2, b2, c2),…,
(an, bn, cn) }

Para resolver el problema planteado definiremos la
instrucción de iteración (repetitiva o cíclica)
con contador:

           
Para  [
contador]=[ valor
inicial
] hasta [ valor
final
]  (paso)

                    
[ instrucción 1]

                       
[ instrucción 2]

          
                      :

         
Próximo
[ nuevo valor del
contador
]

El contador toma un valor inicial y se ejecutan las
instrucciones que se encuentra entre las palabras reservadas
Para-Próximo (ciclo). Al llegar a la palabra reservada
Próximo el contador se incrementa de acuerdo al valor del
paso (cuando no se define se asume como 1). Este proceso se repita hasta que el
contador alcance el valor final.

Ejemplo 8: Se desea conocer cuantos triángulos
equiláteros, isósceles y escalenos, contiene un
conjunto de n triángulos.

// Determinar total de triángulos equiláteros,
isósceles y escalenos

      Entrada n  // total de
triángulos a clasificar

      CEQ = 0,  CES = 0, CIS =
0     // valores iniciales de  los
contadores

           
Para I =1 hasta n

              
Entrada a, b, c   // lados del triángulo

              
Si a = b y b = c

                       
Entonces

           
              
Clas = triángulo equilátero

                       
    CEQ = CEQ
+1        

           
           Sino
Si a = b o b = c o a = c

                                              
Entonces

                                             
Clas = triángulo isósceles

                                              
     CIS= CIS+1

                                           
Sino

                                           
Clas = triángulo escaleno

                                              
 CES = CES +1

                       
Fin Si

               
Fin Si

         Salida 
Clas      // clasificación del
triángulo.

      Próximo I

      Salida CEQ, CIS, CES // total
de triángulos equiláteros, isósceles y  
escalenos

 //Fin del algoritmo

Hay problemas en que se desconoce el tamaño de la lista
(lista indeterminada) que va hacer procesada, solamente se conoce
una condición que determina el final de la lista
(último elemento). En estos casos es necesario emplear la
instrucción de iteración con condición

Mientras [relación de orden1]
(operador lógico) [ relación de orden
2
]

             
       [
instrucción 1]

                       
[ instrucción 2]

                                
:

Fin Mientras

Al principio se prueba la condición que aparece
después de la palabra reservada Mientras, si esta se
satisface se ejecutan las instrucciones que se encuentran entre
las palabras reservadas Mientras-Fin Mientras (ciclo), estas se
van a repetir hasta que la condición deje de satisfacerse.
 Para esto es necesario que las instrucciones que se
ejecutan dentro del ciclo influyan en la condición.

Ejemplo 9: Se tiene un conjunto finito triángulos,
se conoce que el último triangulo es escaleno y las
dimensiones de sus lados son:  a = 27.5, b = 12.2,

c =32.  Determine cuantos triángulos
equiláteros, isósceles y escalenos, contiene el
conjunto.

// Determinar  total de triángulos equiláteros,
isósceles y escalenos 

      CEQ = 0,  CES = 0, CIS =
0     // valores iniciales de  los
contadores

           
     Entrada a, b, c 
   // lados del triángulo

         
Mientras a ≠ 27.5 y b ≠12.2 y c ≠ 32

              
Si a = b y b = c

                       
Entonces

           
              
Clas = triángulo equilátero

                       
    CEQ = CEQ
+1        

           
           Sino
Si a = b o b = c o a = c

                                              
Entonces

                                            
 Clas = triángulo isósceles

                                              
     CIS= CIS+1

                                           
Sino

                                           
Clas = triángulo escaleno

                                              
 CES = CES +1

                       
Fin Si

               
Fin Si

         Salida
 Clas      // clasificación
del triángulo.

           
Entrada a, b, c  

Fin Mientras

      Salida CEQ, CIS, CES
+1   // total de triángulos equiláteros,
isósceles y   escalenos

    //Fin del algoritmo

No es difícil ver que una lista determinada puede ser
tratada con la instrucción iterativa condicionada, como se
muestra a
continuación.

Retomemos el problema del ejemplo 8, y escribamos el algoritmo
empleando la instrucción iterativa condicionada.

// Determinar total de triángulos equiláteros,
isósceles y escalenos

      Entrada n  // total de
triángulos a clasificar

      CEQ = 0,  CES = 0, CIS =
0     // valores iniciales de  los
contadores

       I = 0
      // valor inicial para el
contador del ciclo

           
Mientras I ≠ n

              
Entrada a, b, c   // lados del triángulo

              
Si a = b y b = c

                       
Entonces

           
              
Clas = triángulo equilátero

                       
    CEQ = CEQ
+1        

           
           Sino
Si a = b o b = c o a = c

                                              
Entonces

                              
               Clas
= triángulo isósceles

                                              
     CIS= CIS+1

                                           
Sino

                                           
Clas = triángulo escaleno

                                              
 CES = CES +1

                       
Fin Si

               
Fin Si

 
           I
= I + 1

         Fin
Mientras

         Salida 
Clas      // clasificación del
triángulo.

      Salida CEQ, CIS, CES // total
de triángulos equiláteros, isósceles y  
escalenos

    //Fin del algoritmo

I.4.1 Variables dimensionales (arreglos). Algoritmos
subor-dinados.

Las variables dimensionales (variables con
índices, ejemplo: A(I), B(I, J)), describen las estructuras
compuestas de un conjunto de elementos ordenados conforme al
valor de los índices, es decir,  la posición de
los elementos queda definida por los valores de los índices.
Las variables dimensionales tienen sus antecedentes  en los
entes matemáticos, los vectores
y las matrices.

A diferencia de las variables simples (cada variable simple
almacena un sólo valor), las variables con un índice
A(I), almacenan tantos valores como el valor máximo que toma
el índice (en el caso de la variable bidimensional B(I; J)
estas almacenan un número de elementos igual al producto de los máximos
valores de los índices).

 En la generalidad de los casos se conoce el máximo
valor de los índices, siendo muy usada la instrucción
iterativa con contador para operar con las variables con
índices (lo anterior no significa que no sea utilizada la
instrucción iterativa con condición).

Ejemplo 10: Determinar la suma de todos los elementos
positivos de una matriz    n x
n.

// Suma de los elementos positivos de una matriz.

Entrar n   // número de filas y columnas de la
matriz

Sum = 0    //valor inicial de la suma

Para I =1 hasta n  // inicio del ciclo para el
índice de las filas

      Para  J =1 hasta n //
inicio del ciclo para el índice de las columnas

          
Entrar A(I ;J)  // entrada de los elementos de la matriz por
filas

              
Si  A(I ;J)  > 0

                       
Entonces

                       
     Sum = Sum +A(I ;J)

               
Fin Si

      Próximo J // próximo
valor del índice por las columnas

Próximo I  // próximo valor del índice por
las filas        

Salida Sum  //valor final de la suma

//Fin del algoritmo

Mostraremos ahora como realizar el  algoritmo anterior,
si se emplea la instrucción iterativa condicional para
definir el ciclo,

// Suma de los elementos positivos de una matriz.

Entrar n   // número de filas y columnas de la
matriz

Sum = 0    //valor inicial de la suma

I = 1, J = 1   // valores iniciales de los
índices de las columnas y las filas

Mientras I ≠ N

      Mientras J ≠ N

            
Entrar A(I ;J)  // entrada de los elementos de la matriz por
filas

                       
Si  A(I ;J)  > 0

                       
Entonces

                       
     Sum = Sum +A(I ;J)

               
Fin Si

                       
J =J +1

          
Fin Mientras

       
    I = I +1

      Fin Mientras

   Salida Sum  //valor final de la suma

//Fin del algoritmo

Con frecuencia al desarrollar un algoritmo, resulta posible
aprovechar los algoritmos elaborados antes. De tal modo al
construir el algoritmo, habitualmente se trata de dividir todo el
problema en subproblemas más simples, y si para algún
subproblema ya existe el algoritmo, éste puede incluirse en
el algoritmo en desarrollo. Esto permite no repetir el trabajo ya realizado,
economizar el tiempo.

Los algoritmos acabados, incluidos por completo en el
algoritmo que se elabora, se llaman algoritmos auxiliares o
subordinados
, y el algoritmo en que ellos se incorporan se
llama algoritmo principal o fundamental.

El empleo de los algoritmos
subordinados provoca la necesidad de formalizarlos de modo
especial para poder invocarlos en el
algoritmo principal, para llamar un algoritmo subordinado desde
el algoritmo principal, nosotros utilizaremos la instrucción
de llamada al algoritmo subordinado,

Llamada  [nombre] [
(Lista de parámetros) ]

La ejecución de la instrucción de llamada al
algoritmo subordinado equivale a la ejecución del algoritmo
subordinado. Luego de la palabra reservada Llamada se escribe un
nombre el cual identifica al algoritmo subordinado, la lista de
parámetros entre paréntesis,  separados por comas,
indicándose el nombre de los parámetros de entrada y
salida (los parámetros que son transferidos desde el
algoritmo principal al algoritmo subordinado, y los resultados
que se obtienen en el algoritmo subordinado y son transferidos al
algoritmo principal), estos deben aparecer en el mismo orden. Los
algoritmos subordinados se escriben al final del algoritmo
principal y su nombre tiene que coincidir con el nombre que
aparece en la  instrucción de llamada al algoritmo
subordinado,  a continuación la lista de de
parámetros entre paréntesis separados por coma en el
mismo orden en que aparecen la llamada.

Ejemplo 11: Dado un conjunto de n triángulos, se
desea conocer:

     a)    El valor
máximo de la sucesión de perímetros.

b) Cuantos triángulos equiláteros, isósceles y
escalenos contiene el conjunto.

// Algoritmo Principal Triángulos

      Entrada n  // total de
triángulos

      CEQ = 0,  CES = 0, CIS =
0     // valores iniciales de  los
contadores

       Max = 0 ,P = 0 
    //valor inicial del perímetro
máximo, y el perímetro

           
Para I =1 hasta n

                
Entrada a, b, c   // lados del triángulo

                       
Llamada CalPer (a, b, c, P)

                       
Llamada  MaxPer (P, Max)

                       
Llamada ConTipoTrian (a, b, c, CEQ,  CES, CIS)

           
Próximo I

     Salida Max   //valor del
perímetro máximo

     Salida CEQ, CIS, CES // total de
triángulos equiláteros, isósceles y escalenos

    //Fin del Algoritmo Principal

          
//Algoritmo Auxiliar Calculo Perímetro

           
      CalPer (a, b, c, P)

   
              P
= a + b + c

          //Fin
Algoritmo Auxiliar

         
//Algoritmo Auxiliar Máximo

           
      MaxPer (P, Max)

                
Si P > Max

                                 
Entonces

                                    
Max = P

              
  Fin Si  

          //Fin
Algoritmo Auxiliar

         
//Algoritmo Auxiliar Contar tipo de triángulo

             
ConTipoTrian (a, b, c, CEQ,  CES, CIS)

             
Si a = b y b = c

                       
Entonces

           
              
 CEQ = CEQ +1       

           
           Sino
Si a = b o b = c o a = c

                                              
Entonces

                   
                          CIS=
CIS+1

           
                               Sino

                                              
    CES = CES +1

                      
Fin Si

               
Fin Si

        
  //Fin Algoritmo Auxiliar

 

La forma de escribir los algoritmos diseñando el
algoritmo principal y los algoritmos auxiliares, es conocida como
diseño estructurado
(modular) y más que una técnica de diseño
constituye una filosofía de
programación.

I.4.2  Algoritmos recursivos y Algoritmos de
ordenamiento:

Un algoritmo recursivo es aquel que contiene un
procedimiento recursivo, un procedimiento recursivo queda
definido mediante  una función recursiva.

La teoría de las funciones recursivas fue
desarrollada a finales de la primera mitad del siglo pasado.

Vamos a considerar funciones de  argumentos de la
forma:

                                  
,

donde  denota el
conjunto de los números naturales. Intuitivamente, una
función computable (o calculable) es una función
numérica cuyo valor puede ser hallado mediante algún
algoritmo.

Analicemos el caso particular .
Supongamos que su valor se halla a través del siguiente
esquema de cálculo:

                       

Definición 2: Una función numérica cuyo
valor se calcula con ayuda de un esquema de cálculo
recursivo, se llama función primitiva
recursiva
.

Ejemplos 12:

           
1.

Podemos apreciar que ,
, …,
. Así, por
inducción se establece
que – suma de dos
números naturales.

           
2.

Tenemos que , , …,
. Por tanto,
– producto de dos
números naturales.

           
3. Introduzcamos la operación de diferencia truncada:

           
    

Mostremos que esta función es primitiva recursiva. 
Primero vamos a probar que  es primitiva
recursiva. De hecho,

           
  

A seguir, es fácil ver que:

           
  

           

De forma general, la recursividad es un método de definir
una función mediante el cual para una cantidad arbitraria de
argumentos, un valor de ella se calcula por medio de un esquema
determinado a través de los valores de la función ya
conocidos o calculados anteriormente. Así obtenemos:

           
 

En resumen, un procedimiento recursivo es aquel, en el cual
una función se llama a sí. La recursividad es una forma
poderosa, elegante y natural de resolver una amplia clase de problemas.

El factorial de un número n€N se define como,

Es decir si n ³1, n! es igual al producto de todos los
enteros entre 1 y n.

Por ejemplo 5!= 5 4 3 2 1=120

Observemos que n! puede escribirse en términos de sí
mismo pues si quitamos n, el producto restante es tan solo
(n-1)!, es decir,

n! = n (n-1) (n-2)…2 1= n (n-1)!

Por ejemplo 5!= 5 4!

La ecuación  n! = n (n-1)!, muestra como descomponer
el problema original (calcular n!) en subproblemas cada vez
más sencillos (calcular (n-1)!, calcular (n-2)!…). Al
final las soluciones de cada subproblema
se combinan (multiplicando) para resolver el problema
original.

Por ejemplo el problema 5! se reduce a calcular 4!; el
problema 4! se reduce a calcular 3!; el problema 3! se reduce a
calcular 2!; el problema 2! se reduce a calcular 1! y el problema
1! se reduce a calcular 0! Que por definición es 1.

Una vez que el problema original se ha reducido a resolver
subproblemas, la solución del subproblema más sencillo
puede utilizarse para resolver el siguiente subproblema más
sencillo, y así sucesivamente, hasta lograr la solución
del problema original .

Por ejemplo 5!,

0! = 1

1!=1  0!=1

2!=2  1!=2

3!=3  2!=3 2=6

4!=4  3!=4  6=24

5!=5  4!=5  24=120

Ahora escribiremos un algoritmo para el calculo del factorial,
esto no es más que una traducción de la
ecuación n! = n (n-1)!.

Para definir un procedimiento recursivo utilizaremos la
instrucción,

Procedimiento [nombre] [
(Lista de parámetros) ]

Ejemplo 13:

// Calculo del factorial con recursividad.

 Entrar n

  Procedimiento factorial (n)

   Si n = 0 entonces

           
           
Fac.=
1               

               
 Sino

                    
Fac = (n factorial(n-1))

    Fin Si

 Salida Fac.

Consideremos n = 3, como 3 es distinto de 0, la ejecución
va a la línea debajo de la palabra reservada Sino, sustituye
a n por 3 y llama al procedimiento factorial para el valor n=2,
de forma análoga el procedimiento se ejecuta hasta obtener
Fac = (3 2 1 factorial (0)), se  verifica la condición,
por lo que factorial (0) retorna el valor Fac =1.

Teorema 1: El algoritmo anterior produce como salida el
valor de n!,

Demostración (Por inducción matemática):

Paso base (n = 0). Ya hemos observado que para n = 0,
el algoritmo produce como salida el valor 1.

Paso inductivo. Supongamos que el algoritmo produce
correctamente el valor para  (n -1)!, n > 0. Ahora
supongamos que n es la entrada del algoritmo. Como n ¹ 0, al
ejecutar el algoritmo vamos a la línea debajo de la palabra
reservada Sino. Por la hipótesis de
inducción el procedimiento calcula correctamente el valor (n
-1)!. En la línea debajo de la palabra Sino el procedimiento
calcula correctamente (n -1)! n = n!

Por tanto el algoritmo produce como salida el valor de n! para
cada entero

n ³ 0.

Deben existir ciertas situaciones en las que un procedimiento
recursivo no se llama a sí mismo, en caso contrario se
llamaría a si mismo por siempre. En el algoritmo anterior,
si n = 0, el procedimiento no se llama a sí mismo. Los
valores para los que un procedimiento recursivo no se llama a
sí mismo son los casos bases. Todo procedimiento recursivo
debe tener casos bases para lograr que el procedimiento recursivo
concluya.

La inducción matemática nos ha permitido demostrar
que un algoritmo recursivo calcula el valor que afirma calcular.
Con frecuencia, una demostración por inducción
matemática puede considerarse un algoritmo, donde el paso
base de inducción corresponde  a los casos base de un
procedimiento recursivo, y el paso inductivo corresponde  a
la parte donde el procedimiento recursivo se llama a sí
mismo.

Un problema clásico solucionado con la
implementación de algoritmos es el siguiente: Dado un
conjunto (lista) de n elementos {a1,
a2,…, an} y una relación de orden
(≤) sobre ellos se desea obtener los elementos ordenados de
forma creciente (decreciente). 

La idea general del ordenamiento consiste en encontrar una
permutación que ordene los elementos de la lista. Varios
factores pueden influir al ordenar una lista: tipo y tamaño
de los elementos,  la distribución  de los
elementos en la lista, el agente de cómputo en donde se
encuentran almacenados.

Existen  distintos algoritmos, con distintos ordenes de
eficiencia, que resuelven el problema de ordenar los elementos de
una lista, aquí nos limitaremos a  presentar sólo
dos de ellos:

 Algoritmo de ordenación secuencial: Este
algoritmo ordena los elementos de la lista en orden creciente
(decreciente). La idea del algoritmo consiste en realizar 
permutaciones de forma secuencial comenzando por el primer
elemento de la lista, por ejemplo: sea la lista {7, 8, 3, 5},
ordenémosla de menor a mayor, tomamos el primer elemento y
lo comparamos con los restantes elementos permutándolos
cuando sea necesario, obtenemos la lista {3, 8, 7, 5}, tomamos el
segundo lo comparamos con los restantes elementos y permutamos
cuando es necesario, obtenemos {3, 5, 8, 7}, se continua el
proceso hasta obtener la lista ordenada {3, 5, 7, 8}.

Ejemplo 14:

// Ordenar de menor a mayor

Entrar n  //tamaño de la lista

Para I =1 hasta n

    Entrar  A (I)  //elementos de la
lista

Próximo I

//ordenamiento secuencial

    Para I =1 hasta n-1

         Para  J
= 2 hasta n

              
Si A(I) > A(J) entonces

                             
        Tem = A(J)

                                  
      
A(J)=A(I)     //permutación de los
elementos

                                      
A(I) = Tem

              
Fin Si

        Próximo J

    Próximo I

Para I =1 hasta n

    Salida  A(I) // lista ordenada de
menor a mayor

Próximo I

// Fin del algoritmo

Algoritmo de ordenación burbuja: El nombre de este
algoritmo trata de reflejar cómo el elemento mínimo
"sube", a modo de burbuja hasta el principio de la lista,
consiste en recorrer los elementos de la lista tomados los dos
consecutivos siempre en la misma dirección, comenzando por
el último elemento de la lista intercambiando elementos si
fuera necesario, por ejemplo, sea la lista {7, 8, 3, 5},
ordenémosla de menor a mayor, tomamos el último
elemento y lo comparamos con el anterior, luego el anterior con
el siguiente en la misma dirección continuamos el proceso y
obtenemos {3, 7, 8, 5},  a esta nueva lista le realizamos de
nuevo el procedimiento anterior, obtenemos la lista ordenada {3,
5, 7, 8}.

Ejemplo 15:

// Ordenar de menor a mayor

Entrar n       //tamaño de
la lista

Para I =1 hasta n

    Entrar 
A(I)      //elementos de la lista

Próximo I

//ordenamiento burbuja

    Para I =1 hasta n-1

         Para  J
= n hasta I +1 paso  -1

              
Si A(J-1) > A(J) entonces

            
                         Tem
= A(J)

                                  
      
A(J)=A(J-1)     //permutación de los
elementos

                                      
A(J-1) = Tem

              
Fin Si

        Próximo J

    Próximo I

// Fin ordenamiento burbuja

Para I =1 hasta n

    Salida
 A(I)      // lista ordenada de
menor a mayor

Próximo I

// Fin del algoritmo

Ejercicios para el trabajo independiente:

Escribir un algoritmo para calcular:

1. El valor de la función G(y ,z)= y2 +
Exp (z/2),  donde  y =2×2+ x +
1, 

     z = (x2
+y2)1/2.

2. La función:

3. El valor de la función H (y ,z) = Ln
(y2 ) – 1/ z1/2.,  donde 
y =2×2+ x, 

    z = x +y.

4. Dados  tres ángulos se desea determinar:

    a) Si estos ángulos pueden determinar
un triángulo.

    b) Si el triángulo es rectángulo,
acutángulo o obtusángulo.

    c) El mayor lado del triangulo.

    d) La diferencia entre la suma de los
ángulos interiores y los ángulos  
exteriores.

Escriba un algoritmo.

5. Dados los valores de verdad de las preposiciones simples p
, q. Determine el valor de verdad de las proposiciones
compuestas:

   a)   p y q
(p^q)                                             

   b)   p o q (pvq),

 Nota: 1 (verdadero), 0 (falso)

p

Q

p^q

pvq

1

1

1

1

1

0

0

1

0

1

0

1

0

0

0

0

Escriba un algoritmo.

6. Dada una sucesión (lista) de n números
reales. Escriba un algoritmo para:

 a) Calcular la suma de los elementos de la
sucesión.

 b) Determinar el mayor y el menor elemento de la
sucesión.

 c) Determinar cuantos elementos  son mayores que la
suma. 

7. Escriba un algoritmo para determinar la factorial de un
entero no negativo n.

Nota: Escriba un algoritmo donde se emplee la instrucción
iterativa con contador y otro donde emplee la instrucción
iterativa con condición, para definir el ciclo.

8. Escriba un algoritmo para determinar el mayor y menor
elemento de las sumas parciales de una sucesión de n
números reales.

9. Escriba un algoritmo para determinar el mayor y menor
elemento de las sumas consecutivas de una sucesión de n
números reales.

10. Escriba un algoritmo para determinar el máximo
común divisor (MCD) de dos enteros no negativos.

11. Dadas dos sucesiones de  n
números naturales. Escriba un algoritmo para calcular el
número de pares de números, correspondiente a cada
sucesión, múltiplos entre si.

12. Escriba un algoritmo para contar las consonantes de una
frase que contiene 20 caracteres.

13. Escriba un algoritmo para contar las vocales de una frase
que culmina con el caracter *.

14. Sea un conjunto cuyos elementos son las palabras del
idioma español formadas por 5
caracteres, cuya última palabra es cinco. Escriba un
algoritmo para:

a) Determinar cuantas palabras comienzan con vocal y cuantas
comienzan con consonante.

b) Calcular el número de vocales de cada palabra.

c)  Calcular el total de consonantes del conjunto.

15. Escriba un algoritmo para determinar cuantos números
enteros existen en el intervalo [1; 1000], que sólo son
divisibles por tres números enteros distintos.

16. Dada una matriz de dimensión n x n. Escriba un
algoritmo que:

  a) Encuentre el mayor elemento de cada columna.

  b) Encuentre el menor elemento de cada fila.

  c) Calcule: la suma de los elementos no negativos de la
diagonal principal y producto de los elementos negativos  de
la diagonal principal.

  d) Calcule la factorial de la suma de los elementos no
negativos.

Nota: 1. Escriba un algoritmo donde se emplee la
instrucción iterativa con contador y otro donde emplee la
instrucción iterativa con condición, para definir el
ciclo y las variables indexadas.

           
2. Escriba el algoritmo empleando algoritmos auxiliares.

17. Para los ejercicios 6, 8, 9, 11, 13, 14, 15 escriba un
algoritmo estructurado, empleando arreglos.

18. Escriba el algoritmo estructurado, empleando arreglos para
calcular:

           
 ,   
para todo n, m que pertenecen a los naturales.

19. Escriba un algoritmo donde se implemente un procedimiento
recursivo para los ejercicios:7 , 10 y 18.

20. Un robot puede dar pasos de 1 o 2 metros. Escribir un
algoritmo para el cálculo del número de formas en que
el robot puede recorrer n metros.

21. Escriba los algoritmos de ordenamiento para ordenar una
lista de mayor a menor. Impleméntelos utilizando
instrucción iterativa con condición.

Análisis de los
algoritmos

II.1  Complejidad Computacional:

Cada programador desea escribir el  algoritmo o 
programa más eficaz para
el problema que desea resolver. Tal acercamiento nos conlleva a
pensar, ¿qué hace que un algoritmo sea difícil de
ejecutar por un agente de cómputo?, esto es lo que de forma
intuitiva se define como complejidad computacional. Lo
anterior nos lleva a definir criterios para medir la eficiencia
del algoritmo. Como eficiente puede entenderse el
algoritmo o programa que minimiza los recursos que emplea el
agente de cómputo para lograr la solución del problema
planteado, es decir, el problema radica en minimizar ciertas
función de costo, por ejemplo, el tamaño del programa,
el número de pasos a ejecutar por el agente de computo, la
economía de la memoria, la velocidad de ejecución,
la simplicidad de su implementación, etc.

Ejemplo 16. Para resolver el sistema de ecuaciones algebraicas
lineales  de orden
 con ayuda de la
regla de Cramer se necesitan hallar las componentes del vector
 como la
relación de determinantes: , para
. Si se calculan los
determinantes directamente a partir de su definición, es
necesario realizar  multiplicaciones
y  sumas. Supongamos
que para los cálculos empleamos un agente de cómputo
que realiza  multiplicaciones
por segundo, y que queremos resolver un sistema con
 incógnitas
(bien pequeño para los que surgen en aplicaciones
prácticas). Entonces el cálculo de un solo determinante
necesita  multiplicaciones,
y por tanto, para hallar la solución se requiere
aproximadamente de 10 años de trabajo continuo del agente de
cómputo. Por otro lado, para la solución de este mismo
sistema en la misma máquina usando el método de Gauss,
sólo se necesitan . Esto indica
que como algoritmo de cálculo, la regla de Cramer no debe
ser tomada en consideración.

Ejemplo 17. Supongamos que se necesita calcular
, donde
 es un número
natural. El cálculo de esta magnitud usando multiplicaciones
sucesivas por  exige que se
realicen  operaciones de
multiplicación. No es difícil convencerse de que este
método no es el más efectivo. Por ejemplo,
 puede hallarse
realizando no 63, sino sólo 6 operaciones de
multiplicación, si de manera sucesiva elevamos al cuadrado y
calculamos , , , , , En general,
representamos  como potencias de
2:

                       
,

donde  es un número
estándar para cada agente de cómputo, y
 son cifras
binarias. Entonces

                       
.

Note que en estos productos solamente debemos
considerar aquellos factores para los cuales , o sea, cuando
. Un algoritmo basado
en la descomposición anterior se llama algoritmo
binario
.  Este permite hallar  en a lo sumo
 operaciones de
multiplicación.

Otra medida de la eficiencia de un algoritmo es la
exactitud, lo cual significa que un algoritmo de
cálculo debe ser capaz de proporcionar una solución del
problema con una exactitud  dada o adecuada
para el problema en cuestión.

Dos direcciones pueden adoptarse para evaluar la complejidad
de un algoritmo:

En la primera,  nos preocupamos por la complejidad
estática de un algoritmo,
relacionada con la complejidad del texto del algoritmo (por
ejemplo, su longitud, su complejidad estructural,  la
variedad de tipos de la instrucción usadas en él,
etc.). Esta medida de complejidad caracteriza al algoritmo 
independientemente de los datos de entrada a los que pueden
aplicarse el algoritmo.  El segundo, nos preocupamos por la
complejidad dinámica, está
relacionado con el uso de los recursos requeridos por el agente
de cómputo para llevar a fin la ejecución del algoritmo
para una entrada determinada de datos (por ejemplo, tiempo para
su ejecución, memoria, etc.

La complejidad (estática y dinámica) de un algoritmo
depende de varios elementos: el formalismo con que es expresado
el algoritmo, el agente de cómputo que lo ejecuta, y el
criterio para evaluar su eficacia.

Las dos direcciones, estática o dinámica, pueden ser
usadas para escoger el algoritmo menos complejo entre dos o
más algoritmos equivalentes que  resuelven el mismo
problema. Lo anterior impone evaluar la complejidad
intrínseca del problema a solucionar. Esto nos conlleva a
considerar todos los algoritmos que resuelven el problema dado, y
evaluar la complejidad entre ellos para obtener el menos
complejo.

Claro, evaluar la complejidad intrínseca de un problema
es en general una tarea difícil, porque puede existir un
gran número de algoritmos equivalentes diferentes que
resuelven el problema dado. En general la complejidad de un
algoritmo sólo es determinada de manera aproximada, por
medio de acotaciones (una cota  superior y una cota
inferior).  Dos estrategias pueden seguirse para
obtener una aproximación más fina de la complejidad de
un algoritmo. La primera consiste en disminuir la cota superior,
la otra aumentar la cota inferior.

Un rasgo muy importante para la teoría de la complejidad
es lograr estudios generales, independientes del agente de
cómputo que ejecutará el algoritmo, lo anterior no
minimiza la importancia de obtener medidas de complejidad
específicas al agente de cómputo que ejecuta el
algoritmo.

II.1.1   Axiomas de Blum.

El estudio de la complejidad abstracta proporciona resultados
que se sostienen para cualquier agente de cómputo, y
cualquier criterio para evaluar el costo de la ejecución del
algoritmo. Esta generalidad tiene algunas desventajas, pues se
obtienen en algunos casos resultados paradójicos, pues no se
consideran algunos elementos específicos  del agente de
cómputo.

Considere la  lista de todos los agentes de cómputo
(M1,M2,…), y correspondientemente, una
lista (T1(n),T2(n),…) de las funciones
para evaluar el costo de ejecución de cada agente,
Tk(n) es una función definida en los naturales
(Tk: N–>N), la cual indica el costo de
ejecución del agente Mk para una entrada n. Es
decir, la función Tk(n) puede ser considerada
como el número de unidades de recurso consumidos en la
ejecución por el agente de cómputu Mk para
una entrada n (Mk(n)).

La lista  (T1(n),T2(n),…)
proporciona una medida de complejidad si se satisfacen los
siguiente dos requisitos (Axiomas de Blum ):

  1. Para todos los números naturales k y n,
    Tk(n) esta  definida si y sólo si
    Mk(n) esta  definida.
  2. Existe un algoritmo, que para valores arbitrarios 
    k,  n y m, decide si Tk(n)=m o no.

El primer axioma expresa la idea: el costo de ejecución
para cualquier algoritmo que es ejecutado hasta el final es
calculable, pero debe ser considerado como indefinido el costo de
ejecución de los algoritmos cuya ejecución no concluye,
el segundo axioma exige la existencia de un procedimiento
algorítmico para decidir si una máquina dada
Mk, para una entrada dada n, consume m unidades de
recurso.

Esto significa que a medida que la ejecución avanza se
consumen más  unidades del recurso, por consiguiente,
para verificar si Tk(n)=m, podemos simplemente observa
Mk para la entrada n durante un tiempo finito, esto
define el período en que son consumidas las m unidades del
recurso.  Si Mk se detiene en este período,
entonces Tk(n)=m, si Mk se detiene antes, o
si continua, entonces Tk(n) es diferente de m, debe
notarse que, para el caso contrario, no tendría 
sentido exigir un algoritmo para decidir si Tk(n)=m,
para k, n y m arbitrarios.

Como se ha mostrado,  los requisitos de los axiomas
anteriores  son muy generales, y expresan el deseo de ser
satisfechos para cualquier medida de complejidad, por lo que
estos no son suficientes, por ejemplo: considerando
Tk(n) = Mk(n) para todo  n y k, se
satisface el axioma 1, sin embargo,  el axioma 2 no se
satisface, pues no se puede decidir si la máquina concluye
la ejecución. Como otro ejemplo, consideremos
Tk(n)=0 para todo n y k (es decir la ejecución
está libre de costo), el axioma 2 se satisface, pero se
viola el axioma 1, porque la lista de todas las máquinas  incluye
necesariamente algunas que no concluyen la ejecución. Los
ejemplos anteriores  muestran que los axiomas de Blum pueden
satisfacerse independientemente, y por consiguiente estos son
independientes.

Como hemos expresado la complejidad de un algoritmo 
define el uso eficiente de los recursos, por el agente de
cómputo para ejecutarlo. Frecuentemente  la eficiencia
se mide en función de dos parámetros: el tiempo que
empleó el agente de cómputo Mk para ejecutar
un número finito de pasos para una entrada n
Sk(n) y el número de células (espacios de
memoria) Ck(n) necesarias que usó el agente de
cómputo Mk para la entrada n al ejecutar el
algoritmo (medidas de complejidad), es decir, la complejidad
temporal y capacitiba. La primera medida Sk(n) parece
violar el axioma 1 de Blum, porque un algoritmo que no concluye
la ejecución podría usar un número finito bien
definido de células (espacios de memoria). Lo anterior se
evita al considerar por definición a Ck(n) como
indefinido, de esta  manera el axioma 1 se satisface y el
axioma 2 también es satisfecho en todos los casos, pues
podemos decidir si Mk para la entrada n ejecuta el
algoritmo, tal que Ck(n)=m para todo k, n y m
arbitrario, lo anterior se sustenta en el hecho que hay sólo
un número finito de configuraciones de la máquina
diferentes de m.

Según lo expresado, una medida de complejidad 
consiste en asignar una función de costo, para evaluar
cómo cada agente de cómputo ejecuta un algoritmo. 
Diremos, que el agente de cómputo Mr es
menos  complejo que el agente Ms, respecto ha
cierta función T(n) dada, si para todas las entradas
suficientemente grande n (de longitud mayor que algún valor
dado q), Tr(n) está definida siempre que
Ts(n) este definida, y el valor Tr no es
mayor que el valor de Ts.

II.2  Complejidad temporal.

El tiempo de ejecución de un algoritmo va a depender de
diversos factores: los datos de entrada, las características
del agente de cómputo, la complejidad intrínseca del
algoritmo. Con el florecer de computadoras a partir de la
década 1960-70, la comunidad científica
convino  que la medida más significativa de la eficacia
de un algoritmo es la expresión matemática que define
el tiempo de ejecución del algoritmo por el agente de
cómputo, la cual se expresa como una función de los
datos de entrada T(n), complejidad temporal. T(n) es una
función creciente de n.

Es posible realizar el estudio del tiempo de ejecución de
las maneras siguientes:

  1. Consiste en obtener una función que acote (superior e
    inferiormente) el tiempo de ejecución para unos valores de
    entrada, esto nos  proporciona una medida teórica a
    priori.
  2. Medir el tiempo de ejecución en un agente de
    cómputo especifico para unos valores de entrada dados,
    esto nos proporciona una medida real a posteriori.

Ambas medidas son importantes, la primera nos ofrece
estimaciones del comportamiento del algoritmo
de forma independiente del agente de cómputo en el cual
será ejecutado, la segunda representa la medida real del
comportamiento del algoritmo.

En los algoritmos secuenciales una medida de complejidad
temporal viene expresada por el número de operaciones
elementales (OE) que realiza cada instrucción del algoritmo
a ejecutar por el agente de cómputo para una entrada
determinada n, es decir las operaciones que el agente de
cómputo ejecuta en un tiempo acotado para la entrada n.

Consideraremos OE:

  1. Las operaciones aritméticas básicas.
  2. Las asignaciones a variables.
  3. Las llamadas y retorno a algoritmos auxiliares.
  4. Retorno a las instrucciones de inicio de ciclo.
  5. Las operaciones lógicas (relaciones de orden unidas a
    los operadores lógicos).
  6. Variables dimensionales, cada índice de la variable
    dimensional contabilizará como una OE.

Ejemplo 18: Para el algoritmo del ejemplo 9 calcular el
número de OE.

  • En la línea (2) se ejecutan 3 OE
    (asignación).
  • En la línea (3) se ejecutan 3 OE
    (asignación).
  • En la línea (4) se ejecutan  un total de 5 OE
    (3 operaciones de relación y 2 operaciones
    lógicas).
  • En la línea (5) se ejecutan 3 OE (2 operaciones de
    relación y 1 operación lógicas).
  • En la línea (7) se ejecutan 1 OE
    (asignación).
  • En la línea (8) se ejecutan 2 OE (un incremento
    (suma) y una asignación).
  • En la línea (9) se ejecutan  un total de 5 OE
    (3 operaciones de relación y 2 operaciones
    lógicas).
  • En la línea (11) se ejecutan 1 OE
    (asignación).
  • En la línea (12) se ejecutan 2 OE (un incremento
    (suma) y una asignación).
  • En la línea (14) se ejecutan 1 OE
    (asignación).
  • En la línea (15) se ejecutan 2 OE (un incremento
    (suma) y una asignación).
  • En la línea (19) se ejecutan 3 OE
    (asignación).
  • En la línea (20) se ejecutan 1 OE (retorno al inicio
    del ciclo).
  • En la línea (21) se ejecutan 1 OE (un incremento
    (suma)).

Tenemos un total de 33 OE, pero debemos tener presente que las
líneas 4 y 20 definen un ciclo, por lo que las operaciones
de las líneas (5), (7), (8), (9), (11), (12), (14), (15) y
(19) se ejecutaran tantas veces como veces se ejecute el
ciclo.

La función temporal T: N–>R+, depende del tamaño
de los datos de entrada, por ejemplo: si tenemos que evaluar un
polinomio de grado n, multiplicar dos matrices cuadradas de orden
n.

Ejemplo 19: Para el algoritmo del ejemplo 18
determinemos una expresión para calcular su tiempo de
ejecución.

Como mostramos en el ejemplo 12, el algoritmo realiza 7 OE
fuera del ciclo y 26 dentro del ciclo, por tanto  T(n) =26
(n -1)+7= 26n -19

T(n) es una función que mide el número de OE de un
algoritmo para una entrada n, independiente del agente de
cómputo.

Comúnmente para la solución de un problema puede
obtenerse dos o más implementaciones de un algoritmo, por lo
que es necesario acotar la diferencia que se puede producir entre
ellas.

 Teorema  2 (Principio de Invarianza):

Sea A un algoritmo y I1 e I2 dos
implementaciones que concluyen la ejecución, sean
T1(n) y T2(n) el tiempo de ejecución
de I1 e I2, entonces E C€R, c > 0
y no€N, tal que "n ³ n0, se
verifica que T1(n)  ú c
T2(n).

Demostración:

Sean dos sucesiones finitas que representan el tiempo de
ejecución de cada una de las instrucciones correspondientes
a las implementaciones I1 e I2, para la
entrada n ³ no, no es un número
fijo:

Consideremos , i = 1, 2,…,p, j
= 1,2,…,q,,

Denotemos por T1(n) y T2(n) el tiempo
total de ejecución de las dos implementaciones, de forma
que

 

Entonces,

Luego,

-       Nota: Este teorema
fue presentado en el Libro en formato
electrónico (Internet). Universidad de Málaga, 
1999, sin demostración.

      La demostración del
mismo es original de los autores de la monografía.

El Principio de Invarianza nos dice que el tiempo de
ejecución de dos implementaciones distintas de un algoritmo
dado no van diferir más que en una constante
multiplicativa.

En otras palabras un algoritmo tarda en su ejecución un
tiempo del orden T(n) si existe una constante real c > 0 y una
implementación I del mismo que tarda menos que cT(n), para
toda entrada de tamaño n.

Es importante tener en cuenta las constantes c y no
para las que se verifican las condiciones, pues, por ejemplo,
sean dos implementaciones de un algoritmo, tal que
T1(n)=105n2 y
T2(n)=2n3, el primero sólo
será mejor que el segundo para n > 50.000.

 II.2.1  Cotas asintóticas de complejidad
temporal.

Se desea estimar medidas para el tiempo de ejecución que
permitan comparar la eficiencia de los algoritmos, por ejemplo,
si determinamos la cota superior del tiempo de ejecución de
un algoritmo podemos asegurar que, en ningún caso, el tiempo
de ejecución será superior al de la cota.

Definición 3: Sean T1 y T2
funciones de N–>R+. Escribimos  T1(n) =
O(T2(n)), y diremos que T1(n) es de orden a
la sumo de T2(n), si E C1€R,
C1 > 0 tal que T1(n)  menor o igual
C1 T2(n), An€N, excepto para un
número finito.

La igualdad
T1(n)=O(T2(n)) expresa que T1(n)
esta acotada superiormente por  T2(n),.excepto
para un número finito de
excepciones.         
       

       ,

donde C1 es una constante. El símbolo O(1)
denota una función acotada por una constante. 

Propiedades de O:

  1. T1= O(T1(n))
  2. T1= O(T2(n))  –> 
    O(T1(n)) <
     O(T2(n))  
  3. O(T1(n)) = O(T2(n))  
    <–> T1= O(T2(n))  y
    T2= O(T1(n)) 
  4. Si T1(n) = O(T2(n))  
    y  T2(n) = O(T3(n))  
    –>  T1(n) = O(T3(n))
  5. Si T1(n) = O(T2(n))  
    y  T1(n) = O(T3(n))  
    –>  T1(n) = O(min(T2(n),
    T3(n))).
  6. Si T1(n) = O(T2(n))  
    y  T3(n) = O(T4(n))  
    –>  T1(n) +T3(n)=
    O(max(T2(n), T4(n))).
  7. Si T1(n) = O(T2(n))  
    y  T3(n) = O(T4(n))  
    –>  T1(n) T3(n)=
    O(T2(n) T4(n)).
  8. Si  $  ,
    dependiendo de los valores de que tome C1
    tenemos:

a)     Si
C1€(0,Ñ)  entonces 
O(T1(n)) = O(T2(n))  

          
b)  Si C1= 0  entonces  T1=
O(T2(n))  –>  O(T1(n)) <
O(T2(n))  

Definición 4: Sean T1 y T2
funciones de N–>R+. Escribimos  T1(n) =
W(T2(n)), y diremos que T1(n) es de orden
al menos de T2(n), si E C2€R,
C2 > 0 tal que T1(n)  ³
C2 T2(n), An€N, excepto para un
número finito.

La igualdad T1(n)=W(T2(n)) expresa que
la función T1(n) esta acotada inferiormente
por  T2(n), excepto para un número finito de
excepciones.                                

Propiedades de W:

  1. T1= W (T1(n))
  2. T1= W (T2(n))  –>  W
    (T1(n)) <  W
    (T2(n))  
  3. W (T1(n)) = W (T2(n))  
    <–> T1= W (T2(n))  y
    T2= W (T1(n)) 
  4. Si T1(n) = W (T2(n))  
    y  T2(n) = W (T3(n))  
    –>  T1(n) = W (T3(n))
  5. Si T1(n) = W (T2(n)) y 
    T1(n) = W (T3(n))  
    –>  T1(n) = W (max(T2(n),
    T3(n))).
  6. Si T1(n) = W (T2(n))  y 
    T3(n) = W (T4(n)) –> T1(n)
    +T3(n)= W (T2(n)+
    T4(n))).
  7. Si T1(n) = W (T2(n))  
    y  T3(n) = W (T4(n))  
    –>  T1(n) T3(n)= W
    (T2(n) T4(n)).
  8. Si  $  ,
    dependiendo de los valores de que tome C2
    tenemos:

Partes: 1, 2, 3
 Página anterior Volver al principio del trabajoPágina siguiente 

Nota al lector: es posible que esta página no contenga todos los componentes del trabajo original (pies de página, avanzadas formulas matemáticas, esquemas o tablas complejas, etc.). Recuerde que para ver el trabajo en su versión original completa, puede descargarlo desde el menú superior.

Todos los documentos disponibles en este sitio expresan los puntos de vista de sus respectivos autores y no de Monografias.com. El objetivo de Monografias.com es poner el conocimiento a disposición de toda su comunidad. Queda bajo la responsabilidad de cada lector el eventual uso que se le de a esta información. Asimismo, es obligatoria la cita del autor del contenido y de Monografias.com como fuentes de información.

Categorias
Newsletter