Vous êtes sur la page 1sur 56

Análisis de Algoritmos

1 INTRODUCCION

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


1
Análisis de Algoritmos

1. Introducción a los Problemas

Un problema es un asunto o un conjunto de cuestiones que se plantean para ser


resueltas. La naturaleza de los problemas varía con el ámbito o con el contexto donde
están planteados; existen problemas matemáticos, químicos, filosóficos, etc.

Muchas veces, la mitad del trabajo es saber exactamente qué problema hay que
resolver. Si al tratar de resolver un problema este no tiene una descripción simple o
precisa resulta complejo modelar, simular o programar su solución en un computador.
En este punto hay que dar importancia de ciertos aspectos relacionados con la
resolución de problemas entre los que podemos mencionar estrategias, notaciones de
representación, relaciones entre problemas.

Esta fase está dada por el enunciado del problema, el cual requiere una definición clara
y precisa.

Tomar en cuenta que la solución del problema debe estar en función de lo que el
problema requiera y no en función de lo que el programador quiera.

Es importante que se conozca lo que se desea que realice la computadora; mientras


esto no se conozca del todo no tiene mucho caso continuar con la siguiente etapa.

1.1 Análisis del Problema

No existe un método general para la resolución de problemas, la resolución de un


problema es un proceso creativo donde el conocimiento, la habilidad y la experiencia
tienen un papel importante, el proceder de manera sistemática ayuda a resolver un
problema.

Al comenzar a abordar un problema hay que tener en cuenta que para la mayoría de
ellos hay muchas maneras de resolver y pueden existir muchas soluciones, se plantean
algunos criterios o estrategias generales que se deben tomar en cuenta, las cuales son
útiles en el análisis del problema.

Usar toda la información útil (no superficial) disponible en el enunciado del


problema.
Hacer explícita las reglas y datos que aparezcan implícitos (en muchos
problemas numéricos se pueden utilizar reglas de la aritmética o álgebra)
Profundizar en el problema considerado (emplear algún tipo de notación).
Dividir el problema complejo en subproblemas más simples. que se pueden
resolver independientemente y después combinar sus soluciones.
Otra forma de abordar el problema consiste en trabajar “hacia atrás” es decir
parir de la solución e intentar llegar al estado inicial.

El propósito del análisis del problema es ayudar al programador para llegar a una
cierta comprensión de la naturaleza del problema. Una buena definición del problema
junto con una descripción detallada de las especificaciones de entrada y de salida, son
los requisitos más importantes para llegar a una solución eficaz.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


2
Análisis de Algoritmos

Análisis del
problema

Definición del Especificación de Especificación de


problema datos de Entrada datos de Salida

Fig.:1.1 Análisis del Problema

Una vez que se ha comprendido lo que se desea de la computadora, es necesario


definir:

Los datos de entrada.


Cual es la información que se desea producir (salida)
Los métodos y fórmulas que se necesitan para procesar los datos.

Una recomendación muy practica es el que nos pongamos en el lugar de la


computadora y analicemos que es lo que necesitamos que nos ordenen y en que
secuencia para producir los resultados esperados.

Ejercicio.- Leer el radio de círculo y calcular e imprimir su superficie.

Definición del problema.


Calcular la superficie de una circunferencia

Análisis del problema


La entrada a este problema es el radio de la circunferencia y de tipo real.
La salida de este problema es la superficie que también es de tipo real.

Una vez modelado el problema puede buscarse una solución en forma de algoritmo.
¨Algoritmo es una secuencia finita de instrucciones, cada una de las cuales tiene un
significado preciso y puede ejecutarse con una cantidad finita de esfuerzo en un tiempo
finito. Ha de tener las siguientes características: legible, correcto, modular, eficiente,
estructurado, no ambiguo y a ser posible se ha de desarrollar en el menor tiempo
posible

2. Introducción a los algoritmos y programas

El objetivo principal de la materia es el de enseñar a resolver problemas mediante una


computadora. Un programador de computadoras antes de nada es un resolvedor de
problemas.

Por lo que para llegar a ser un programador eficaz se necesita aprender a resolver
problemas de un modo riguroso y sistemático.

Vamos a considerar el significado de la palabra ALGORITMO esta palabra se deriva de


la traducción al latín de la palabra árabe ALKHÔWARÎZMI, nombre de un
matemático y astrónomo árabe que escribió un tratado sobre la manipulación de
números y ecuaciones en el siglo IX, titulado KITAB AL-JABR W’ALMUGALABA, la
palabra álgebra se derivó por su semejanza sonora de AL-JABR.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


3
Análisis de Algoritmos

Etimológicamente la palabra problema deriva del griego PROBALLEIN y significa


“algo lanzado hacia delante”.

Problema Diseño del Programa de


algoritmo computadora

Fig.:2.1. Esquema del desarrollo de algoritmos

2.1. Definición

“Un Algoritmo es una secuencia de operaciones detalladas y no ambiguas, que al


ejecutarse paso a paso, conducen a la solución de un problema”. En otras palabras es
un conjunto de reglas para resolver una cierta clase de problema.

“Algoritmo es un conjunto de instrucciones que especifican la secuencia de operaciones


a realizar, en orden, para resolver un sistema específico o clase de problema”.

“Un Algoritmo es la aplicación de pasos lógicos, secuenciales y metódicamente


aplicados para dar solución a un problema en cuestión.” En otras palabras un algoritmo
es una formula para resolver problemas.

“En otras palabras un algoritmo es una formula para la solución de un problema.”

“Todo problema se puede describir por medio de un algoritmo “

“Todo algoritmo es independiente del lenguaje”

2.2 Características De Los Algoritmos.

Las propiedades de un algoritmo son las siguientes:

a) El algoritmo debe ser preciso e indicar el orden de realización de cada paso.


b) El algoritmo debe ser definido, si se sigue un algoritmo dos veces, se debe obtener
el mismo resultado cada vez.
c) El algoritmo debe ser finito, si se sigue un algoritmo se debe terminar en algún
momento; o sea debe tener un número finito de pasos.

El algoritmo debe ser planteado como un sistema de información.

Entrada Proceso Salida

Modelo Resultados

Análisis
Fig.:.2.2 Representación de un algoritmo como un sistema de Información

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


4
Análisis de Algoritmos

2.3 Clasificación De Los Algoritmos

Se puede clasificar tomando en cuenta los aspectos.

Secuenciales
Condicionales
Repetitivos

2.4 Tipos De Algoritmos

Cualitativos: Son aquellos en los que se describen los pasos utilizando palabras.
Cuantitativos: Son aquellos en los que se utilizan cálculos numéricos para definir los
pasos del proceso.

2.5 Lenguajes Algorítmicos

Es una serie de símbolos y reglas que se utilizan para describir de manera explícita un
proceso.

2.6 Tipos De Lenguajes Algorítmicos

Gráficos: Es la representación gráfica de las operaciones que realiza un


algoritmo (diagrama de flujo).
No Gráficos: Representa en forma descriptiva las operaciones que debe realizar
un algoritmo (pseudocodigo).

Un algoritmo puede ser expresado de las siguientes formas.

Lenguaje Natural: el uso de términos del lenguaje natural, es una


forma de representar un algoritmo.
Lenguaje Simbólico: es otra forma de representación de un
algoritmo, que además permite una introducción a la programación estructural.
Lenguaje Gráfico: es una forma de escribir una secuencia de pasos
en forma de diagrama, en la practica se denomina Diagramas de Flujo.

Una receta de un plato de cocina se puede expresar en español, ingles o francés pero
cualquiera sea el lenguaje los pasos para la elaboración del plato se realizarán sin
importar el cocinero.

2.7 Diseño del Algoritmo

Un computador no tiene capacidad para solucionar problemas más que cuando se le


proporciona los sucesivos pasos a realizar. Estos pasos indican las instrucciones a
ejecutar por la máquina y se denomina algoritmo.

Las características de un buen algoritmo son:

Debe tener un punto particular de inicio.


Debe ser definido, no debe permitir dobles interpretaciones.
Debe ser general, es decir, soportar la mayoría de las variantes que se puedan
presentar en la definición del problema.
Debe ser finito en tamaño y tiempo de ejecución.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


5
Análisis de Algoritmos

Se pueden utilizar cualquier técnica de diseño de algoritmos, diseño descendente,


divide y vencerás.

Normalmente los pasos diseñados en un primer esbozo del algoritmo son incompletos
e indican solo unos pocos pasos, tras esta primera descripción estos se amplían en una
descripción más detallada con pasos específicos este proceso se denomina
refinamiento del algoritmo.

Ejemplo problema cálculo de la superficie de una circunferencia.

Calcular la superficie de un círculo

Calculo de la superficie
Entrada de datos Salida de resultados

Entrar el Radio S = PI * R ^2 S

En el diseño de un algoritmo tomamos en cuenta el siguiente desarrollo.

Diseño del algoritmo

 Diseño Refinamiento Herramienta de representación


Descendente por pasos  Diagramas de flujo
 Divide y vencerás  Pseudocódigo
 Diagramas
Nassi/Shneiderman-S
(Chapin)
 Método Warnier
 Método Jackson
 Método Bertini
 Método Tabourier

2.8 Verificación del algoritmo

Una vez que se ha terminado de escribir un algoritmo es necesario comprobar que


realiza las tareas para las que ha sido diseñado y produce el resultado correcto y
esperado.

El modo más normal de comprobar un algoritmo es mediante la ejecución manual


(prueba de escritorio), usando datos significativos que abarquen todo el posible rango
de valores y anotando en una hoja de papel las modificaciones que se producen en las
diferentes fases hasta la obtención de los resultados.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


6
Análisis de Algoritmos

2.9 Fase de Implementación

Una vez que el algoritmo está diseñado, representado gráficamente mediante una
herramienta y verificado se debe pasar a la fase de codificación, traducir el algoritmo a
un determinado lenguaje de programación que deberá ser completada con la ejecución
y verificación de resultado en el computador.

2.10 Codificación

La codificación es la operación de escribir la solución del problema (de acuerdo a la


lógica del diagrama de flujo o pseudocodigo), en una serie de instrucciones detalladas,
en un código reconocible por la computadora, la serie de instrucciones detalladas se le
conoce como código fuente, el cual se escribe en un lenguaje de programación o
lenguaje de alto nivel.

2.11 Prueba y Depuración

Los errores humanos dentro de la programación de computadoras son muchos y


aumentan considerablemente con la complejidad del problema. El proceso de
identificar y eliminar errores, para dar paso a una solución sin errores se le llama
depuración.

La depuración o prueba resulta una tarea tan creativa como el mismo desarrollo de la
solución, por ello se debe considerar con el mismo interés y entusiasmo.

Resulta conveniente observar los siguientes principios al realizar una depuración, ya


que de este trabajo depende el éxito de nuestra solución.

2.12 Documentación

Es la guía o comunicación escrita es sus variadas formas, ya sea en enunciados,


procedimientos, dibujos o diagramas.

A menudo un programa escrito por una persona, es usado por otra. Por ello la
documentación sirve para ayudar a comprender o usar un programa o para facilitar
futuras modificaciones (mantenimiento).

La documentación se divide en tres partes:

Documentación Interna
Documentación Externa
Manual del Usuario

Documentación Interna: Son los comentarios o mensaje que se añaden al código


fuente para hacer mas claro el entendimiento de un proceso.

Documentación Externa: Se define en un documento escrito los siguientes puntos:

Descripción del Problema


Nombre del Autor
Algoritmo (diagrama de flujo o pseudocodigo)
Diccionario de Datos
Código Fuente (programa)

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


7
Análisis de Algoritmos

Manual del Usuario: Describe paso a paso la manera como funciona el programa, con
el fin de que el usuario obtenga el resultado deseado.

2.13 Técnicas Para La Formulación De Algoritmos

Para representar una algoritmo se debe utilizar algún método que permita
independizar dicho algoritmo del lenguaje de programación elegido. Ello permitirá que
un algoritmo pueda ser codificado inmediatamente en cualquier lenguaje.

Las herramientas utilizadas comúnmente para diseñar algoritmos son:

Pseudocodigo
Diagrama de Flujo.
Diagramas Nassi/Shneiderman-S (Chapin)
Método Warnier
Método Jackson
Método Bertini
Método Tabourier

2.13.1Pseudocodigo

Mezcla de lenguaje de programación y español (o ingles o cualquier otro idioma) que


se emplea, dentro de la programación estructurada, para realizar el diseño de un
programa. En esencial, el pseudocodigo se puede definir como un lenguaje de
especificaciones de algoritmos.

Es la representación narrativa de los pasos que debe seguir un algoritmo para dar
solución a un problema determinado. El pseudocodigo utiliza palabras que indican el
proceso a realizar.

El inicio de un algoritmo en pseudocodigo comienza con la palabra Inicio y termina con


la palabra fin.

Las líneas que están entre llaves ({ }) se denomina comentario.

Un ejemplo aclaratorio es el siguiente. Calcular el área de un cuadrado.

Inicio
Leer (lado)
A  lado * lado
Imprimir( A)
Fin

2.13.2Diagrama De Flujo

Un diagrama de flujo es la representación gráfica de un algoritmo. También se puede


decir que es la representación detallada en forma gráfica de como deben realizarse los
pasos en la computadora para producir resultados.

Esta representación gráfica se da cuando varios símbolos (que indican diferentes


procesos en la computadora), se relacionan entre si mediante líneas que indican el
orden en que se deben ejecutar los procesos.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


8
Análisis de Algoritmos

Características

Toda representación gráfica, de cualquier tipo sea, debe cumplir las siguientes
cualidades.

Sencillez. Un método gráfico de diseño de algoritmo debe permitir la


construcción de estos de manera fácil y sencilla
Claridad. Cuando un algoritmo es representado por un método gráfico necesita
ser interpretado por otra persona distinta de la que lo diseñó, debe estar lo
suficientemente claro para su un fácil reconocimiento de todos los elementos.
Normalización. Tanto los diseñadores de programas como los usuarios que
necesitan la documentación de estos deben utilizar las mismas normas de
documentación.
Flexibilidad. Todo método gráfico de representación debe permitir, sin grandes
dificultades, posteriores modificaciones de algunas partes de un algoritmo y la
inserción de alguna nueva.

Descripción de los bloques utilizados

Los símbolos utilizados han sido normalizados por el instituto norteamericano de


normalización (ANSI).

Terminal. Indica el inicio y el final de nuestro


diagrama de flujo.

Indica la entrada y salida de datos.

Indican la entrada de datos

Indican salida de Datos

Símbolo de proceso y nos indica la asignación


de un valor en la memoria y/o la ejecución
de una operación aritmética.

Símbolo de decisión indica la realización de No si


una comparación de valores.

Subprogramas

Conector dentro de página. Representa la


continuidad del diagrama dentro de la misma
página.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


9
Análisis de Algoritmos

Conector de página. Representa la


continuidad del diagrama en otra página.

Líneas de flujo o dirección. Indican la


secuencia en que se realizan las operaciones.

Símbolo de decisión , con opciones múltiples

comentarios

Ciclo repetitivo para

NO
Ciclo repetitivo Mientras SI

Ciclo repetitivo Repetir

No si

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


10
Análisis de Algoritmos

Diferencia entre organigrama y ordinograma (D.F.)

Organigrama diagramas de flujo del sistema.

Ordinogramas  diagramas de flujo del programa

Recomendaciones para el diseño de Diagramas de Flujo

Se deben se usar solamente líneas de flujo horizontal y/o vertical.


Se debe evitar el cruce de líneas utilizando los conectores.
Se deben usar conectores solo cuando sea necesario.
No deben quedar líneas de flujo sin conectar.
Se deben trazar los símbolos de manera que se puedan leer de arriba hacia
abajo y de izquierda a derecha.
Todo texto escrito dentro de un símbolo deberá ser escrito claramente, evitando
el uso de muchas palabras.

Ventajas De Utilizar Un Pseudocodigo A Un Diagrama De Flujo

Ocupa menos espacio en una hoja de papel


Permite representar en forma fácil operaciones repetitivas complejas

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


11
Análisis de Algoritmos

Es muy fácil pasar de pseudocodigo a un programa en algún lenguaje de


programación.
Si se siguen las reglas se puede observar claramente los niveles que tiene cada
operación.

2.13.3Diagramas Estructurados (Nassi-Schneiderman)

El diagrama estructurado N-S también conocido como diagrama de chapin es como un


diagrama de flujo en el que se omiten las flechas de unión y las cajas son contiguas.
Las acciones sucesivas se pueden escribir en cajas sucesivas y como en los diagramas
de flujo, se pueden escribir diferentes acciones en una caja. Un algoritmo se
represente en la sig. forma:

Acciones simples

Las acciones simples, también denominadas instrucciones primitivas, son aquellas que
el procesador ejecuta de forma inmediata.

Asignación Almacena en una variable el resultado de evaluar una expresión

A = a+3

Entrada Toma un dato del dispositivo de entrada

Leer A,C

Salida Devuelve un dato al dispositivo de salida

Escribir a,b

Sentencias de control

También se llaman sentencias estructuradas y controlan el flujo de ejecución de otras


instrucciones.

Secuencia. Se ejecutan instrucciones de I1,I2,...,In en el mismo orden en el


que aparece
I1
I2
...
IN

Alternativa. En esta instrucción la condición es booleana

condicion
True False

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


12
Análisis de Algoritmos

Repetición o bucles. En un bucle hay una o varias acciones que se han de


repetir y una condición que determina el número de veces que se repiten las
instrucciones.

Condicion
1 2 3 4 5 6 7 8

Mientras

MIentras

Repetir

repetir

Para
Para

2.13.4 Método Warnier

El método se basa en el empleo de llaves de distintos tamaños que se relacionan entre


sí.

La representación del algoritmo se basa en los siguientes puntos.

U programa se representa por un solo diagrama en la cual se engloban todas


las operaciones, estas operaciones están colocadas a la derecha de la llave y en
la parte izquierda se encuentra el nombre.
En la parte superior de la llave principal se coloca inicio
En la parte inferior de la llave principal se coloca fin

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


13
Análisis de Algoritmos

Acciones simples

Las acciones simples, también denominadas instrucciones primitivas, son aquellas que
el procesador ejecuta de forma inmediata.

Asignación Almacena en una variable el resultado de evaluar una expresión

Variable  expresión

Entrada Toma un dato del dispositivo de entrada

Leer (Variable)

Salida Devuelve un dato al dispositivo de salida

Imprimir (variable)

Sentencias de control

También se llaman sentencias estructuradas y controlan el flujo de ejecución de otras


instrucciones.

Secuencia. Se ejecutan instrucciones de I1,I2,...,In en el mismo orden en el


que aparece

I1
I2
...
I3

Alternativa. En esta instrucción la condición es booleana

Si I1
Condición
No I2

Expresión = V1 A

Expresión = V2 A

Expresión = V3 A

Expresión = Otros A

Repetición o bucles. En un bucle hay una o varias acciones que se han de


repetir y una condición que determina el número de veces que se repiten las
instrucciones.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


14
Análisis de Algoritmos

Mientras

Proceso A
Mientras condición

Repetir

Proceso A
Hasta condición

Para

Proceso A
N veces

2.13.5 Método Jackson

Se trata de un método de representación de programa en forma de árbol denominado


diagrama arborescente de Jackson, un diagrama de Jackson consta de :

 Definición detallada de los datos de entrada y salida incluyendo los


archivos lógicos utilizados.
 Representación del proceso o algoritmo.

La simbología utilizada es la siguiente

O *

La lectura del árbol se realiza en preorden

 Situarse en la raíz (R)


 Recorrer el subarbol izquierdo (I)
 Recorrer el subarbol derecho (D)

Acciones simples

Las acciones simples, también denominadas instrucciones primitivas, son aquellas que
el procesador ejecuta de forma inmediata.

Asignación Almacena en una variable el resultado de evaluar una expresión

Variable  expresión

Entrada Toma un dato del dispositivo de entrada

Leer (Variable)

Salida Devuelve un dato al dispositivo de salida

Imprimir (variable)

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


15
Análisis de Algoritmos

Sentencias de control

También se llaman sentencias estructuradas y controlan el flujo de ejecución de otras


instrucciones.

Secuencia. Se ejecutan instrucciones de I1,I2,...,In en el mismo orden en el


que aparece

Proceso

A B C

Alternativa. En esta instrucción la condición es booleana

Condición

Si O No O
A B

Expresión

= V1 O = V2 O = V3 O = VN O
A B C D

Repetición o bucles. En un bucle hay una o varias acciones que se han de


repetir y una condición que determina el número de veces que se repiten las
instrucciones.
Proceso

*
Condición

Mientras
En el bloque condición se escribe mientras condición

Repetir
En el bloque condición se escribe hasta condición
Para
En el bloque condición se escribe N veces

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


16
Análisis de Algoritmos

2.13.6 Método Bertini

Al igual que Jackson, la representación de programas es en forma de árbol


denominado diagrama arborescente de Bertini. Un diagrama de Bertini consta de.

 Definición detallada de los datos de entrada y salida.


 Representación del proceso o algoritmo.

La simbología utilizada es la siguiente.

La lectura del árbol se realiza en postorden

Situarse en la raíz (R)


Recorrer el subarbol Derecho (D)
Recorrer el subarbol Izquierdo (I)

Acciones simples

Las acciones simples, también denominadas instrucciones primitivas, son aquellas que
el procesador ejecuta de forma inmediata.

Asignación Almacena en una variable el resultado de evaluar una expresión

Variable  expresión

Entrada Toma un dato del dispositivo de entrada

Leer (Variable)

Salida Devuelve un dato al dispositivo de salida

Imprimir (variable)

Sentencias de control

También se llaman sentencias estructuradas y controlan el flujo de ejecución de otras


instrucciones.

Secuencia. Se ejecutan instrucciones de I1,I2,...,In en el mismo orden en el


que aparece

C B A

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


17
Análisis de Algoritmos

Alternativa. En esta instrucción la condición es booleana

COND COND

A B

EXPRESION

=V1 =V2 =V3 =OTROS

A B C D

Repetición o bucles. En un bucle hay una o varias acciones que se han de


repetir y una condición que determina el número de veces que se repiten las
instrucciones.

CONDICION

Mientras

En el bloque condición se escribe mientras condición

Repetir

En el bloque condición se escribe hasta condición

Para

En el bloque condición se escribe N veces

2.13.7 Método Tabourier

Se trata de un método de representación de programa en forma de árbol denominado


diagrama arborescente de Tabourier, un diagrama de Tabourier consta de :

Definición detallada de los datos de entrada y salida incluyendo los archivos


lógicos utilizados.
Representación del proceso o algoritmo.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


18
Análisis de Algoritmos

La simbología utilizada es la siguiente

La lectura del árbol se realiza en preorden

Situarse en la raíz (R)


Recorrer el subarbol izquierdo (I)
Recorrer el subarbol derecho (D)

Acciones simples

Las acciones simples, también denominadas instrucciones primitivas, son aquellas que
el procesador ejecuta de forma inmediata.

Asignación Almacena en una variable el resultado de evaluar una expresión

Variable  expresión

Entrada Toma un dato del dispositivo de entrada

Leer (Variable)

Salida Devuelve un dato al dispositivo de salida

Imprimir (variable)

Sentencias de control

También se llaman sentencias estructuradas y controlan el flujo de ejecución de otras


instrucciones.

Secuencia. Se ejecutan instrucciones de I1,I2,...,In en el mismo orden en el


que aparece

Boque

A B C

Alternativa. En esta instrucción la condición es booleana

Si entonces Sino

Condi. A B

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


19
Análisis de Algoritmos

Expresión En caso de

= V1 = V2 = V3 = VN
A B C D

Repetición o bucles. En un bucle hay una o varias acciones que se han de


repetir y una condición que determina el número de veces que se repiten las
instrucciones.

Mientras

Mientras

A
Condi.

Repetir

Repetir

A
Condi.

Para
Para

A
Condi.

2.14 Conversión de Algoritmos

Se tiene las siguientes analogías entre las herramientas de presentación de algoritmos

Diagramas de flujo
Pseudocodigo
Diagramas N-S

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


20
Análisis de Algoritmos

Instrucciones, Pseudocodigo Diagrama de flujo Diagrama N-S


acciones
Estructura del Algoritmo Identificador
Algoritmo {Sección de declaración de Inicio Algoritmo Identificador
variables}
inicio
....
Fin
Fin
fin
Declaración de Descripción de variables y tipos en Se escriben las variables y tipos Escritura de una tabla de variables
variables la tabla de variables en la tabla de variables junto
con el diagrama de flujo
Asignación Variable  Expresión Variable  Expresión Variable  Expresión

Entrada de datos Leer (lista de variables)

Leer Leer
(lista de variables) (lista de variables)

Salida de datos Escribir (lista de variables)

Escribir Escribir
(lista de variables) (lista de variables)

Instrucción
compuesta S1 S1
S1
S2 S2 S2
S3
... ... ...
SN
Sn Sn

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


21
Análisis de Algoritmos

Comentarios
{ FASE DESCRIPTIVA DE
COMENTARIO}

Selectiva alternativa
simple Si condición entonces condicion
S1 True False
S2
...
S3
Finsi

Selectiva alternativa
doble Si condición entonces
S1 condicion
S2 True False
...
S3
Sino
S1
S2
...
S3
Finsi

Selectiva alternativa
múltiple Según_sea expresión hacer
E1 : S1,S2,...Sn Condicion
1 2 3 4 5 6 7 8
E2 : S1,S2,...Sn
E3 : S1,S2,...Sn
.....
EN : S1,S2,...Sn
En_otro_caso
EN : S1,S2,...Sn
Fin_según_sea

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


22
Análisis de Algoritmos

Repetitiva mientras
Mientras condición
S1 no Mientras
S2
... Si
S3
Fin_Mientras

Repetitiva repetir
Repetir
S1
S2
...
S3
Hasta condición
No Si
Repetir

Repetitiva para
(desde) Para Var de ValInc Hasta ValFin
[incremento x] hacer Para V de Para
S1 inic  fin hacer
S2
...
Sn
Fin_Para

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


23
Análisis de Algoritmos

3. Sintaxis y Semántica

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


24
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


25
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


26
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


27
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


28
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


29
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


30
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


31
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


32
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


33
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


34
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


35
Análisis de Algoritmos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


36
Análisis de Algoritmos

El enfoque cambió cuando los investigadores comprobaron que el ser humano procesa
la información con muy poco cálculo, pero con gran cantidad de conocimiento
estructural: es decir, con conocimiento de los objetos relacionados con el problema.
Este nuevo paradigma, que tuvo su expresión práctica con la creación a mediados de
los 70 del primer sistema experto, fue denominado el paradigma del conocimiento: "Un
problema se resuelve según el conocimiento que se tenga de él".

Paradigma es una colección de patrones conceptuales que modelan la forma de


razonar sobre problemas

Paradigma de programación es un modelo básico de diseño y desarrollo de programas,


que permite producir programas con unas directrices específicas, tales como:
estructura modular, fuerte cohesión, alta rentabilidad, etc.

Un paradigma de programación es una colección de modelos conceptuales que juntos


modelan el proceso de diseño y determinan, al final una estructura de un programa.

Esa estructura conceptual de modelos está pensada de forma que esos modelos
determinan la forma correcta de los programas y controlan el modo en que pensamos
y formulamos soluciones, y al llegar a la solución, ésta se debe de expresar mediante
un lenguaje de programación. Para que este proceso sea efectivo las características del
lenguaje deben reflejar adecuadamente los modelos conceptuales de ese paradigma.

Cuando un lenguaje refleja bien un paradigma particular, se dice que soporta el


paradigma, y en la práctica un lenguaje que soporta correctamente un paradigma, es
difícil distinguirlo del propio paradigma, por lo que se identifica con él

5. Tipos de Paradigmas

Floyd describió tres categorías de paradigmas de programación:

Los que soportan técnicas de programación de bajo nivel (ej.: copia de ficheros
frente estructuras de datos compartidos)
Los que soportan métodos de diseño de algoritmos (ej.: divide y vencerás,
programación dinámica, etc.)
Los que soportan soluciones de programación de alto nivel, como los descritos
en el punto anterior

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


37
Análisis de Algoritmos

Floyd también señala lo diferentes que resultan los lenguajes de programación que
soportan cada una de estas categorías de paradigmas. Sólo comentaremos los
paradigmas relacionados con la programación de alto nivel.

Se agrupan en tres categorías de acuerdo con la solución que aportan para


resolver el problema
Solución procedimental u operacional. Describe etapa a etapa el modo de
construir la solución. Es decir señala la forma de obtener la solución.
Solución demostrativa. Es una variante de la procedimental. Especifica la
solución describiendo ejemplos y permitiendo que el sistema generalice la
solución de estos ejemplos para otros casos. Aunque es fundamentalmente
procedimental, el hecho de producir resultados muy diferentes a ésta, hace que
sea tratada como una categoría separada.
Solución declarativa. Señala las características que debe tener la solución, sin
describir cómo procesarla. Es decir señala qué se desea obtener pero no cómo
obtenerlo.
Paradigmas procedimentales u operacionales
La característica fundamental de estos paradigmas es la secuencia computacional
realizada etapa a etapa para resolver el problema. Su mayor dificultad reside en
determinar si el valor computado es una solución correcta del problema, por lo
que se han desarrollado multitud de técnicas de depuración y verificación para
probar la corrección de los problemas desarrollados basándose en este tipo de
paradigmas.

Pueden ser de dos tipos básicos: Los que actúan modificando repetidamente la
representación de sus datos (efecto de lado); y los que actúan creando nuevos
datos continuamente (sin efecto de lado).
Los paradigmas con efecto de lado utilizan un modelo en el que las variables están
estrechamente relacionadas con direcciones de la memoria del ordenador.
Cuando se ejecuta el programa, el contenido de estas direcciones se actualiza
repetidamente, pues las variables reciben múltiples asignaciones, y al finalizar
el trabajo, los valores finales de las variables representan el resultado.

Existen dos tipos de paradigmas con efectos de lado:

El imperativo

El orientado a objetos

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


38
Análisis de Algoritmos

Los paradigmas sin efecto de lado no incluyen a los que tradicionalmente son
denominados paradigmas funcionales. Sin embargo es importante distinguir la
solución funcional procedimental de la solución funcional declarativa.

Los paradigmas procedimentales definen la secuencia explícitamente, pero esta


secuencia se puede procesar en serie o en paralelo. En este segundo caso el
procesamiento paralelo puede ser asíncrono (cooperación de procesos
paralelos) o síncrono (procesos simples aplicados simultáneamente a muchos
objetos).

Paradigmas declarativos

En este tipo, un programa se construye señalando hechos, reglas, restricciones,


ecuaciones, transformaciones y otras propiedades derivadas del conjunto de
valores que configuran la solución.

A partir de esta información el sistema debe de proporcionar un esquema que


incluya el orden de evaluación que compute una solución. Aquí no existe la
descripción de las diferentes etapas a seguir para alcanzar una solución, como
en el caso anterior.

Estos paradigmas permiten el uso de variables para almacenar valores


intermedios, pero no para actualizar estados de información.

Dado que estos paradigmas especifican la solución sin indicar cómo construirla,
en principio eliminan la necesidad de probar que el valor calculado es el valor
solución. En la práctica, mientras que muchos de los paradigmas secuencia de
control y efecto de lado que requiera la noción de estado, las soluciones son
todavía producidas como construcciones más bien que cómo especificaciones.
Por lo que los paradigmas resultantes y los lenguajes que los soportan no son
verdaderamente declarativos, sino pseudodeclarativos. En este grupo se
encuentran: el funcional, el lógico y el de transformación.

En principio, los paradigmas declarativos no son soluciones inherentes de tipos


serie o paralelo, ya que no dirigen la secuencia de control y no pueden alterar el
natural no paralelismo del algoritmo. No obstante, los paradigmas
pseudodeclarativos requieren al menos un limitado grado de secuencia, y por lo
tanto admiten versiones en serie y paralelo.

Paradigmas demostrativos

Cuando se programa bajo un paradigma demostrativo (también llamada


programación por ejemplos), el programador no especifica procedimentalmente
cómo construir una solución. En su lugar, presentan soluciones de problemas
similares y permite al sistema que generalice una solución procedimental a
partir de estas demostraciones. Los esquemas individuales para generalizar
tales soluciones van desde simular una secuencia procedimental o inferir
intenciones.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


39
Análisis de Algoritmos

Los sistemas que infieren, intentan generalizar usando razonamiento basado en


el conocimiento. Una solución basada en la inferencia intenta determinar en qué
son similares un grupo de datos u objetos, y, a partir de ello, generalizar estas
similaridades.

Otra solución es la programación asistida: el sistema observa acciones que el


programador ejecuta, y si son similares o acciones pasadas, intentará inferir
cuál es la próxima acción que hará el programador. Las dos principales
objeciones al sistema de inferencia son:
Si no se comprueban exhaustivamente pueden producir programas erróneos
que trabajan correctamente con los ejemplos de prueba, pero que fallen
posteriormente en otros casos
La capacidad de inferencia es tan limitada, que el usuario debe de guiar el
proceso en la mayoría de los casos.

Los resultados más satisfactorios de los sistemas de inferencia son en áreas limitadas,
donde el sistema tenía un conocimiento semántico importante de la aplicación.

El mayor problema que se presenta con estos sistemas, es conocer cuándo un


programa es correcto. En el caso de los sistemas procedimentales, se consigue
estudiando el algoritmo y el resultado de juegos de ensayo apropiados.

En el caso de los sistemas demostrativos el algoritmo se mantiene en una


representación interna, y su estudio se sale del ámbito de estos sistemas. Por lo
que la veracidad de la decisión se debe hacer exclusivamente sobre la base de
la eficiencia del algoritmo sobre los casos específicos de prueba.

La programación demostrativa es del tipo "bottom-up" y se adapta bien a nuestra


capacidad de pensar. Sin embargo en la mayor parte de los paradigmas la
resolución del problema se efectúa aplicando métodos abstractos "top-down".

5.1 Paradigma Funcional

Se basa en el concepto matemático de función, una función es una regla de


correspondencia que asocia a cada elemento de un conjunto de origen. Los conjuntos
de origen suelen llamarse dominio y rangote la función

F(x) = z
Historia

Sus orígenes provienen del Cálculo Lambda (o λ-cálculo), una teoría matemática
elaborada por Alonzo Church como apoyo a sus estudios sobre computabilidad. Un
lenguaje funcional es, a grandes rasgos, un azúcar sintáctico del Cálculo Lambda.

Alonzo Church (14 de junio de 1903 - 11 de agosto de 1995), matemático y


lógico Norteamericano responsable por crear la bases de la computación teórica.
Nacido en la ciudad de Washington, se diplomó en la Universidad de Princeton en
1924 y obtuvo su doctorado en 1927, donde ejerció como profesor entre 1929 y
1967.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


40
Análisis de Algoritmos

Su obra más conocida es el desarrollo del cálculo lambda, y su trabajo de 1936 que
muestra la existencia de problemas indecidibles. Este trabajo precedió el famoso
trabajo de su alumno Alan Turing sobre el problema de parada que también
demostró la existencia de problemas irresolubles por dispositivos mecánicos. Luego
de revisar la tesis doctoral de Turing, demostraron que el cálculo lambda y la
máquina de Turing utilizada para expresar el problema de parada tenían igual
poder de expresión; posteriormente demostraron que una variedad de procesos
mecánicos alternos para realizar cálculos tenían poder de cómputo equivalente.
Como resultado se postuló la Tesis de Church-Turing.

Entre los más conocidos estudiantes de doctorado de Church están Stephen Kleene,
J. Barkley Rosser, Leon Henkin, John George Kemeny, Michael O. Rabin, Dana
Scott, Simon Kochen, Raymond Smullyan y otros.

El cálculo lambda influenció el diseño del lenguaje Lisp así como los lenguajes de
programación funcional.

El cálculo lambda es un sistema formal diseñado para investigar la definición de


función, la noción de aplicación de funciones y la recursión. Fue introducido por
Alonzo Church y Stephen Kleene en la década de 1930; Church usó el cálculo
lambda en 1936 para resolver el Entscheidungsproblem. Puede ser usado para
definir de manera limpia y precisa qué es una "función computable".

Church resolvió negativamente el Entscheidungsproblem: probó que no había


algoritmo que pudiese ser considerado como una "solución" al
Entscheidungsproblem.

El cálculo lambda ha influenciado enormemente el diseño de lenguajes de


programación funcionales, especialmente LISP.

Se puede considerar al cálculo lambda como el más pequeño lenguaje universal de


programación. Consiste de una regla de transformación simple (substitución de
variables) y un esquema simple para definir funciones.

El cálculo lambda es universal porque cualquier función computable puede ser


expresada y evaluada a través de él. Por lo tanto, es equivalente a las máquinas de
Turing. Sin embargo, el cálculo lambda no hace énfasis en el uso de reglas de
transformación y no considera las máquinas reales que pueden implementarlo. Se
trata de una propuesta más cercana al software que el hardware

Utilidad

El objetivo es conseguir lenguajes expresivos y matemáticamente elegantes, en los


que no sea necesario bajar al nivel de la máquina para describir el proceso llevado
a cabo por el programa, y evitando el concepto de estado del cómputo. La
secuencia de computaciones llevadas a cabo por el programa se regiría única y
exclusivamente por la reescritura de definiciones más amplias a otras cada vez más
concretas y definidas, usando lo que se denominan "definiciones dirigidas".

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


41
Análisis de Algoritmos

Características

Los programas escritos en un lenguaje funcional están constituidos únicamente por


definiciones de funciones, entendiendo éstas no como subprogramas clásicos de un
lenguaje imperativo, sino como funciones puramente matemáticas, en las que se
verifican ciertas propiedades como la transparencia referencial (el significado de
una expresión depende únicamente del significado de sus subexpresiones), y por
tanto, la carencia total de efectos laterales.

Otras características propias de estos lenguajes son la no existencia de


asignaciones de variables y la falta de construcciones estructuradas como la
secuencia o la iteración (lo que obliga en la práctica a que todas las repeticiones de
instrucciones se lleven a cabo por medio de funciones recursivas).

Existen dos grandes categorías de lenguajes funcionales: los funcionales puros y


los híbridos. La diferencia entre ambos estriba en que los lenguajes funcionales
híbridos son menos dogmáticos que los puros, al admitir conceptos tomados de los
lenguajes procedimentales, como las secuencias de instrucciones o la asignación de
variables. En contraste, los lenguajes funcionales puros tienen una mayor potencia
expresiva, conservando a la vez su transparencia referencial, algo que no se
cumple siempre con un lenguaje funcional híbrido.

Entre los lenguajes funcionales puros, cabe destacar a Haskell y Miranda*. Los
lenguajes funcionales híbridos más conocidos son Lisp, Scheme, Ocaml y Standard
ML (estos dos últimos, descendientes del lenguaje ML).

Entonces sacamos como conclusión que la programación funcional tiene como objeto
imitar las funciones matemáticas lo mas posible. Un lenguaje funcional posee la
propiedad matemática de transparencia referencial, lo que significa que una expresión
representa siempre el mismo valor. Esto permite razonar sobre la ejecución de un
programa y demostrar matemáticamente que es correcto. Las variables de un lenguaje
funcional son como las variables en álgebra. Inicialmente representan un valor
desconocido que, una vez calculado, ya no cambia.

5.2 Paradigma Imperatrivo

La programación imperativa, en contraposición a la programación declarativa es un


paradigma de programación que describe la programación en términos del estado del
programa y sentencias que cambian dicho estado.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


42
Análisis de Algoritmos

Este paradigma se caracteriza por un modelo abstracto de ordenador que consiste en


un gran almacenamiento de memoria.

El ordenador almacena una representación codificada de un cálculo y ejecuta


una secuencia de comandos que modifican el contenido de ese
almacenamiento. Este paradigma viene bien representado por la arquitectura
Von Neuman (1903-1957), ya que utiliza este modelo de máquina para
conceptualizar las soluciones: "Existe un programa en memoria que se va
ejecutando secuencialmente, y que toma unos datos de la memoria, efectúa
unos cálculos y actualiza la memoria".

La programación en el paradigma imperativo consiste en determinar qué datos


son requeridos para el cálculo, asociar a esos datos unas direcciones de
memoria, y efectuar paso a paso una secuencia de transformaciones en los
datos almacenados, de forma que el estado final represente el resultado
correcto.

En su forma pura este paradigma sólo soporta sentencias simples que modifican
la memoria y efectúan bifurcaciones condicionales e incondicionales. Incluso
cuando se añade una forma simple de abstracción procedimental, el modelo
permanece básicamente sin cambiar. Los parámetros de los procedimientos son
"alias" de las zonas de memoria, por lo que pueden alterar su valor, y no
retorna ningún tipo de cálculo. La memoria también se puede actualizar
directamente mediante referencias globales.

El paradigma imperativo debe su nombre al papel dominante que desempeñan


las sentencias imperativas. Su esencia es el cálculo iterativo, paso a paso, de
valores de nivel inferior y su asignación a posiciones de memoria.

Si se analizan las características fundamentales de este tipo de paradigma se


detectan las siguientes:
Concepto de celda de memoria ("variable") para almacenar valores. El
componente principal de la arquitectura es la memoria, compuesto por un gran
número de celdas donde se almacenan los datos. Las celdas tienen nombre
(concepto de variable) que las referencian, y sobre los que se producen efectos
de lado y definiciones de alias.
Operaciones de asignación. Estrechamente ligado a la arquitectura de la
memoria, se encuentra la idea de que cada valor calculado debe ser
"almacenado", es decir asignado a una celda. Esta es la razón de la importancia
de la sentencia de asignación en el paradigma imperativo. Las nociones de
celda de memoria y asignación en bajo nivel, se tienden a todos los lenguajes
de programación y fuerzan en los programadores un estilo de pensamiento
basado en la arquitectura Von Neumann.
Repetición. Un programa imperativo, normalmente realiza su tarea ejecutando
repetidamente una secuencia de pasos elementales, ya que en este modelo
computacional la única forma de ejecutar algo complejo es repitiendo una
secuencia de instrucciones.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


43
Análisis de Algoritmos

A este tipo de paradigma de programación se le suele llamar algorítmico, dado que el


significado de algoritmo es análogo al de receta, método, técnica,
procedimiento o rutina, y se define como "un conjunto finito de reglas
diseñadas para crear una secuencia de operaciones para resolver un tipo
específico de problemas". De esta forma para N. Wirth, un programa viene
definido por la ecuación

Algoritmos + Estructura de Datos = Programas

No obstante, entendemos que aunque el concepto de algoritmo encaja en otros tipos


de paradigmas, es privativo del tipo de programación procedimental en el que
su característica fundamental es la secuencia computacional.

Atendiendo a los lenguajes imperativos, cabe clasificarlos en "orientados a


expresiones" y "orientados a sentencias", según jueguen las expresiones o
sentencias un papel más predominante en el lenguaje, respectivamente. Ambos
son términos relativos y no se pueden aplicar de forma absoluta. Se puede
decir que C, FORTRAN; Algol, Pascal, son lenguajes orientados a expresiones,
mientras que COBOL y PL/1 están orientados a sentencias.

Las expresiones se han encontrado útiles principalmente porque son simples y jerárquicas y
pueden combinarse uniformemente para construir expresiones más complejas. Sí
pues, las expresiones no sufren influencias de la arquitectura de Von Neumann.

Como ejemplos de programación imperativa, se muestran en lenguaje Pascal la


generación de números primos mediante la criba de Eratóstenes, y en lenguaje C la
ordenación de datos mediante el método de la burbuja.

Números Primos

(* Genera números primos en el rango 2..n, utilizando la criba


de Eratóstenes *)
Program primos(input, output);

Const n=50;
Var i: 2..n;
j: 2..25;
iprimo: boolean;
Begin

for i:=2 to n do

Begin (* ¿ Es primo i ? *)
j:=2; iprimo:=true;
While iprimo and (j<=i div 2) do
if ( (i mod j) <>0)
then j:=j+1 else iprimo:=false;
(* Si es primo imprime su valor *)
if iprimo then write (i:3)

End
End.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


44
Análisis de Algoritmos

En este programa se destacan las tres características principales del paradigma


imperativo:

 Celdas de memoria: declaraciones de var (i,j, primo)


 Operaciones de asignación de tipo destructivo: j:=2, iprimo:=true, ..
 Sentencias repetitivas: for y while

Ordenar
/* Ordena un conjunto de datos leídos desde el dispositivo de entrada,
utilizando el método de la burbuja */

#include

void ordenar (int *, int);


void escribir (int *, int);
main( )
{
int n=0, dato;
int a[50];
scanf("%d", &dato);
while(dato != EOF);
a[n++] = dato;
scanf("%d",&dato); }
ordenar(a,n-1);
escribir(a,n-1);
}

/* función ordenar */

void ordenar (int a[ ], int n)


{
int i,j, tem;
for (i=0; i<n; y++)
for (j=i+1; j<=n; j++)
if (a[i]>a[j])
{tem = a[i];
a[i]=a[j];
a[j]=tem;}
}
void escribir (int a[ ], int n)
{
int i;
for (y=0; i<n; y++)
{
if (!(i % 10)) printf ("\n");
printf("% 5d", a[i]);
}
}

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


45
Análisis de Algoritmos

La función ordenar compara parejas de datos contiguos e intercambia su contenido si


el primero es mayor que el segundo. Y en cada iteración de la variable j, coloca
en la cabeza de la lista que está ordenando el dato menor (la burbuja más
ligera)

En este ejemplo, al igual que en anterior predominan los tres componentes


descritos del paradigma imperativo.

Algunos lenguajes imperativos


BASIC
C
C++
Java
C#
Perl

5.3 Paradigma orientado a objetos

La Programación Orientada a Objetos (POO u OOP según siglas en inglés) es un


paradigma de programación que define los programas en términos de "clases de
objetos", objetos que son entidades que combinan estado (es decir, datos),
comportamiento (esto es, procedimientos o métodos) e identidad (propiedad del
objeto que lo diferencia del resto). La programación orientada a objetos expresa un
programa como un conjunto de estos objetos, que colaboran entre ellos para realizar
tareas. Esto difiere de los lenguajes procedurales tradicionales, en los que los datos y
los procedimientos están separados y sin relación. Estos métodos están pensados para
hacer los programas y módulos más fáciles de escribir, mantener y reutilizar.

Otra manera en que esto es expresado a menudo, es que la programación orientada a


objetos anima al programador a pensar en los programas principalmente en términos
de estructuras de datos, y en segundo lugar en las operaciones ("métodos")
específicas a esas estructuras de datos. Los lenguajes procedurales animan al
programador a pensar sobre todo en términos de procedimientos, y en segundo lugar
en las estructuras de datos que esos procedimientos manejan.

Los programadores que emplean lenguajes procedurales, escriben funciones y después


les pasan datos. Los programadores que emplean lenguajes orientados a objetos
definen objetos con datos (estructuras) y métodos y después envían mensajes a los
objetos diciendo qué realicen esos métodos en sí mismos.

Algunas personas también diferencian la POO sin clases, la cual es llamada a veces
programación basada en objetos.

Origen

Los conceptos de la programación orientada a objetos tienen origen en Simula 67,


un lenguaje diseñado para hacer simulaciones, creado por Ole-Johan Dahl y Kristen
Nygaard del Centro de Cómputo Noruego en Oslo. Según se informa, la historia es
que trabajaban en simulaciones de naves, y fueron confundidos por la explosión
combinatoria de cómo las diversas cualidades de diversas naves podían afectar
unas a las otras. La idea ocurrió para agrupar los diversos tipos de naves en

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


46
Análisis de Algoritmos

diversas clases de objetos, siendo responsable cada clase de objetos de definir sus
propios datos y comportamiento. Fueron refinados más tarde en Smalltalk, que fue
desarrollado en Simula en Xerox PARC (y cuya primera vesión fue escrita sobre
Basic) pero diseñado para ser un sistema completamente dinámico en el cual los
objetos se podrían crear y modificar "en marcha" en lugar de tener un sistema
basado en programas estáticos.

La programación orientada a objetos tomó posición como la metodología de


programación dominante a mediados de los años ochenta, en gran parte debido a
la influencia de C++ , una extensión del lenguaje de programación C. Su
dominación fue consolidada gracias al auge de las Interfaces gráficas de usuario,
para los cuales la programación orientada a objetos está particularmente bien
adaptada. En este caso, se habla también de programación orientada a eventos.

Las características de orientación a objetos fueron agregadas a muchos lenguajes


existentes durante ese tiempo, incluyendo Ada, BASIC, Lisp, Pascal, y otros. La
adición de estas características a los lenguajes que no fueron diseñados
inicialmente para ellas condujo a menudo a problemas de compatibilidad y a la
capacidad de mantenimiento del código. Los lenguajes orientados a objetos
"puros", por otra parte, carecían de las características de las cuales muchos
programadores habían venido a depender. Para saltar este obstáculo, se hicieron
muchas tentativas para crear nuevos lenguajes basados en métodos orientados a
objetos, pero permitiendo algunas características procedurales de maneras
"seguras". El Eiffel de Bertrand Meyer fue un temprano y moderadamente acertado
lenguaje con esos objetivos pero ahora ha sido esencialmente reemplazado por
Java, en gran parte debido a la aparición de Internet, y a la implementación de la
máquina virtual de Java en la mayoría de navegadores.

Diferencias con la programación procedural

Aunque la programación procedural o procedimental condujo a mejoras de la


técnica de programación secuencial, tales como la programación estructurada y
"refinamientos sucesivos", los métodos modernos de diseño de software orientado
a objetos incluyen mejoras entre las que están el uso de los patrones de diseño,
diseño por contrato, y lenguajes de modelado (ej: UML).

La programación procedimental clásica presenta ciertos problemas, que fueron


haciéndose cada vez más graves, a medida que se construían aplicaciones y
sistemas informáticos más complejos, entre los que destacan los siguientes:

Modelo mental anómalo. Nuestra imagen del mundo se apoya en los seres, a
los que asignamos nombres sustantivos, mientras la programación clásica se
basa en el comportamiento, representado usualmente por verbos.
Es difícil modificar y extender los programas, pues suele haber datos
compartidos por varios subprogramas, que introducen interacciones ocultas
entre ellos.
Es difícil mantener los programas. Casi todos los sistemas informáticos grandes
tienen errores ocultos, que no surgen a la luz hasta después de muchas horas
de funcionamiento.
Es difícil reutilizar los programas. Es prácticamente imposible aprovechar en
una aplicación nueva las subrutinas que se diseñaron para otra.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


47
Análisis de Algoritmos

Es compleja la coordinación y organización entre programadores para la


creación de aplicaciones de media y gran envergadura.

En la programación orientada a objetos pura no deben utilizarse llamadas de


subrutinas, únicamente mensajes.

Por ello, a veces recibe el nombre de programación sin CALL, igual que la
programación estructurada se llama también programación sin GOTO.

Sin embargo, no todos los lenguajes orientados a objetos prohíben la instrucción


CALL (o su equivalente), permitiendo realizar programación híbrida, procedimental
y orientada a objetos a la vez.

La Programación Orientada a Objetos (POO) como solución

La programación orientada a objetos es una nueva forma de programar que trata


de encontrar solución a estos problemas. Introduce nuevos conceptos, que superan
y amplian conceptos antiguos ya conocidos. Entre ellos destacan los siguientes:

Objeto: entidad provista de un conjunto de propiedades o atributos (datos) y de


comportamiento o funcionalidad ("métodos"). Corresponden a los objetos reales del
mundo que nos rodea, o a objetos internos del sistema (del programa).

Clase: definiciones de las propiedades y comportamiento de un tipo de objeto


concreto. La instanciación es la lectura de estas definiciones y la creación de un
objeto a partir de ellas.

Método: algoritmo asociado a un objeto (o a una clase de objetos), cuya ejecución


se desencadena tras la recepción de un "mensaje". Desde el punto de vista del
comportamiento, es lo que el objeto puede hacer. Un método puede producir un
cambio en las propiedades del objeto, y/o la generación de un "evento" con un
nuevo mensaje para otro objeto del sistema.

Evento: un suceso en el sistema (tal como una interacción del usuario con la
máquina, o un mensaje enviado por un objeto). El sistema maneja el evento
enviando el mensaje adecuado al objeto pertinente.

Mensaje: una comunicación dirigida a un objeto, que le ordena que ejecute uno de
sus métodos con ciertos parámetros asociados al evento que lo generó.

Propiedad o atributo: contenedor de un tipo de datos asociados a un objeto (o a


una clase de objetos), que hace los datos visibles desde fuera del objeto, y cuyo
valor puede ser alterado por la ejecución de algún método.

Estado interno: es una propiedad invisible de los objetos, que puede ser
únicamente accedida y alterada por un método del objeto, y que se utiliza para
indicar distintas situaciones posibles para el objeto (o clase de objetos).

contenedor interno del atributo del objeto o de un estado interno, así como la
"función" es un procedimiento interno del método del objeto.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


48
Análisis de Algoritmos

Características de la POO

Hay un cierto desacuerdo sobre exactamente qué características de un método de


programación o lenguaje le definen como "orientado a objetos", pero hay un
consenso general en que las características siguientes son las más importantes
(para más información, seguir los enlaces respectivos):

Abstracción: Cada objeto en el sistema sirve como modelo de un "agente"


abstracto que puede realizar trabajo, informar y cambiar su estado, y
"comunicarse" con otros objetos en el sistema sin revelar cómo se implementan
estas características. Los procesos, las funciones o los métodos pueden también ser
abstraídos y cuando lo están, una variedad de técnicas son requeridas para ampliar
una abstracción.

Encapsulamiento: También llamado "ocultación de la información". Cada objeto


está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una
interfaz a otros objetos que especifica cómo pueden interactuar con los objetos de
la clase. El aislamiento protege a las propiedades de un objeto contra su
modificación por quien no tenga derecho a acceder a ellas, solamente los propios
métodos internos del objeto pueden acceder a su estado. Esto asegura que otros
objetos no pueden cambiar el estado interno de un objeto de maneras inesperadas,
eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes
relajan esto, permitiendo un acceso directo a los datos internos del objeto de una
manera controlada y limitando el grado de abstracción. La aplicación entera se
reduce a un agregado o rompecabezas de objetos.

Polimorfismo: comportamientos diferentes, asociados a objetos distintos, pueden


compartir el mismo nombre, al llamarlos por ese nombre se utilizará el
comportamiento correspondiente al objeto que se esté usando. O dicho de otro
modo, las referencias y las colecciones de objetos pueden contener objetos de
diferentes tipos, y la invocación de un comportamiento en una referencia producirá
el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto
ocurre en "tiempo de ejecución", esta última característica se llama asignación
tardía o asignación dinámica. Algunos lenguajes proporcionan medios más estáticos
(en "tiempo de compilación") de polimorfismo, tales como las plantillas y la
sobrecarga de operadores de C++.

Herencia: las clases no están aisladas, sino que se relacionan entre sí, formando
una jerarquía de clasificación. Los objetos heredan las propiedades y el
comportamiento de todas las clases a las que pertenecen. La herencia organiza y
facilita el polimorfismo y la encapsulación permitiendo a los objetos ser definidos y
creados como tipos especializados de objetos preexistentes. Estos pueden
compartir (y extender) su comportamiento sin tener que reimplementar su
comportamiento. Esto suele hacerse habitualmente agrupando los objetos en clases
y estas en árboles o enrejados que reflejan un comportamiento común. Cuando un
objeto pertenece a más de una clase se llama herencia múltiple; esta característica
no está soportada por algunos lenguajes (como Java).

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


49
Análisis de Algoritmos

Lenguajes orientados a objetos

Entre los lenguajes orientados a objetos destacan los siguientes:

ActionScript
Ada 95
C++
C#
Clarion
Delphi
Eiffel
Java
Lexico (en castellano)
Objective-C
Ocaml
PHP 5
PowerBuilder
Python
Ruby
Smalltalk
Visual Basic

5.4 Paradigma lógico

La programación lógica consiste en la aplicación del corpus de conocimiento sobre


lógica para el diseño de lenguajes de programación; no debe confundirse con la
disciplina de la lógica computacional.

La programación lógica comprende dos paradigmas de programación: la programación


declarativa y la programación funcional. La programación declarativa gira en torno al
concepto de predicado, o relación entre elementos. La programación funcional se basa
en el concepto de función (que no es más que una evolución de los predicados), de
corte más matemático.

Motivación

Históricamente, los ordenadores se han programado utilizando lenguajes muy


cercanos a las peculiaridades de la propia máquina: operaciones aritméticas
simples, instrucciones de acceso a memoria, etc. Un programa escrito de esta
manera puede ocultar totalmente su propósito a la comprensión de un ser humano,
incluso uno entrenado. Hoy día, estos lenguajes pertenecientes al paradigma de la
Programación imperativa han evolucionado de manera que ya no son tan crípticos.
Sin embargo, aún existen casos donde el uso de lenguajes imperativos es inviable
debido a la complejidad del problema a resolver.

En cambio, la lógica matemática es la manera más sencilla, para el intelecto


humano, de expresar formalmente problemas complejos y de resolverlos mediante
la aplicación de reglas, hipótesis y teoremas. De ahí que el concepto de
"programación lógica" resulte atractivo en diversos campos donde la programación
tradicional es un fracaso.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


50
Análisis de Algoritmos

Campos de aplicación

La programación lógica encuentra su habitat natural en aplicaciones de inteligencia


artificial o relacionadas:

Sistemas expertos, donde un sistema de información imita las recomendaciones


de un experto sobre algún dominio de conocimiento.
Demostración automática de teoremas, donde un programa genera nuevos
teoremas sobre una teoría existente.
Reconocimiento de lenguaje natural, donde un programa es capaz de
comprender (con limitaciones) la información contenida en una expresión
lingüística humana.
Etc.

La programación lógica también se utiliza en aplicaciones más "mundanas" pero de


manera muy limitada, ya que la programación tradicional es más adecuada a
tareas de propósito general.

Fundamentos

La mayoría de los lenguajes de programación lógica se basan en la teoría lógica de


primer orden, aunque también incorporan algunos comportamientos de orden
superior. En este sentido, destacan los lenguajes funcionales, ya que se basan en el
cálculo lambda, que es la única teoría lógica de orden superior que es
demostradamente computable (hasta el momento).

En qué consiste (ejemplo)

La programación lógica permite formalizar hechos del mundo real, por ejemplo:

las aves vuelan


los pingüinos no vuelan
"pichurri" es un ave
"sandokan" es un perro
"alegría" es un ave
"pocholo" es un pingüino

y también reglas o restricciones:

una mascota vuela si es un ave y no es un pingüino

Ante dicho "programa" es posible establecer hipótesis que no son mas que
preguntas o incógnitas, por ejemplo:

¿ "pichurri" vuela ?
¿ qué mascotas vuelan ?

Gracias a que la lógica de primer orden es computable, el ordenador será capaz de


verificar la hipótesis, es decir, responder a las incógnitas:

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


51
Análisis de Algoritmos

Es cierto que "pichurri" vuela.


"pichurri" y "alegría" vuelan.

Obsérvese que el programa lógico no solamente es capaz de responder si una


determinada hipótesis es verdadera o falsa. También es capaz de determinar que
valores de la incógnita hacen cierta la hipótesis.

Este ejemplo es claramente académico. Sin embargo, consideremos el siguiente


ejemplo: el sistema de control de semáforos de una ciudad.

El estado de cada uno de los semáforos (verde, rojo o ámbar) constituye los
hechos del mundo real. El programa en sí consiste en unas pocas reglas de sentido
común: determinados semáforos no pueden permanecer simultáneamente en
verde, un semáforo solamente puede transitar de verde a ambar y de ambar a
rojo, etc. La hipótesis es el estado en el que deberían estar cada uno de los
semaforos en el siguiente instante de tiempo.

Este es un ejemplo imposible de resolver mediante programación tradicional, ya


que la lógica subyacente al comportamiento de los semáforos en su conjunto queda
enmascarada por simples ordenes imperativas del tipo "cambiar color de tal o cual
semaforo".

Lenguajes

El lenguaje de programación lógica por excelencia es Prolog, que cuenta con


diversas variantes. La más importante es la Programación lógica con restricciones,
que posibilita la resolución de ecuaciones lineales además de la demostración de
hipótesis

5.5 Paradigma orientado a eventos

La programación dirigida por eventos es un paradigma de programación en el que


tanto la estructura como la ejecución de los programas van determinados por los
sucesos que ocurran en el sistema o que ellos mismos provoquen.

Para entender la programación dirigida por eventos, podemos oponerla a lo que no es:
mientras en la programación secuencial es el programador el que define cuál va a ser
el flujo del programa, en la programación dirigida por eventos será el propio usuario
--o lo que sea que esté accionando el programa-- el que dirija el flujo del programa.

En la programación dirigida por eventos, al comenzar la ejecución del programa se


llevarán a cabo las inicializaciones y demás código inicial y a continuación el programa
quedará bloqueado hasta que se produzca algún evento. Cuando alguno de estos
eventos tenga lugar, el programa pasará a ejecutar el código del correspondiente
manejador de evento. Por ejemplo, si el evento consiste en que el usuario ha hecho
click en el botón de play de un reproductor de películas, se ejecutará el código del
manejador de evento, que será el que haga que la película se muestre por pantalla.

Un ejemplo claro lo tenemos en los sistemas de programación Lexico y Visual Basic, en


los que a cada elemento del programa (objetos, controles, etcétera) se le asignan una

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


52
Análisis de Algoritmos

serie de eventos que generará dicho elemento, como la pulsación de un botón del
ratón sobre él o el redibujado del control.

5.6 Paradigma ensamblador

Un aumento del primero cada lenguaje ensamblador está asociado a una maquina
concreta los valores manipulados ya o son abstractos sino se maneja su representación
binaria en la memoria del computador los elementos clave son:
o modos de direccionamiento
o etiquetas
o subrutinas
o interrupciones

5.7 Paradigma heurística

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


53
Análisis de Algoritmos

Muchas de las tareas más interesantes y difíciles de programación implican utilizar el


ordenador para resolver problemas del tipo: "¿Cuál es el camino más corto?"
"Listar todos los casos posibles", "¿Existe una disposición de elementos que
satisfaga?. Las características de estos problemas implica potencialmente una
búsqueda exhaustiva de todas las posibles combinaciones de algún conjunto
finito, que si no está controlado puede producir una "explosión combinatoria"
(incremento exponencial del espacio de búsqueda con la dimensión del
problema) imposible de tratar.

La Programación Heurística ha venido a significar el uso del conocimiento


específico del dominio para cubrir esta explosión de posibilidades guiando la
búsqueda por las direcciones más prometedoras. Se puede definir como "aquel
tipo de programación computacional que aplica para la resolución de problemas
reglas de buena lógica (reglas del pulgar). Denominadas heurísticas, las cuales
proporcionan entre varios cursos de acción uno que presenta visos de ser el
más prometedor, pero no garantiza necesariamente el curso de acción más
efectivo."

La Programación Heurística implica una forma de modelizar el problema en lo


que respecta a la representación de su estructura, estrategias de búsqueda y
métodos de resolución, que configuran el Paradigma Heurístico.

Este tipo de programación se aplica con mayor intensidad en el campo de la


Inteligencia Artificial (IA), y en especial, en el de la Ingeniería del
Conocimiento, dado que el ser humano opera la mayor parte de las veces
utilizando heurísticas, un hecho cierto que una heurística es la conclusión del
razonamiento humano en un dominio específico, por lo que es normal que este
tipo de programación que encuadrado en el área de la I.A., ya que implementa
el conocimiento humano, dado por la experiencia, utilizando reglas de buena
lógica.

Como se ha señalado inicialmente, un paradigma de programación es un


modelo básico de diseño e implementación de programas. Un modelo que
permite producir programas de acuerdo con una metodología específica. Así, el
paradigma de programación estructurada se basa en estructuras modulares,
con fuerte cohesión en el módulo y bajo acoplamiento entre ellos, desarrollo
"top-down", utilización de diagramas privilegiados, etc.

El Paradigma Heurístico define pues, un modelo de resolución de problemas en


el que se incorpora alguna componente heurística sobre la base de:
Una representación más apropiada de la estructura del problema para su
resolución con técnicas heurísticas
La utilización de métodos de resolución de problemas aplicando funciones de
evaluación con procedimientos específicos de búsqueda heurística para la
consecución de las metas.

Por otra parte, la Programación Heurística se presenta y utiliza desde diferentes puntos
de vista:
Como técnica de búsqueda para la obtención de metas en problemas no
algorítmicos, o con algoritmos que generan explosión combinatoria (ej. damas.
ajedrez, etc.).
Como un método aproximado de resolución de problemas utilizando funciones
de evaluación de tipo heurístico (ej. algoritmos A*, AO*)

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


54
Análisis de Algoritmos

Como método de poda para estrategias de programas que juegan, aunque


estos métodos no son realmente heurísticos (ej. poda alfa-beta).

Se aconseja utilizar un modelo heurístico cuando:


Los datos, limitados e inexactos, utilizados para estimar los parámetros modelo
pueden contener errores inherentes muy superiores a los proporcionados con la
solución de una buena heurística.
Se utiliza un modelo simplificado, que por sí es una representación imprecisa de
un problema real, por lo que la solución "óptima" es puramente académica.
No se dispone de un método exacto que sea fiable para ser aplicado en un
modelo del problema; o si existe, es intratable computacionalmente.
Se desea mejorar la eficacia de un algoritmo optimizador aplicado al model por
ejemplo, proporcionando buenas soluciones de inicio, guiando la búsqueda y
reduciendo el número de soluciones candidatas
Se tiene la necesidad de resolver el mismo problema frecuentemente, o una
base de tiempo real, y el tratamiento heurístico significa un ahorro
computacional

En general, un modelo heurístico es aconsejable si puede proporcionar resultados


superiores a los del modelo actual.

Las especificaciones más relevantes del tratamiento heurístico deben tener en


cuenta las características de la heurística, de la información y de las
especificaciones del problema de acuerdo con las siguientes condiciones,
Una buena heurística debe ser simple, con requerimientos razonables de
memoria, con velocidad de búsqueda que no produzca incrementos
polinomiales, ni exponenciales, precisa, robusta, que proporcione soluciones
múltiples, y que disponga de un buen criterio de parada que incorpore el
conocimiento obtenido durante la búsqueda.
La información a tratar es fundamentalmente simbólica, inexacta o limitada,
"incremental" y basada en el conocimiento.
Las especificaciones del problema pueden ser: de optimización o de satisfación;
que produzcan una o múltiples soluciones; con tratamiento en tiempo real o no;
con decisión interactiva o no, etc.

La Programación Heurística no ha producido un lenguaje específico de programación,


debido a que las heurísticas, al "ser reglas de sentido común", se pueden
implementar con cualquiera de los lenguajes descritos en los diferentes
paradigmas de programación. Por otra parte, al aplicarse este tipo de
programación, fundamentalmente, en el campo de la I.A., las heurísticas están
siendo implementadas mayoritariamente en herramientas de esta área.

No obstante, si se tuviera que definir un lenguaje heurístico las características más


destacables que debería incorporar son:
Ser un lenguaje conversacional, que permitiera una interacción directa con el
programador para la definición e implementación del problema.
Tratamiento de estructuras "incrementales, que implementen programas que
vayan ampliando el cuerpo de conocimiento que, en base a la experiencia,
configure y refine el modelo heurístico.
Tratamiento fundamentalmente simbólico, dado que la mayor parte de los
problemas que precisan tratamiento heurístico tienen estructura simbólica.

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


55
Análisis de Algoritmos

Unidades funcionales autónomas que posibiliten modelar una heurística y su


mecanismo de ejecución, definiendo módulos independientes.
Estructuras de datos que permitan describir estados de problemas y relaciones
entre estados.
Estructuras procedimentales de control y de proceso (o de definición) que
permitan la ejecución coherente del modelo heurístico, y posibiliten la
adquisición y utilización del conocimiento adquirido en el proceso de resolución
del problema.
6. Bibliografía

Diseño y análisis de algoritmos funcionales e imperativos ¨javier galve


frances
Galve, J., Gonzáles, J.C., Sánchez A.,Veláquez J. A. Algoritmica, Diseño
y Análisis de Algoritmos. Addison Wesley.
*Trakhtenbrot, B.A., Algoritmos y Computadoras. Limusa.
Aguilar, Ramiro, Programación II.
Aho A., Hopcroft J., Ullman D. Estructura de datos y Algoritmos. Addison
Wesley¨

ANALISIS Y COMPLEJIDAD DE ALGORITMOS


56