Navegación

-Primer Año

Programacion Estructurada

Programación estructurada

La programación estructurada es una forma de escribir programas de ordenador (programación de computadora) de forma clara. Para ello utiliza únicamente tres estructuras: secuencia, selección e iteración; siendo innecesario el uso de la instrucción o instrucciones de transferencia incondicional (GOTO, EXIT FUNCTION, EXIT SUB o múltiples RETURN).

Hoy en día las aplicaciones informáticas son mucho más ambiciosas que las necesidades de programación existentes en los años 1960, principalmente debido a las aplicaciones gráficas, por lo que las técnicas de programación estructurada no son suficientes. Ello ha llevado al desarrollo de nuevas técnicas, tales como la programación orientada a objetos y el desarrollo de entornos de programación que facilitan la programación de grandes aplicaciones.

Orígenes de la programación estructurada

A finales de los años 1960 surgió una nueva forma de programar que no solamente daba lugar a programas fiables y eficientes, sino que además estaban escritos de manera que facilitaba su comprensión posterior.

El teorema del programa estructurado, demostrado por Böhm-Jacopini, demuestra que todo programa puede escribirse utilizando únicamente las tres instrucciones de control siguientes:

  • Secuencia
  • Instrucción condicional.
  • Iteración (bucle de instrucciones) con condición al principio.

Solamente con estas tres estructuras se pueden escribir todos los programas y aplicaciones posibles. Si bien los lenguajes de programación tienen un mayor repertorio de estructuras de control, éstas pueden ser construidas mediante las tres básicas.

Estructura secuencial

Una estructura de programa es secuencial si se ejecutan una tras otra a modo de secuencia, es decir que una instrucción no se ejecuta hasta que finaliza la anterior.

Ejemplo:

   INPUT x

   INPUT y

   auxiliar= x

   x= y

   y= auxiliar

   PRINT x

   PRINT y

  • Esta secuencia de instrucciones permuta los valores de x e y, con ayuda de una variable auxiliar, intermedia.
  • 1º Guardamos una copia del valor de x en auxiliar.
  • 2º Guardamos el valor de y en x, se pierde el valor anterior de x pero no importa porque tenemos una copia en auxiliar.
  • 3º Guardamos en y el valor de auxiliar, que es el valor inicial de x.
  • El resultado es el intercambio de los valores de x e y, en tres operaciones secuenciales.

Estructura selectiva o de selección

La estructura selectiva permite la realización de una instrucción u otra según un criterio, solo una de estas instrucciones se ejecutara.

Ejemplo:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSE

      PRINT a ; "no es mayor que" ; b

   END IF

Esta instrucción selectiva puede presentar dos mensajes, uno a es mayor que b, y el otro a no es mayor que b, solo uno de ellos será presentado, según el resultado de la comparación de a y b, si el resultado de a > b es cierto, se presenta el primer mensaje, si es falso el segundo, las palabras IF, THEN, ELSE, END IF; son propias de la instrucción (palabra reservadas) que tienen un significado en el lenguaje, sirven de separadores, y el usuario no debe utilizarlas salvo para este fin.

  • IF señala el comienzo de la instrucción condicional, y se espera que después esté la condición de control de la instrucción.
  • THEN señala el fin de la condición, y después estará la instrucción a realizar si la condición es cierta.
  • ELSE separa la instrucción que se ejecutará si la condición es cierta de la que se ejecutará si es falsa.
  • END IF indica que la instrucción condicional finaliza y el programa seguirá su curso.

Ampliemos un poco el ejemplo anterior:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSEIF a < b THEN

      PRINT a ; "es menor que" ; b

   ELSE

      PRINT a ; "es igual que" ; b

   END IF

Este ejemplo nos permite considerar situaciones en las que tenemos más de dos alternativas. En este caso hemos considerado tres, pero hay situaciones en las que deben considerarse más casos y para ellos se puede repetir las veces que queramos la parte ELSEIF.

Estructura iterativa

Un bucle iterativo o iteración de una secuencia de instrucciones, hace que se repitan mientras se cumpla una condición, en un principio el número de iteraciones no tiene porque estar determinado.

Ejemplo:

   a= 0

   b= 7

 

   WHILE b > a DO

      PRINT a

      a= a + 1

   WEND

Esta instrucción tiene tres palabras reservadas WHILE, DO y WEND.

  • WHILE: señala el comienzo del bucle y después de esta palabra se espera la condición de repetición, si la condición es cierta se pasa al cuerpo del bucle, si no al final de la instrucción mientras.
  • DO: señala el final de la condición, lo que esté después será el cuerpo del bucle.
  • WEND: señala el final del cuerpo del bucle y de la instrucción WHILE.

El bucle mientras, se repite mientras la condición sea cierta, esta condición se comprueba al principio por lo que el cuerpo del bucle puede que no se ejecute nunca, cuando la condición es falsa en un principio, o que se repita tantas veces como sea necesario, mientras la condición sea cierta.

En el ejemplo tenemos dos variables a y b que al iniciarse el bucle tienen los valores a=0 y b=7.

La condición del bucle es b > a.

Cuando a=0 y b=7. la condición es cierta, en el cuerpo del bucle se escribe el valor de a en pantalla y se incrementa a en una unidad. Entonces a=1 y b=7.

...

...

Cuando a=6 y b=7. la condición es cierta, se escribe el valor de a en pantalla y se incrementa en una unidad.

Resultando que a=7 y b=7. Entonces la condición es falsa y la instrucción WHILE finaliza.

La salida por pantalla de este ejemplo seria 0 1 2 3 4 5 6

Anidamiento

El cuerpo de cualquier estructura puede ser una instrucción simple u otra estructura, que a su vez puede anidar a otra.

Ejemplo:

   IF a > b THEN

      auxiliar= a

      a= b

      b= auxiliar

   ELSE

      REM nada

   END IF

   PRINT a ; b

Ventajas de la programación estructurada

1. Los programas son más fáciles de entender, ya que pueden ser leídos de forma secuencial, sin necesidad de hacer seguimiento a saltos de línea (GOTO) dentro de los bloques de código para entender la lógica.

2. La estructura del programa es clara, puesto que las instrucciones están más ligadas o relacionadas entre sí.

3. Reducción del esfuerzo en las pruebas. El seguimiento de los fallos o errores del programa ("debugging") se facilita debido a la estructura más visible, por lo que los errores se pueden detectar y corregir más fácilmente.

4. Reducción de los costos de mantenimiento de los programas.

5. Programas más sencillos y más rápidos (ya que es más fácil su optimización).

6. Los bloques de código son auto explicativos, lo que facilita la documentación.

7. Los GOTO se reservan para construir las instrucciones básicas. Aunque no se usan de forma directa, por estar prohibida su utilización, están incluidas implícitamente en las instrucciones de selección e iteración.

8. Un programa escrito de acuerdo a estos principios no solamente tendrá una mejor estructura sino también una excelente presentación.

9. La programación estructurada ofrece estos beneficios, pero no se la debe considerar como una panacea ya que el desarrollo de programas es, principalmente, una tarea de dedicación, esfuerzo y creatividad.

 

Inconvenientes de la programación estructurada

El principal inconveniente de este método de programación es que se obtiene un único bloque de programa, que cuando se hace demasiado grande puede resultar problemático su manejo; esto se resuelve empleando la programación modular, definiendo módulos interdependientes programados y compilados por separado (en realidad esto no es necesario, pero es recomendable para su mantenimiento y funcionalidad).

En realidad, cuando se programa hoy en día (inicios del siglo XXI) se suelen utilizar, tanto las técnicas de programación estructurada como las de programación modular, de forma conjunta y por lo tanto es posible que cuando uno haga referencia a la programación estructurada esté considerando también las técnicas de modularización.

Un método un poco más sofisticado es la programación por capas, en la que los módulos tienen una estructura jerárquica en la que se pueden definir funciones dentro de funciones o de procedimientos.

Algoritmo

En ciencias de la computación y disciplinas relacionadas, un algoritmo (del latín, dixit algorithmus y éste a su vez del matemático persa Al Juarismi[1] ) es una lista bien definida, ordenada y finita de operaciones que permite hallar la solución a un problema.[2] Dado un estado inicial y una entrada, a través de pasos sucesivos y bien definidos se llega a un estado final, obteniendo una solución. Los algoritmos son objeto de estudio de la algoritmia.[1]

En la vida cotidiana se emplean algoritmos en multitud de ocasiones para resolver diversos problemas. Algunos ejemplos se encuentran en los instructivos (manuales de usuario), los cuales muestran algoritmos para usar el aparato en cuestión o incluso en las instrucciones que recibe un trabajador por parte de su patrón. También existen ejemplos de índole matemática, como el algoritmo de la división para calcular el cociente de dos números, el algoritmo de Euclides para calcular el máximo común divisor de dos enteros positivos, o el método de Gauss para resolver un Sistema lineal de ecuaciones.

Características principales y definición formal

En general, no existe ningún consenso definitivo en cuanto a la definición formal de algoritmo. Muchos autores los señalan como listas de instrucciones para resolver un problema abstracto, es decir, que un número finito de pasos convierten los datos de un problema (entrada) en una solución (salida).[1] [2] [3] [4] [5] [6] Sin embargo cabe notar que algunos algoritmos no necesariamente tienen que terminar o resolver un problema en particular. Por ejemplo, una versión modificada de la criba de Eratóstenes que nunca termine de calcular números primos no deja de ser un algoritmo.[7]

A lo largo de la historia varios autores han tratado de definir formalmente a los algoritmos utilizando modelos matemáticos como máquinas de Turing entre otros.[8] [9] Sin embargo estos modelos están sujetos a un tipo particular de datos como son números, símbolos o gráficas mientras que, en general, los algoritmos funcionan sobre una basta cantidad de estructuras de datos.[3] [1] En general, la parte común en todas las definiciones se puede resumir en las siguientes tres propiedades siempre y cuando no consideremos algoritmos paralelos:[7]

Tiempo secuencial. Un algoritmo funciona en tiempo discretizado –paso a paso–, definiendo así una secuencia de estados "computacionales" por cada entrada válida (la entrada son los datos que se le suministran al algoritmo antes de comenzar).

Estado abstracto. Cada estado computacional puede ser descrito formalmente utilizando una estructura de primer orden y cada algoritmo es independiente de su implementación (los algoritmos son objetos abstractos) de manera que en un algoritmo las estructuras de primer orden son invariantes bajo isomorfismo.

Exploración acotada. La transición de un estado al siguiente queda completamente determinada por una descripción fija y finita; es decir, entre cada estado y el siguiente solamente se puede tomar en cuenta una cantidad fija y limitada de términos del estado actual.

En resumen, un algoritmo es cualquier cosa que funcione paso a paso, donde cada paso se pueda describir sin ambigüedad y sin hacer referencia a una computadora en particular, y además tiene un límite fijo en cuanto a la cantidad de datos que se pueden leer/escribir en un solo paso. Esta amplia definición abarca tanto a algoritmos prácticos como aquellos que solo funcionan en teoría, por ejemplo el método de Newton y la eliminación de Gauss-Jordan funcionan, al menos en principio, con números de precisión infinita; sin embargo no es posible programar la precisión infinita en una computadora, y no por ello dejan de ser algoritmos.[10] En particular es posible considerar una cuarta propiedad que puede ser usada para validar la tesis de Church-Turing de que toda función calculable se puede programar en una máquina de Turing (o equivalentemente, en un lenguaje de programación suficientemente general):[10]

Aritmetizabilidad. Solamente operaciones innegablemente calculables están disponibles en el paso inicial.

Medios de expresión de un algoritmo [editar]

Los algoritmos pueden ser expresados de muchas maneras, incluyendo al lenguaje natural, pseudocódigo, diagramas de flujo y lenguajes de programación entre otros. Las descripciones en lenguaje natural tienden a ser ambiguas y extensas. El usar pseudocódigo y diagramas de flujo evita muchas ambigüedades del lenguaje natural. Dichas expresiones son formas más estructuradas para representar algoritmos; no obstante, se mantienen independientes de un lenguaje de programación específico.

La descripción de un algoritmo usualmente se hace en tres niveles:

  1. Descripción de alto nivel. Se establece el problema, se selecciona un modelo matemático y se explica el algoritmo de manera verbal, posiblemente con ilustraciones y omitiendo detalles.
  2. Descripción formal. Se usa pseudocódigo para describir la secuencia de pasos que encuentran la solución.
  3. Implementación. Se muestra el algoritmo expresado en un lenguaje de programación específico o algún objeto capaz de llevar a cabo instrucciones.

También es posible incluir un teorema que demuestre que el algoritmo es correcto, un análisis de complejidad o ambos.

Diagrama de flujo

Diagrama de flujo que expresa un algoritmo para calcular la raíz cuadrada de un número x

Artículo principal: Diagrama de flujo

Los diagramas de flujo son descripciones gráficas de algoritmos; usan símbolos conectados con flechas para indicar la secuencia de instrucciones y están regidos por ISO.

Los diagramas de flujo son usados para representar algoritmos pequeños, ya que abarcan mucho espacio y su construcción es laboriosa. Por su facilidad de lectura son usados como introducción a los algoritmos, descripción de un lenguaje y descripción de procesos a personas ajenas a la computación.

Pseudocódigo

Artículo principal: Pseudocódigo

Pseudocódigo es la descripción de un algoritmo que asemeja a un lenguaje de programación pero con algunas convenciones del lenguaje natural (de ahí que tenga el prefijo pseudo, que significa falso). Tiene varias ventajas con respecto a los diagramas de flujo, entre las que se destaca el poco espacio que se requiere para representar instrucciones complejas. El pseudocódigo no está regido por ningún estándar.

Sistemas formales

La teoría de autómatas y la teoría de funciones recursivas proveen modelos matemáticos que formalizan el concepto de algoritmo. Los modelos más comunes son la máquina de Turing, máquina de registro y funciones μ-recursivas. Estos modelos son tan precisos como un lenguaje máquina, careciendo de expresiones coloquiales o ambigüedad, sin embargo se mantienen independientes de cualquier computadora y de cualquier implementación.

Implementación

Muchos algoritmos son ideados para implementarse en un programa. Sin embargo, los algoritmos pueden ser implementados en otros medios, como una red neuronal, un circuito eléctrico o un aparato mecánico y eléctrico. Algunos algoritmos inclusive se diseñan especialmente para implementarse usando lápiz y papel. El algoritmo de multiplicación tradicional, el algoritmo de Euclides, la criba de Eratóstenes y muchas formas de resolver la raíz cuadrada son sólo algunos ejemplos.

Algoritmos como funciones

Artículo principal: Teoría de la computabilidad

Esquemática de un algoritmo solucionando un problema de ciclo hamiltoniano.

Un algoritmo se puede concebir como una función que transforma los datos de un problema (entrada) en los datos de una solución (salida). Más aún, los datos se pueden representar a su vez como secuencias de bits, y en general, de símbolos cualesquiera.[1] [9] [11] Como cada secuencia de bits representa a un número natural (véase Sistema binario), entonces los algoritmos son en esencia funciones de los números naturales en los números naturales que sí se pueden calcular. Es decir que todo algoritmo calcula una función donde cada número natural es la codificación de un problema o de una solución.

En ocasiones los algoritmos son susceptibles de nunca terminar, por ejemplo, cuando entran a un bucle infinito. Cuando esto ocurre, el algoritmo nunca devuelve ningún valor de salida, y podemos decir que la función queda indefinida para ese valor de entrada. Por esta razón se considera que los algoritmos son funciones parciales, es decir, no necesariamente definidas en todo su dominio de definición.

Cuando una función puede ser calculada por medios algorítmicos, sin importar la cantidad de memoria que ocupe o el tiempo que se tarde, se dice que dicha función es computable. No todas las funciones entre secuencias datos son computables. El problema de la parada es un ejemplo.

Análisis de algoritmos

Artículo principal: Análisis de algoritmos

Como medida de la eficiencia de un algoritmo, se suelen estudiar los recursos (memoria y tiempo) que consume el algoritmo. El análisis de algoritmos se ha desarrollado para obtener valores que de alguna forma indiquen (o especifiquen) la evolución del gasto de tiempo y memoria en función del tamaño de los valores de entrada.

El análisis y estudio de los algoritmos es una disciplina de las ciencias de la computación y, en la mayoría de los casos, su estudio es completamente abstracto sin usar ningún tipo de lenguaje de programación ni cualquier otra implementación; por eso, en ese sentido, comparte las características de las disciplinas matemáticas. Así, el análisis de los algoritmos se centra en los principios básicos del algoritmo, no en los de la implementación particular. Una forma de plasmar (o algunas veces "codificar") un algoritmo es escribirlo en pseudocódigo o utilizar un lenguaje muy simple tal como Léxico, cuyos códigos pueden estar en el idioma del programador.

Algunos escritores restringen la definición de algoritmo a procedimientos que deben acabar en algún momento, mientras que otros consideran procedimientos que podrían ejecutarse eternamente sin pararse, suponiendo el caso en el que existiera algún dispositivo físico que fuera capaz de funcionar eternamente. En este último caso, la finalización con éxito del algoritmo no se podría definir como la terminación de éste con una salida satisfactoria, sino que el éxito estaría definido en función de las secuencias de salidas dadas durante un periodo de vida de la ejecución del algoritmo. Por ejemplo, un algoritmo que verifica que hay más ceros que unos en una secuencia binaria infinita debe ejecutarse siempre para que pueda devolver un valor útil. Si se implementa correctamente, el valor devuelto por el algoritmo será válido, hasta que evalúe el siguiente dígito binario. De esta forma, mientras evalúa la siguiente secuencia podrán leerse dos tipos de señales: una señal positiva (en el caso de que el número de ceros sea mayor que el de unos) y una negativa en caso contrario. Finalmente, la salida de este algoritmo se define como la devolución de valores exclusivamente positivos si hay más ceros que unos en la secuencia y, en cualquier otro caso, devolverá una mezcla de señales positivas y negativas.

Ejemplo de algoritmo

El problema consiste en encontrar el máximo de un conjunto de números. Para un ejemplo más complejo véase Algoritmo de Euclides.

Descripción de alto nivel

Dado un conjunto finito C de números, se tiene el problema de encontrar el número más grande. Sin pérdida de generalidad se puede asumir que dicho conjunto no es vacío y que sus elementos están numerados como c_0,c_1,\dots,c_n.

Es decir, dado un conjunto C=\{c_0,c_1,\dots,c_n\}se pide encontrar m tal que x\leq mpara todo elemento x que pertenece al conjunto C.

Para encontrar el elemento máximo, se asume que el primer elemento (c0) es el máximo; luego, se recorre el conjunto y se compara cada valor con el valor del máximo número encontrado hasta ese momento. En el caso que un elemento sea mayor que el máximo, se asigna su valor al máximo. Cuando se termina de recorrer la lista, el máximo número que se ha encontrado es el máximo de todo el conjunto.


Tipos de algoritmos según su función

Técnicas de diseño de algoritmos

  • Algoritmos voraces (greedy): seleccionan los elementos más prometedores del conjunto de candidatos hasta encontrar una solución. En la mayoría de los casos la solución no es óptima.
  • Algoritmos paralelos: permiten la división de un problema en subproblemas de forma que se puedan ejecutar de forma simultánea en varios procesadores.
  • Algoritmos probabilísticos: algunos de los pasos de este tipo de algoritmos están en función de valores pseudoaleatorios
  • Algoritmos determinísticos: El comportamiento del algoritmo es lineal: cada paso del algoritmo tiene únicamente un paso sucesor y otro ancesor.
  • Algoritmos no determinísticos: El comportamiento del algoritmo tiene forma de árbol y a cada paso del algoritmo puede bifurcarse a cualquier número de pasos inmediatamente posteriores, además todas las ramas se ejecutan simultáneamente.
  • Divide y vencerás: dividen el problema en subconjuntos disjuntos obteniendo una solución de cada uno de ellos para después unirlas, logrando así la solución al problema completo.
  • Metaheurísticas: encuentran soluciones aproximadas (no óptimas) a problemas basándose en un conocimiento anterior (a veces llamado experiencia) de los mismos.
  • Programación dinámica: intenta resolver problemas disminuyendo su coste computacional aumentando el coste espacial.
  • Ramificación y acotación: se basa en la construcción de las soluciones al problema mediante un árbol implícito que se recorre de forma controlada encontrando las mejores soluciones.
  • Vuelta Atrás (Backtracking): se construye el espacio de soluciones del problema en un árbol que se examina completamente, almacenando las soluciones menos costosas.

 

Diseño estructurado

En programación y diseño de algoritmos, el diseño estructurado persigue elaborar algoritmos que cumplan la propiedad de modularidad, para ello, dado un problema que se pretende resolver mediante la elaboración de un programa de ordenador, se busca dividir dicho programa en módulos siguiendo los principios de diseño de Descomposición por refinamientos sucesivos, creación de una Jerarquía modular y elaboración de módulos Independientes.

Etapas del Diseño estructurado

Descomposición

¿Por qué descomponer un problema en partes? Experimentalmente está comprobado que:

  • Un problema complejo cuesta más de resolver que otro más sencillo (de Perogrullo).
  • La complejidad de un problema global es mayor que el valor de las complejidades de cada una de sus partes por separado.

Según esto, merece la pena el esfuerzo de dividir un problema grande en subproblemas más pequeños. Si el objetivo es elaborar un programa para resolver dicho problema grande, cada subproblema (menos complejo) podrá ser resuelto por un módulo (subalgoritmo) relativamente fácil de implementar (más que el programa global No dividido). Ahora la cuestión es ¿cómo realizar la descomposición?; realizando un estudio descendente Top-Down que nos lleve desde la concepción del problema (programa o algoritmo) global hasta identificar sus partes (módulos). Esta técnica se repite aplicando una estrategia llamada de refinamiento sucesivo propuesta por el experto en Ciencias de la Computación Niklaus Wirth, que consiste precisamente en volver a aplicar el estudio descendente Top-Down a cada subproblema una y otra vez hasta obtener subproblemas suficientemente pequeños, que puedan ser resueltos por módulos que cumplan, en la medida de lo posible, las características deseables en un módulo en el ámbito de la programación. En palabras del propio Niklaus Wirth:

  • En cada paso (del refinamiento), una o varias instrucciones del programa dado, se descomponen en instrucciones más detalladas. Esta descomposición sucesiva o refinamiento de especificaciones termina cuanto todas las instrucciones están expresadas en términos de la computadora usada o del lenguaje de programación...
  • Conforme se refinan las tareas, también los datos pueden ser refinados, descompuestos o estructurados, siendo lo natural refinar las especificaciones del programa y de los datos en paralelo.
  • Cada paso de refinamiento implica algunas decisiones de diseño. Es importante que el programador sea consciente de los criterios subyacentes (en las decisiones de diseño adoptadas) y de la existencia de soluciones alternativas...

Problema del refinamiento sucesivo

¿Cuándo parar el refinamiento?. Un refinamiento excesivo podría dar lugar a un número tan grande de módulos que haría poco práctica la descomposición. Se tendrán en cuenta estos criterios para dejar de descomponer:

  • Cuando no haya tareas bien definidas.
  • Cuando la interfaz de un módulo sea tan complicada como el propio módulo

Jerarquía de módulos

Ésta es una consecuencia directa de la descomposición del problema mediante refinamientos sucesivos, el resultado será un conjunto de módulos estratificados en capas a modo de pirámide donde en la cima habrá un único módulo que representará al programa global y en los niveles inferiores aparecerán los módulos resultantes de las sucesivas divisiones.

Al final, debe obtenerse una estructura piramidal donde los módulos de los niveles superiores se encargan de las tareas de coordinación, lógica de la aplicación y manipulación de los módulos inferiores; estos otros deberán realizar tareas de cálculo, tratamiento y entrada/salida de información.

Independencia

Módulo

En programación un módulo es una parte de un programa de ordenador. De las varias tareas que debe realizar un programa para cumplir con su función u objetivos, un módulo realizará una de dichas tareas (o quizá varias en algún caso).

En un caso general (no necesariamente relacionado con la programación), un módulo recibirá como entrada la salida que haya proporcionado un módulo anterior o los datos de entrada al sistema (programa) si se trata del módulo inicial de éste; y proporcionará una salida que será utilizada como entrada de un módulo posterior o que será la salida final del sistema (programa) si se tratase del módulo final.

Particularmente, en el caso de la programación, los módulos suelen estar organizados jerárquicamente en niveles, de forma que hay un módulo superior que realiza las llamadas oportunas a los módulos del nivel inferior. Cuando un módulo es llamado, recibe como entrada los datos proporcionados por el módulo de nivel superior que ha hecho la llamada, realiza su tarea, a su vez este módulo puede llamar a otro u otros módulos de nivel inferior si fuera necesario; cuando finaliza su tarea, devuelve la salida pertinente al módulo superior que lo llamo inicialmente, y es este módulo superior el que continúa con la ejecución del programa.

Características de un módulo

Cada uno de los módulo de un programa idealmente debería cumplir las siguientes características:

  • Tamaño pequeño.- Facilita aislar el impacto que pueda tener la realización de un cambio en el programa, bien para corregir un error, bien por rediseño del algoritmo correspondiente.
  • Independencia modular.- Cuanto más independientes son los módulos entre sí más fácilmente se trabajará con ellos, esto implica que para desarrollar un módulo no es necesario conocer detalles internos de otros módulos. Como consecuencia de la independencia modular un módulo cumplirá:

·         Características de caja negra, es decir abstracción (ver abstracción en programación orientada a objetos).

·         Aislamiento de los detalles mediante encapsulamiento (ver encapsulamiento en programación orientada a objetos).

Evaluando el diseño

Para evaluar o determinar como de bueno es un diseño estructurado se utilizan los conceptos de acoplamiento y cohesión; éstos están muy relacionados entre sí, tanto que difícilmente se puede variar uno sin que eso afecte al otro. También cabe decir que estos conceptos no son medidas que se puedan cuantificar numéricamente, son más bien magnitudes cualitativas. También se tienen en consideración los conceptos de fan-in y fan-out.

Acoplamiento

Se define como el grado de interdependencia que hay entre los distintos módulos de un programa; lo deseable es que esta interdependencia sea lo menor posible, es decir, un bajo acoplamiento. Los niveles de acoplamiento, ordenados de menor (más deseable) a mayor (menos deseable) son:

  • Acoplamiento normal.- Un módulo llama a otro de un nivel inferior y tan solo intercambian datos (parámetros de entrada/salida). Dentro de este tipo de acoplamiento podemos encontrarnos 3 subtipos, dependiendo de los datos que intercambien los módulos:
    • Acoplamiento de datos: Los módulos se comunican mediante parámetros.
    • Acoplamiento de marca o por estampado: Los módulos se pasan datos con estructura de registro. No es muy deseable si el módulo receptor sólo requiere parte de los datos que se le pasan.
    • Acoplamiento de control: Los datos que se intercambian entre los módulos son controles. Debido a que en este subtipo un módulo controla la ejecución del otro, no es un buen acoplamiento, ya que impide que sean totalmente independientes.
  • Acoplamiento Común.- Dos módulos acceden a un mismo recurso común, típicamente memoria compartida, una variable global o un fichero. Una variante de este tipo de acoplamiento es el acoplamiento externo:
    • Acoplamiento externo.- Los módulos están ligados a componentes externos. Por ejemplo, dispositivos de E/S, protocolos de comunicaciones... etc.
  • Acoplamiento de contenido.- Ocurre cuando un módulo necesita acceder a una parte de otro módulo.

Cohesión

Se define como la medida de fuerza o relación funcional existente entre las sentencias o grupos de sentencias de un mismo módulo. Un módulo coherente ejecutará una única tarea sencilla interactuando muy poco o nada con el resto de módulos del programa. Se persigue que los módulos tengan una alta cohesión.

En el diseño estructurado podemos encontrarnos con los siguientes 7 tipos de cohesión (de la mejor o más deseable a la menos recomendable):

  • Cohesión funcional: Los elementos del módulo están relacionados en el desarrollo de una única función.
  • Cohesión secuencial: Un módulo realiza distintas tareas en secuencia, de forma que las entradas de cada tarea son las salidas de la tarea anterior. No es una mala cohesión si las tareas implicadas no son muy complejas y requieren pocas líneas de código.
  • Cohesión comunicacional: El módulo realiza actividades paralelas usando los mismos datos de entrada y salida. Como en el caso anterior, tampoco se trata de un mal tipo de cohesión si las tareas son relativamente sencillas.
  • Cohesión procedimental: El módulo tiene una serie de funciones relacionadas por un procedimiento efectuado por el código (a modo de librería). Es similar a la secuencial, pero puede incluir el paso de controles. Será deseable que las funciones estén relacionadas o realicen tareas dentro del mismo ámbito (p.e. la librería string.h de C contienen funciones para operar con cadenas de caracteres).
  • Cohesión temporal: Los elementos del módulo están implicados en actividades relacionadas con el tiempo.
  • Cohesión lógica: Las actividades que realiza el módulo tienen la misma categoría. Esto es, es como si se tuvieran partes independientes dentro del mismo módulo.
  • Cohesión casual o coincidente: Los elementos del módulo contribuyen a las actividades relacionándose mutuamente de una manera poco significativa. Este tipo de cohesión viola el principio de independencia y de caja negra de los módulos.

Fan-In y Fan-Out

Además de los dos conceptos anteriores, se deben tener en cuenta el grado de absorción (fan-in) y la diseminación del control (fan-out) de los módulos para garantizar la calidad del diseño.

  • Fan-In: También llamado grado de absorción. Es el número de superordinados inmediatos que tiene el módulo en cuestión. Es conveniente maximizar el fan-in durante el proceso de diseño, ya que cada instancia de fan-in múltiple indica que se ha evitado la duplicación de código.
  • Fan-Out: También llamado diseminación del control. Es el número de subordinados inmediatos que tiene el módulo en cuestión. Conviene no tener un fan-out ni muy alto ni muy bajo, ya que eso es un posible indicador de un diseño pobre. Si no es posible evitarlo, es preferible un fan-out bajo antes que uno alto.

Diagrama de flujo

Diagrama de flujo sencillo con los pasos a seguir si una lámpara no funciona.

Un diagrama de flujo es una forma de representar gráficamente los detalles algorítmicos de un proceso multifactorial. Se utiliza principalmente en programación, economía y procesos industriales, pasando también a partir de estas disciplinas a formar parte fundamental de otras, como la psicología cognitiva. Estos diagramas utilizan una serie de símbolos con significados especiales y son la representación gráfica de los pasos de un proceso. En computación, son modelos tecnológicos utilizados para comprender los rudimentos de la programación secuencial

Definición

Es la representación gráfica de flujo de un algoritmo o de secuencias rutinarias. Se basan en la utilización de diversos símbolos para representar operaciones específicas. Se les llama diagramas de flujo porque los símbolos utilizados se conectan por medio de flechas para indicar la secuencia de la operación.

Símbolos utilizados

Los símbolos que se utilizan para diseño se someten a una normalización, es decir, se hicieron símbolos casi universales, ya que, en un principio cada usuario podría tener sus propios símbolos para representar sus procesos en forma de Diagrama de flujo. Esto trajo como consecuencia que sólo aquel que conocía sus símbolos, los podía interpretar. La simbología utilizada para la elaboración de diagramas de flujo es variable y debe ajustarse a las normas preestablecidas universalmente para dichos símbolos o datos.

 

Características que debe cumplir un diagrama de flujo

En los diagramas de flujo se presuponen los siguientes aspectos:

  • Existe siempre un camino que permite llegar a una solución (finalización del algoritmo).
  • Existe un único inicio del proceso.
  • Existe un único punto de fin para el proceso de flujo (salvo del rombo que indica una comparación con dos caminos posibles).

Desarrollo del diagrama de flujo

Las siguientes son acciones previas a la realización del diagrama de flujo:

  • Identificar las ideas principales a ser incluidas en el diagrama de flujo. Deben estar presentes el dueño o responsable del proceso, los dueños o responsables del proceso anterior y posterior y de otros procesos interrelacionados, otras partes interesadas.
  • Definir qué se espera obtener del diagrama de flujo.
  • Identificar quién lo empleará y cómo.
  • Establecer el nivel de detalle requerido.
  • Determinar los límites del proceso a describir.

Los pasos a seguir para construir el diagrama de flujo son :

  • Establecer el alcance del proceso a describir. De esta manera quedará fijado el comienzo y el final del diagrama. Frecuentemente el comienzo es la salida del proceso previo y el final la entrada al proceso siguiente.
  • Identificar y listar las principales actividades/subprocesos que están incluidos en el proceso a describir y su orden cronológico.
  • Si el nivel de detalle definido incluye actividades menores, listarlas también.
  • Identificar y listar los puntos de decisión.
  • Construir el diagrama respetando la secuencia cronológica y asignando los correspondientes símbolos.
  • Asignar un título al diagrama y verificar que esté completo y describa con exactitud el proceso elegido.


Diagramas Básicos de Flujo Gramas



 Estructuras de control

En lenguajes de programación, las estructuras de control permiten modificar el flujo de ejecución de las instrucciones de un programa.

Con las estructuras de control se puede:

  • De acuerdo a una condición, ejecutar un grupo u otro de sentencias (If-Then-Else y Select-Case)
  • Ejecutar un grupo de sentencias mientras exista una condición (Do-While)
  • Ejecutar un grupo de sentencias hasta que exista una condición (Do-Until)
  • Ejecutar un grupo de sentencias un número determinado de veces (For-Next)
  • Etc

Todas las estructuras de control tienen un único punto de entrada y un único punto de salida. Las estructuras de control se puede clasificar en : secuenciales, iterativas y de control avanzadas. Esto es una de las cosas que permite que la programación se rija por los principios de la programación estructurada.

Los lenguajes de programación modernos tienen estructuras de control similares. Básicamente lo que varía entre las estructuras de control de los diferentes lenguajes es su sintaxis, cada lenguaje tiene una sintaxis propia para expresar la estructura.

Otros lenguajes ofrecen estructuras diferentes, como por ejemplo los comandos guardados.

Tipos de estructura de control

Antecendentes

El término "estructuras de control", viene del campo de la ciencia computacional. Cuando se presentan implementaciones de Java para las estructuras de control, nos referimos a ellas con la terminología de la Especificación del lenguaje Java, que se refiera a ella como instrucciones.

Ejecución secuencial

Pero por lo general las instrucciones se ejecutan una después de la otra, en el orden en que están escritas, es decir, en secuencia. Este proceso se conoce como ejecución secuencial.

Transferencia de control

En lenguajes de programación por excelencia como C y/o C++, el programador puede especificar que las siguientes instrucciones a ejecutarse tal vez no sea la siguiente en secuencia. Esto se conoce como transferencia de control. Hay que tener en cuenta que la instrucción goto es una palabra reservada pero no se utiliza ni se recomienda. Un programa bien estructurado no necesita de esta instrucción. Si sabes programar no utilizaras goto.

Estructura de control: selección if simple

Se trata de una estructura de control que permite redirigir un curso de acción según la evaluación de una condición simple, sea falsa o verdadera. Por ejemplo: Escribir un programa en Java que compare dos números e indique si cuál es mayor, menor, mayor y/o igual, menor y/o igual, o si son iguales:

  String strComparacion = "";

...

  if( numero1 == numero2 )

     strComparacion += numero1 + " == " + numero2;

  if( numero1 > numero2 )

     strComparacion += numero1 + " > " + numero2;

  if( numero1 < numero2 )

     strComparacion += numero1 + " < " + numero2;

  if( numero1 >= numero2 )

     strComparacion += numero1 + " >= " + numero2;

  if( numero1 <= numero2 )

     strComparacion += numero1 + " <= " + numero2;

  System.out.println(strComparacion);

...

If-Then-Else

La estructura selectiva permite la realización de una instrucción u otra según un criterio, solo una de estas instrucciones se ejecutara.

Ejemplo:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSE

      PRINT a ; "no es mayor que" ; b

   END IF

Esta instrucción selectiva puede presentar dos mensajes, uno a es mayor que b, y el otro a no es mayor que b, solo uno de ellos será presentado, según el resultado de la comparación de a y b, si el resultado de a > b es cierto, se presenta el primer mensaje, si es falso el segundo, las palabras IF, THEN, ELSE, END IF; son propias de la instrucción (palabra reservadas) que tienen un significado en el lenguaje, sirven de separadores, y el usuario no debe utilizarlas salvo para este fin.

  • IF señala el comienzo de la instrucción condicional, y se espera que después esté la condición de control de la instrucción.
  • THEN señala el fin de la condición, y después estará la instrucción a realizar si la condición es cierta.
  • ELSE separa la instrucción que se ejecutará si la condición es cierta de la que se ejecutará si es falsa.
  • END IF indica que la instrucción condicional finaliza y el programa seguirá su curso.

Ampliemos un poco el ejemplo anterior:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSEIF a < b THEN

      PRINT a ; "es menor que" ; b

   ELSE

      PRINT a ; "es igual que" ; b

   END IF

Este ejemplo nos permite considerar situaciones en las que tenemos más de dos alternativas. En este caso hemos considerado tres, pero hay situaciones en las que deben considerarse más casos y para ellos se puede repetir las veces que queramos la parte ELSEIF.

 

Si la condición es verdadera, se ejecuta el bloque de sentencias 1, de lo contrario, se ejecuta el bloque de sentencias 2.

   IF (Condición) THEN

      (Bloque de sentencias 1)

   ELSE

      (Bloque de sentencias 2)

   END IF

Select-Case

  • Se evalúa la expresión, dando como resultado un número.
  • Luego, se recorren los "Case" dentro de la estructura buscando que el número coincida con uno de los valores.
  • Es necesario que coincidan todos sus valores.
  • Cuando se encuentra la primera coincidencia, se ejecuta el bloque de sentencias correspondiente y se sale de la estructura Select-Case.
  • Si no se encuentra ninguna coincidencia con ningún valor, se ejecuta el bloque de sentencias de la sección "Case Else".

   SELECT (Expresión)

      CASE Valor1

         (Bloque de sentencias 1)

      CASE Valor2

         (Bloque de sentencias 2)

      CASE Valor n

         (Bloque de sentencias n)

      CASE ELSE

         (Bloque de sentencias "Else")

   END SELECT

Do-While

Mientras la condición sea verdadera, se ejecutarán las sentencias del bloque.

   DO WHILE (Condición)

      (Bloque de sentencias)

   LOOP

que también puede expresarse:

   WHILE (Condición)

      (Bloque de sentencias)

   WEND

Do-Until

Se ejecuta el bloque de sentencias, hasta que la condición sea verdadera

   DO

      (Bloque de sentencias)

   LOOP UNTIL (Condición)

For-Next

  • Primero, se evalúan las expresiones 1 y 2, dando como resultado dos números.
  • La variable del bucle recorrerá los valores desde el número dado por la expresión 1 hasta el número dado por la expresión 2.
  • El bloque de sentencias se ejecutará en cada uno de los valores que tome la variable del bucle.

   FOR (Variable) = (Expresión1) TO (Expresión2) STEP (Salto)

      (Bloque de sentencias)

   NEXT

Estructuras anidadas

Las estructuras de control básicas pueden anidarse, es decir pueden ponerse una dentro de otra.


 

Ejercicios:

Operaciones Aritméticas Básicas (+, -, *, /)

Operaciones de Comparación( <, >, <>, <=, >=, etc.)

Operaciones Aritméticas complejas (Mod, \, ^,)

Operaciones de Relación (And, Or, Not)

Operador lógico

Los operadores lógicos son utilizados por la lógica proposicional para admitir o rechazar proposiciones. En programación de ordenadores se utilizan para combinar valores lógicos (Verdadero/Falso) y obtener nuevos valores lógicos que determinen el flujo de control de un algoritmo o programa.

Tablas de Verdad

El comportamiento de un operador lógico suele definirse mediante su correspondiente tabla de verdad, en ella se muestra el resultado que produce la aplicación de un determinado operador a uno o dos valores lógicos. Las operaciones lógicas más usuales son:


  • NO lógico (NOT) o negación:

Operador unario (aplicado a un único operando). Cambia el valor de verdad de verdadero (V) a falso (F) y viceversa.

p

NOT p

V

F

F

V

 

 

 

 

 

  • O lógica (OR) o disyunción:

Operador n-ario (aplicado a 2 o más operandos). Si todos los operandos son F devuelve F; si hay alguno que sea V devuelve V.

p

q

p OR q

V

V

V

V

F

V

F

V

V

F

F

F

 

 

 

 

  • Y lógica (AND) o conjunción:

Operador n-ario . Si todos los operandos son V devuelve V; si hay alguno que sea F devuelve F.

p

q

p AND q

V

V

V

V

F

F

F

V

F

F

F

F

 

 

  • O-eXclusiva lógica (XOR):

Operador binario (aplicado a dos operandos). Devuelve V cuando ambos operandos son distintos y F cuando son iguales.

p

q

p XOR q

V

V

F

V

F

V

F

V

V

F

F

F

 


Los 16 operadores lógicos binarios pueden ser definidos a través de la siguiente Tabla de Verdad :

p

q

T

~p

~q

\leftrightarrow

\vee

\not\leftrightarrow

q

\not\leftarrow

p

\not\rightarrow

\wedge

F

T

T

T

F

T

F

T

F

T

F

T

F

T

F

T

F

T

F

T

F

T

T

F

F

T

T

F

F

T

T

F

F

T

T

F

F

F

T

T

T

T

T

F

F

F

F

T

T

T

T

F

F

F

F

F

F

T

T

T

T

T

T

T

T

F

F

F

F

F

F

F

F


Donde:

  • T : tautología
  • ↑ : negación alternativa, incompatibilidad, no ambos, exclusión, "NAND"
  • → : condicional, implicación (simple), "IMP"
  • ~ : negación, "NOT"
  • ← : implicación inversa
  • \leftrightarrow : bicondicional, implicación doble, equivalencia, "EQV", "XNOR"
  • ↓ : negación conjunta, "NOR"
  • \vee: disyunción, "Ó", "OR"
  • \not\leftrightarrow : disyunción exclusiva, contravalencia, "XOR"
  • \not\leftarrow : negación del condicional inverso
  • \not\rightarrow : negación del condicional
  • \wedge : conjunción, "Y", "AND"
  • F : contradicción

 

 

Bienvenidos Futuros Programadores estarás apunto de dar tus primeros pasos en la amplia rama de la programación de ordenadores, será un camino largo así que agarra fuerzas y no te rindas.....  Empecemos ya.

Programación estructurada

La programación estructurada es una forma de escribir programas de ordenador (programación de computadora) de forma clara. Para ello utiliza únicamente tres estructuras: secuencia, selección e iteración; siendo innecesario el uso de la instrucción o instrucciones de transferencia incondicional (GOTO, EXIT FUNCTION, EXIT SUB o múltiples RETURN).

Hoy en día las aplicaciones informáticas son mucho más ambiciosas que las necesidades de programación existentes en los años 1960, principalmente debido a las aplicaciones gráficas, por lo que las técnicas de programación estructurada no son suficientes. Ello ha llevado al desarrollo de nuevas técnicas, tales como la programación orientada a objetos y el desarrollo de entornos de programación que facilitan la programación de grandes aplicaciones.

Orígenes de la programación estructurada

A finales de los años 1960 surgió una nueva forma de programar que no solamente daba lugar a programas fiables y eficientes, sino que además estaban escritos de manera que facilitaba su comprensión posterior.

El teorema del programa estructurado, demostrado por Böhm-Jacopini, demuestra que todo programa puede escribirse utilizando únicamente las tres instrucciones de control siguientes:

  • Secuencia
  • Instrucción condicional.
  • Iteración (bucle de instrucciones) con condición al principio.

Solamente con estas tres estructuras se pueden escribir todos los programas y aplicaciones posibles. Si bien los lenguajes de programación tienen un mayor repertorio de estructuras de control, éstas pueden ser construidas mediante las tres básicas.

Estructura secuencial

Una estructura de programa es secuencial si se ejecutan una tras otra a modo de secuencia, es decir que una instrucción no se ejecuta hasta que finaliza la anterior.

Ejemplo:

   INPUT x

   INPUT y

   auxiliar= x

   x= y

   y= auxiliar

   PRINT x

   PRINT y

  • Esta secuencia de instrucciones permuta los valores de x e y, con ayuda de una variable auxiliar, intermedia.
  • 1º Guardamos una copia del valor de x en auxiliar.
  • 2º Guardamos el valor de y en x, se pierde el valor anterior de x pero no importa porque tenemos una copia en auxiliar.
  • 3º Guardamos en y el valor de auxiliar, que es el valor inicial de x.
  • El resultado es el intercambio de los valores de x e y, en tres operaciones secuenciales.

Estructura selectiva o de selección

La estructura selectiva permite la realización de una instrucción u otra según un criterio, solo una de estas instrucciones se ejecutara.

Ejemplo:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSE

      PRINT a ; "no es mayor que" ; b

   END IF

Esta instrucción selectiva puede presentar dos mensajes, uno a es mayor que b, y el otro a no es mayor que b, solo uno de ellos será presentado, según el resultado de la comparación de a y b, si el resultado de a > b es cierto, se presenta el primer mensaje, si es falso el segundo, las palabras IF, THEN, ELSE, END IF; son propias de la instrucción (palabra reservadas) que tienen un significado en el lenguaje, sirven de separadores, y el usuario no debe utilizarlas salvo para este fin.

  • IF señala el comienzo de la instrucción condicional, y se espera que después esté la condición de control de la instrucción.
  • THEN señala el fin de la condición, y después estará la instrucción a realizar si la condición es cierta.
  • ELSE separa la instrucción que se ejecutará si la condición es cierta de la que se ejecutará si es falsa.
  • END IF indica que la instrucción condicional finaliza y el programa seguirá su curso.

Ampliemos un poco el ejemplo anterior:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSEIF a < b THEN

      PRINT a ; "es menor que" ; b

   ELSE

      PRINT a ; "es igual que" ; b

   END IF

Este ejemplo nos permite considerar situaciones en las que tenemos más de dos alternativas. En este caso hemos considerado tres, pero hay situaciones en las que deben considerarse más casos y para ellos se puede repetir las veces que queramos la parte ELSEIF.

Estructura iterativa

Un bucle iterativo o iteración de una secuencia de instrucciones, hace que se repitan mientras se cumpla una condición, en un principio el número de iteraciones no tiene porque estar determinado.

Ejemplo:

   a= 0

   b= 7

 

   WHILE b > a DO

      PRINT a

      a= a + 1

   WEND

Esta instrucción tiene tres palabras reservadas WHILE, DO y WEND.

  • WHILE: señala el comienzo del bucle y después de esta palabra se espera la condición de repetición, si la condición es cierta se pasa al cuerpo del bucle, si no al final de la instrucción mientras.
  • DO: señala el final de la condición, lo que esté después será el cuerpo del bucle.
  • WEND: señala el final del cuerpo del bucle y de la instrucción WHILE.

El bucle mientras, se repite mientras la condición sea cierta, esta condición se comprueba al principio por lo que el cuerpo del bucle puede que no se ejecute nunca, cuando la condición es falsa en un principio, o que se repita tantas veces como sea necesario, mientras la condición sea cierta.

En el ejemplo tenemos dos variables a y b que al iniciarse el bucle tienen los valores a=0 y b=7.

La condición del bucle es b > a.

Cuando a=0 y b=7. la condición es cierta, en el cuerpo del bucle se escribe el valor de a en pantalla y se incrementa a en una unidad. Entonces a=1 y b=7.

...

...

Cuando a=6 y b=7. la condición es cierta, se escribe el valor de a en pantalla y se incrementa en una unidad.

Resultando que a=7 y b=7. Entonces la condición es falsa y la instrucción WHILE finaliza.

La salida por pantalla de este ejemplo seria 0 1 2 3 4 5 6

Anidamiento

El cuerpo de cualquier estructura puede ser una instrucción simple u otra estructura, que a su vez puede anidar a otra.

Ejemplo:

   IF a > b THEN

      auxiliar= a

      a= b

      b= auxiliar

   ELSE

      REM nada

   END IF

   PRINT a ; b


Ventajas de la programación estructurada

1. Los programas son más fáciles de entender, ya que pueden ser leídos de forma secuencial, sin necesidad de hacer seguimiento a saltos de línea (GOTO) dentro de los bloques de código para entender la lógica.

2. La estructura del programa es clara, puesto que las instrucciones están más ligadas o relacionadas entre sí.

3. Reducción del esfuerzo en las pruebas. El seguimiento de los fallos o errores del programa ("debugging") se facilita debido a la estructura más visible, por lo que los errores se pueden detectar y corregir más fácilmente.

4. Reducción de los costos de mantenimiento de los programas.

5. Programas más sencillos y más rápidos (ya que es más fácil su optimización).

6. Los bloques de código son auto explicativos, lo que facilita la documentación.

7. Los GOTO se reservan para construir las instrucciones básicas. Aunque no se usan de forma directa, por estar prohibida su utilización, están incluidas implícitamente en las instrucciones de selección e iteración.

8. Un programa escrito de acuerdo a estos principios no solamente tendrá una mejor estructura sino también una excelente presentación.

9. La programación estructurada ofrece estos beneficios, pero no se la debe considerar como una panacea ya que el desarrollo de programas es, principalmente, una tarea de dedicación, esfuerzo y creatividad.

 

Inconvenientes de la programación estructurada

El principal inconveniente de este método de programación es que se obtiene un único bloque de programa, que cuando se hace demasiado grande puede resultar problemático su manejo; esto se resuelve empleando la programación modular, definiendo módulos interdependientes programados y compilados por separado (en realidad esto no es necesario, pero es recomendable para su mantenimiento y funcionalidad).

En realidad, cuando se programa hoy en día (inicios del siglo XXI) se suelen utilizar, tanto las técnicas de programación estructurada como las de programación modular, de forma conjunta y por lo tanto es posible que cuando uno haga referencia a la programación estructurada esté considerando también las técnicas de modularización.

Un método un poco más sofisticado es la programación por capas, en la que los módulos tienen una estructura jerárquica en la que se pueden definir funciones dentro de funciones o de procedimientos.

Algoritmo

En ciencias de la computación y disciplinas relacionadas, un algoritmo (del latín, dixit algorithmus y éste a su vez del matemático persa Al Juarismi[1] ) es una lista bien definida, ordenada y finita de operaciones que permite hallar la solución a un problema.[2] Dado un estado inicial y una entrada, a través de pasos sucesivos y bien definidos se llega a un estado final, obteniendo una solución. Los algoritmos son objeto de estudio de la algoritmia.[1]

En la vida cotidiana se emplean algoritmos en multitud de ocasiones para resolver diversos problemas. Algunos ejemplos se encuentran en los instructivos (manuales de usuario), los cuales muestran algoritmos para usar el aparato en cuestión o incluso en las instrucciones que recibe un trabajador por parte de su patrón. También existen ejemplos de índole matemática, como el algoritmo de la división para calcular el cociente de dos números, el algoritmo de Euclides para calcular el máximo común divisor de dos enteros positivos, o el método de Gauss para resolver un Sistema lineal de ecuaciones.

Características principales y definición formal

En general, no existe ningún consenso definitivo en cuanto a la definición formal de algoritmo. Muchos autores los señalan como listas de instrucciones para resolver un problema abstracto, es decir, que un número finito de pasos convierten los datos de un problema (entrada) en una solución (salida).[1] [2] [3] [4] [5] [6] Sin embargo cabe notar que algunos algoritmos no necesariamente tienen que terminar o resolver un problema en particular. Por ejemplo, una versión modificada de la criba de Eratóstenes que nunca termine de calcular números primos no deja de ser un algoritmo.[7]

A lo largo de la historia varios autores han tratado de definir formalmente a los algoritmos utilizando modelos matemáticos como máquinas de Turing entre otros.[8] [9] Sin embargo estos modelos están sujetos a un tipo particular de datos como son números, símbolos o gráficas mientras que, en general, los algoritmos funcionan sobre una basta cantidad de estructuras de datos.[3] [1] En general, la parte común en todas las definiciones se puede resumir en las siguientes tres propiedades siempre y cuando no consideremos algoritmos paralelos:[7]

Tiempo secuencial. Un algoritmo funciona en tiempo discretizado –paso a paso–, definiendo así una secuencia de estados "computacionales" por cada entrada válida (la entrada son los datos que se le suministran al algoritmo antes de comenzar).

Estado abstracto. Cada estado computacional puede ser descrito formalmente utilizando una estructura de primer orden y cada algoritmo es independiente de su implementación (los algoritmos son objetos abstractos) de manera que en un algoritmo las estructuras de primer orden son invariantes bajo isomorfismo.

Exploración acotada. La transición de un estado al siguiente queda completamente determinada por una descripción fija y finita; es decir, entre cada estado y el siguiente solamente se puede tomar en cuenta una cantidad fija y limitada de términos del estado actual.

En resumen, un algoritmo es cualquier cosa que funcione paso a paso, donde cada paso se pueda describir sin ambigüedad y sin hacer referencia a una computadora en particular, y además tiene un límite fijo en cuanto a la cantidad de datos que se pueden leer/escribir en un solo paso. Esta amplia definición abarca tanto a algoritmos prácticos como aquellos que solo funcionan en teoría, por ejemplo el método de Newton y la eliminación de Gauss-Jordan funcionan, al menos en principio, con números de precisión infinita; sin embargo no es posible programar la precisión infinita en una computadora, y no por ello dejan de ser algoritmos.[10] En particular es posible considerar una cuarta propiedad que puede ser usada para validar la tesis de Church-Turing de que toda función calculable se puede programar en una máquina de Turing (o equivalentemente, en un lenguaje de programación suficientemente general):[10]

Aritmetizabilidad. Solamente operaciones innegablemente calculables están disponibles en el paso inicial.


Medios de expresión de un algoritmo

Los algoritmos pueden ser expresados de muchas maneras, incluyendo al lenguaje natural, pseudocódigo, diagramas de flujo y lenguajes de programación entre otros. Las descripciones en lenguaje natural tienden a ser ambiguas y extensas. El usar pseudocódigo y diagramas de flujo evita muchas ambigüedades del lenguaje natural. Dichas expresiones son formas más estructuradas para representar algoritmos; no obstante, se mantienen independientes de un lenguaje de programación específico.

La descripción de un algoritmo usualmente se hace en tres niveles:

  1. Descripción de alto nivel. Se establece el problema, se selecciona un modelo matemático y se explica el algoritmo de manera verbal, posiblemente con ilustraciones y omitiendo detalles.
  2. Descripción formal. Se usa pseudocódigo para describir la secuencia de pasos que encuentran la solución.
  3. Implementación. Se muestra el algoritmo expresado en un lenguaje de programación específico o algún objeto capaz de llevar a cabo instrucciones.

También es posible incluir un teorema que demuestre que el algoritmo es correcto, un análisis de complejidad o ambos.

Diagrama de flujo

http://upload.wikimedia.org/wikipedia/commons/thumb/2/26/AlgoritmoRaiz.png/180px-AlgoritmoRaiz.png

http://es.wikipedia.org/skins-1.5/common/images/magnify-clip.png

Diagrama de flujo que expresa un algoritmo para calcular la raíz cuadrada de un número x

Artículo principal: Diagrama de flujo

Los diagramas de flujo son descripciones gráficas de algoritmos; usan símbolos conectados con flechas para indicar la secuencia de instrucciones y están regidos por ISO.

Los diagramas de flujo son usados para representar algoritmos pequeños, ya que abarcan mucho espacio y su construcción es laboriosa. Por su facilidad de lectura son usados como introducción a los algoritmos, descripción de un lenguaje y descripción de procesos a personas ajenas a la computación.

Pseudocódigo

Artículo principal: Pseudocódigo

Pseudocódigo es la descripción de un algoritmo que asemeja a un lenguaje de programación pero con algunas convenciones del lenguaje natural (de ahí que tenga el prefijo pseudo, que significa falso). Tiene varias ventajas con respecto a los diagramas de flujo, entre las que se destaca el poco espacio que se requiere para representar instrucciones complejas. El pseudocódigo no está regido por ningún estándar.

Sistemas formales

La teoría de autómatas y la teoría de funciones recursivas proveen modelos matemáticos que formalizan el concepto de algoritmo. Los modelos más comunes son la máquina de Turing, máquina de registro y funciones μ-recursivas. Estos modelos son tan precisos como un lenguaje máquina, careciendo de expresiones coloquiales o ambigüedad, sin embargo se mantienen independientes de cualquier computadora y de cualquier implementación.

Implementación

Muchos algoritmos son ideados para implementarse en un programa. Sin embargo, los algoritmos pueden ser implementados en otros medios, como una red neuronal, un circuito eléctrico o un aparato mecánico y eléctrico. Algunos algoritmos inclusive se diseñan especialmente para implementarse usando lápiz y papel. El algoritmo de multiplicación tradicional, el algoritmo de Euclides, la criba de Eratóstenes y muchas formas de resolver la raíz cuadrada son sólo algunos ejemplos.

Algoritmos como funciones

Artículo principal: Teoría de la computabilidad

http://upload.wikimedia.org/wikipedia/commons/thumb/a/a3/Esquem%C3%A1ticaAlgoritmo1.svg/400px-Esquem%C3%A1ticaAlgoritmo1.svg.png

http://es.wikipedia.org/skins-1.5/common/images/magnify-clip.png

Esquemática de un algoritmo solucionando un problema de ciclo hamiltoniano.

Un algoritmo se puede concebir como una función que transforma los datos de un problema (entrada) en los datos de una solución (salida). Más aún, los datos se pueden representar a su vez como secuencias de bits, y en general, de símbolos cualesquiera.[1] [9] [11] Como cada secuencia de bits representa a un número natural (véase Sistema binario), entonces los algoritmos son en esencia funciones de los números naturales en los números naturales que sí se pueden calcular. Es decir que todo algoritmo calcula una función donde cada número natural es la codificación de un problema o de una solución.

En ocasiones los algoritmos son susceptibles de nunca terminar, por ejemplo, cuando entran a un bucle infinito. Cuando esto ocurre, el algoritmo nunca devuelve ningún valor de salida, y podemos decir que la función queda indefinida para ese valor de entrada. Por esta razón se considera que los algoritmos son funciones parciales, es decir, no necesariamente definidas en todo su dominio de definición.

Cuando una función puede ser calculada por medios algorítmicos, sin importar la cantidad de memoria que ocupe o el tiempo que se tarde, se dice que dicha función es computable. No todas las funciones entre secuencias datos son computables. El problema de la parada es un ejemplo.

Análisis de algoritmos

Artículo principal: Análisis de algoritmos

Como medida de la eficiencia de un algoritmo, se suelen estudiar los recursos (memoria y tiempo) que consume el algoritmo. El análisis de algoritmos se ha desarrollado para obtener valores que de alguna forma indiquen (o especifiquen) la evolución del gasto de tiempo y memoria en función del tamaño de los valores de entrada.

El análisis y estudio de los algoritmos es una disciplina de las ciencias de la computación y, en la mayoría de los casos, su estudio es completamente abstracto sin usar ningún tipo de lenguaje de programación ni cualquier otra implementación; por eso, en ese sentido, comparte las características de las disciplinas matemáticas. Así, el análisis de los algoritmos se centra en los principios básicos del algoritmo, no en los de la implementación particular. Una forma de plasmar (o algunas veces "codificar") un algoritmo es escribirlo en pseudocódigo o utilizar un lenguaje muy simple tal como Léxico, cuyos códigos pueden estar en el idioma del programador.

Algunos escritores restringen la definición de algoritmo a procedimientos que deben acabar en algún momento, mientras que otros consideran procedimientos que podrían ejecutarse eternamente sin pararse, suponiendo el caso en el que existiera algún dispositivo físico que fuera capaz de funcionar eternamente. En este último caso, la finalización con éxito del algoritmo no se podría definir como la terminación de éste con una salida satisfactoria, sino que el éxito estaría definido en función de las secuencias de salidas dadas durante un periodo de vida de la ejecución del algoritmo. Por ejemplo, un algoritmo que verifica que hay más ceros que unos en una secuencia binaria infinita debe ejecutarse siempre para que pueda devolver un valor útil. Si se implementa correctamente, el valor devuelto por el algoritmo será válido, hasta que evalúe el siguiente dígito binario. De esta forma, mientras evalúa la siguiente secuencia podrán leerse dos tipos de señales: una señal positiva (en el caso de que el número de ceros sea mayor que el de unos) y una negativa en caso contrario. Finalmente, la salida de este algoritmo se define como la devolución de valores exclusivamente positivos si hay más ceros que unos en la secuencia y, en cualquier otro caso, devolverá una mezcla de señales positivas y negativas.

Ejemplo de algoritmo

El problema consiste en encontrar el máximo de un conjunto de números. Para un ejemplo más complejo véase Algoritmo de Euclides.


 

Descripción de alto nivel

Dado un conjunto finito C de números, se tiene el problema de encontrar el número más grande. Sin pérdida de generalidad se puede asumir que dicho conjunto no es vacío y que sus elementos están numerados como c_0,c_1,\dots,c_n.

Es decir, dado un conjunto C=\{c_0,c_1,\dots,c_n\}se pide encontrar m tal que x\leq mpara todo elemento x que pertenece al conjunto C.

Para encontrar el elemento máximo, se asume que el primer elemento (c0) es el máximo; luego, se recorre el conjunto y se compara cada valor con el valor del máximo número encontrado hasta ese momento. En el caso que un elemento sea mayor que el máximo, se asigna su valor al máximo. Cuando se termina de recorrer la lista, el máximo número que se ha encontrado es el máximo de todo el conjunto.

Descripción formal

El algoritmo escrito de una manera más formal, esto es, en pseudocódigo tendría el siguiente aspecto:

Algoritmo Encontrar el máximo de un conjunto

función \max(C)\,

//C es un conjunto no vacío de números//

n\gets|C|// | C | es el número de elementos de C//

m\gets c_0

para i\gets 1hasta n\,hacer

si c_i > m\,entonces

m\gets c_i

devolver m\,

Sobre la notación:

  • "\gets" representa la asignación entre dos objetos. Por ejemplo, m\leftarrow xsignifica que el objeto m cambia su valor por el de x
  • "devolver" termina el algoritmo y devuelve el valor a su derecha (en este caso, el máximo de C)

Tipos de algoritmos según su función

Técnicas de diseño de algoritmos

  • Algoritmos voraces (greedy): seleccionan los elementos más prometedores del conjunto de candidatos hasta encontrar una solución. En la mayoría de los casos la solución no es óptima.
  • Algoritmos paralelos: permiten la división de un problema en subproblemas de forma que se puedan ejecutar de forma simultánea en varios procesadores.
  • Algoritmos probabilísticos: algunos de los pasos de este tipo de algoritmos están en función de valores pseudoaleatorios
  • Algoritmos determinísticos: El comportamiento del algoritmo es lineal: cada paso del algoritmo tiene únicamente un paso sucesor y otro ancesor.
  • Algoritmos no determinísticos: El comportamiento del algoritmo tiene forma de árbol y a cada paso del algoritmo puede bifurcarse a cualquier número de pasos inmediatamente posteriores, además todas las ramas se ejecutan simultáneamente.
  • Divide y vencerás: dividen el problema en subconjuntos disjuntos obteniendo una solución de cada uno de ellos para después unirlas, logrando así la solución al problema completo.
  • Metaheurísticas: encuentran soluciones aproximadas (no óptimas) a problemas basándose en un conocimiento anterior (a veces llamado experiencia) de los mismos.
  • Programación dinámica: intenta resolver problemas disminuyendo su coste computacional aumentando el coste espacial.
  • Ramificación y acotación: se basa en la construcción de las soluciones al problema mediante un árbol implícito que se recorre de forma controlada encontrando las mejores soluciones.
  • Vuelta Atrás (Backtracking): se construye el espacio de soluciones del problema en un árbol que se examina completamente, almacenando las soluciones menos costosas.

Diseño estructurado

En programación y diseño de algoritmos, el diseño estructurado persigue elaborar algoritmos que cumplan la propiedad de modularidad, para ello, dado un problema que se pretende resolver mediante la elaboración de un programa de ordenador, se busca dividir dicho programa en módulos siguiendo los principios de diseño de Descomposición por refinamientos sucesivos, creación de una Jerarquía modular y elaboración de módulos Independientes.

Etapas del Diseño estructurado

Descomposición

¿Por qué descomponer un problema en partes? Experimentalmente está comprobado que:

  • Un problema complejo cuesta más de resolver que otro más sencillo (de Perogrullo).
  • La complejidad de un problema global es mayor que el valor de las complejidades de cada una de sus partes por separado.

Según esto, merece la pena el esfuerzo de dividir un problema grande en subproblemas más pequeños. Si el objetivo es elaborar un programa para resolver dicho problema grande, cada subproblema (menos complejo) podrá ser resuelto por un módulo (subalgoritmo) relativamente fácil de implementar (más que el programa global No dividido). Ahora la cuestión es ¿cómo realizar la descomposición?; realizando un estudio descendente Top-Down que nos lleve desde la concepción del problema (programa o algoritmo) global hasta identificar sus partes (módulos). Esta técnica se repite aplicando una estrategia llamada de refinamiento sucesivo propuesta por el experto en Ciencias de la Computación Niklaus Wirth, que consiste precisamente en volver a aplicar el estudio descendente Top-Down a cada subproblema una y otra vez hasta obtener subproblemas suficientemente pequeños, que puedan ser resueltos por módulos que cumplan, en la medida de lo posible, las características deseables en un módulo en el ámbito de la programación. En palabras del propio Niklaus Wirth:

  • En cada paso (del refinamiento), una o varias instrucciones del programa dado, se descomponen en instrucciones más detalladas. Esta descomposición sucesiva o refinamiento de especificaciones termina cuanto todas las instrucciones están expresadas en términos de la computadora usada o del lenguaje de programación...
  • Conforme se refinan las tareas, también los datos pueden ser refinados, descompuestos o estructurados, siendo lo natural refinar las especificaciones del programa y de los datos en paralelo.
  • Cada paso de refinamiento implica algunas decisiones de diseño. Es importante que el programador sea consciente de los criterios subyacentes (en las decisiones de diseño adoptadas) y de la existencia de soluciones alternativas...

Problema del refinamiento sucesivo

¿Cuándo parar el refinamiento?. Un refinamiento excesivo podría dar lugar a un número tan grande de módulos que haría poco práctica la descomposición. Se tendrán en cuenta estos criterios para dejar de descomponer:

  • Cuando no haya tareas bien definidas.
  • Cuando la interfaz de un módulo sea tan complicada como el propio módulo

Jerarquía de módulos

Ésta es una consecuencia directa de la descomposición del problema mediante refinamientos sucesivos, el resultado será un conjunto de módulos estratificados en capas a modo de pirámide donde en la cima habrá un único módulo que representará al programa global y en los niveles inferiores aparecerán los módulos resultantes de las sucesivas divisiones.

Al final, debe obtenerse una estructura piramidal donde los módulos de los niveles superiores se encargan de las tareas de coordinación, lógica de la aplicación y manipulación de los módulos inferiores; estos otros deberán realizar tareas de cálculo, tratamiento y entrada/salida de información.

Independencia

Módulo

En programación un módulo es una parte de un programa de ordenador. De las varias tareas que debe realizar un programa para cumplir con su función u objetivos, un módulo realizará una de dichas tareas (o quizá varias en algún caso).

En un caso general (no necesariamente relacionado con la programación), un módulo recibirá como entrada la salida que haya proporcionado un módulo anterior o los datos de entrada al sistema (programa) si se trata del módulo inicial de éste; y proporcionará una salida que será utilizada como entrada de un módulo posterior o que será la salida final del sistema (programa) si se tratase del módulo final.

Particularmente, en el caso de la programación, los módulos suelen estar organizados jerárquicamente en niveles, de forma que hay un módulo superior que realiza las llamadas oportunas a los módulos del nivel inferior. Cuando un módulo es llamado, recibe como entrada los datos proporcionados por el módulo de nivel superior que ha hecho la llamada, realiza su tarea, a su vez este módulo puede llamar a otro u otros módulos de nivel inferior si fuera necesario; cuando finaliza su tarea, devuelve la salida pertinente al módulo superior que lo llamo inicialmente, y es este módulo superior el que continúa con la ejecución del programa.

Características de un módulo

Cada uno de los módulo de un programa idealmente debería cumplir las siguientes características:

  • Tamaño pequeño.- Facilita aislar el impacto que pueda tener la realización de un cambio en el programa, bien para corregir un error, bien por rediseño del algoritmo correspondiente.
  • Independencia modular.- Cuanto más independientes son los módulos entre sí más fácilmente se trabajará con ellos, esto implica que para desarrollar un módulo no es necesario conocer detalles internos de otros módulos. Como consecuencia de la independencia modular un módulo cumplirá:

·         Características de caja negra, es decir abstracción (ver abstracción en programación orientada a objetos).

·         Aislamiento de los detalles mediante encapsulamiento (ver encapsulamiento en programación orientada a objetos).

Evaluando el diseño

Para evaluar o determinar como de bueno es un diseño estructurado se utilizan los conceptos de acoplamiento y cohesión; éstos están muy relacionados entre sí, tanto que difícilmente se puede variar uno sin que eso afecte al otro. También cabe decir que estos conceptos no son medidas que se puedan cuantificar numéricamente, son más bien magnitudes cualitativas. También se tienen en consideración los conceptos de fan-in y fan-out.

Acoplamiento

Se define como el grado de interdependencia que hay entre los distintos módulos de un programa; lo deseable es que esta interdependencia sea lo menor posible, es decir, un bajo acoplamiento. Los niveles de acoplamiento, ordenados de menor (más deseable) a mayor (menos deseable) son:

  • Acoplamiento normal.- Un módulo llama a otro de un nivel inferior y tan solo intercambian datos (parámetros de entrada/salida). Dentro de este tipo de acoplamiento podemos encontrarnos 3 subtipos, dependiendo de los datos que intercambien los módulos:
    • Acoplamiento de datos: Los módulos se comunican mediante parámetros.
    • Acoplamiento de marca o por estampado: Los módulos se pasan datos con estructura de registro. No es muy deseable si el módulo receptor sólo requiere parte de los datos que se le pasan.
    • Acoplamiento de control: Los datos que se intercambian entre los módulos son controles. Debido a que en este subtipo un módulo controla la ejecución del otro, no es un buen acoplamiento, ya que impide que sean totalmente independientes.
  • Acoplamiento Común.- Dos módulos acceden a un mismo recurso común, típicamente memoria compartida, una variable global o un fichero. Una variante de este tipo de acoplamiento es el acoplamiento externo:
    • Acoplamiento externo.- Los módulos están ligados a componentes externos. Por ejemplo, dispositivos de E/S, protocolos de comunicaciones... etc.
  • Acoplamiento de contenido.- Ocurre cuando un módulo necesita acceder a una parte de otro módulo.

Cohesión

Se define como la medida de fuerza o relación funcional existente entre las sentencias o grupos de sentencias de un mismo módulo. Un módulo coherente ejecutará una única tarea sencilla interactuando muy poco o nada con el resto de módulos del programa. Se persigue que los módulos tengan una alta cohesión.

En el diseño estructurado podemos encontrarnos con los siguientes 7 tipos de cohesión (de la mejor o más deseable a la menos recomendable):

  • Cohesión funcional: Los elementos del módulo están relacionados en el desarrollo de una única función.
  • Cohesión secuencial: Un módulo realiza distintas tareas en secuencia, de forma que las entradas de cada tarea son las salidas de la tarea anterior. No es una mala cohesión si las tareas implicadas no son muy complejas y requieren pocas líneas de código.
  • Cohesión comunicacional: El módulo realiza actividades paralelas usando los mismos datos de entrada y salida. Como en el caso anterior, tampoco se trata de un mal tipo de cohesión si las tareas son relativamente sencillas.
  • Cohesión procedimental: El módulo tiene una serie de funciones relacionadas por un procedimiento efectuado por el código (a modo de librería). Es similar a la secuencial, pero puede incluir el paso de controles. Será deseable que las funciones estén relacionadas o realicen tareas dentro del mismo ámbito (p.e. la librería string.h de C contienen funciones para operar con cadenas de caracteres).
  • Cohesión temporal: Los elementos del módulo están implicados en actividades relacionadas con el tiempo.
  • Cohesión lógica: Las actividades que realiza el módulo tienen la misma categoría. Esto es, es como si se tuvieran partes independientes dentro del mismo módulo.
  • Cohesión casual o coincidente: Los elementos del módulo contribuyen a las actividades relacionándose mutuamente de una manera poco significativa. Este tipo de cohesión viola el principio de independencia y de caja negra de los módulos.

Fan-In y Fan-Out

Además de los dos conceptos anteriores, se deben tener en cuenta el grado de absorción (fan-in) y la diseminación del control (fan-out) de los módulos para garantizar la calidad del diseño.

  • Fan-In: También llamado grado de absorción. Es el número de superordinados inmediatos que tiene el módulo en cuestión. Es conveniente maximizar el fan-in durante el proceso de diseño, ya que cada instancia de fan-in múltiple indica que se ha evitado la duplicación de código.
  • Fan-Out: También llamado diseminación del control. Es el número de subordinados inmediatos que tiene el módulo en cuestión. Conviene no tener un fan-out ni muy alto ni muy bajo, ya que eso es un posible indicador de un diseño pobre. Si no es posible evitarlo, es preferible un fan-out bajo antes que uno alto.

Diagrama de flujo

Diagrama de flujo sencillo con los pasos a seguir si una lámpara no funciona.

Un diagrama de flujo es una forma de representar gráficamente los detalles algorítmicos de un proceso multifactorial. Se utiliza principalmente en programación, economía y procesos industriales, pasando también a partir de estas disciplinas a formar parte fundamental de otras, como la psicología cognitiva. Estos diagramas utilizan una serie de símbolos con significados especiales y son la representación gráfica de los pasos de un proceso. En computación, son modelos tecnológicos utilizados para comprender los rudimentos de la programación secuencial

Definición

Es la representación gráfica de flujo de un algoritmo o de secuencias rutinarias. Se basan en la utilización de diversos símbolos para representar operaciones específicas. Se les llama diagramas de flujo porque los símbolos utilizados se conectan por medio de flechas para indicar la secuencia de la operación.

Símbolos utilizados

Los símbolos que se utilizan para diseño se someten a una normalización, es decir, se hicieron símbolos casi universales, ya que, en un principio cada usuario podría tener sus propios símbolos para representar sus procesos en forma de Diagrama de flujo. Esto trajo como consecuencia que sólo aquel que conocía sus símbolos, los podía interpretar. La simbología utilizada para la elaboración de diagramas de flujo es variable y debe ajustarse a las normas preestablecidas universalmente para dichos símbolos o datos.

 

Características que debe cumplir un diagrama de flujo

En los diagramas de flujo se presuponen los siguientes aspectos:

  • Existe siempre un camino que permite llegar a una solución (finalización del algoritmo).
  • Existe un único inicio del proceso.
  • Existe un único punto de fin para el proceso de flujo (salvo del rombo que indica una comparación con dos caminos posibles).

Desarrollo del diagrama de flujo

Las siguientes son acciones previas a la realización del diagrama de flujo:

  • Identificar las ideas principales a ser incluidas en el diagrama de flujo. Deben estar presentes el dueño o responsable del proceso, los dueños o responsables del proceso anterior y posterior y de otros procesos interrelacionados, otras partes interesadas.
  • Definir qué se espera obtener del diagrama de flujo.
  • Identificar quién lo empleará y cómo.
  • Establecer el nivel de detalle requerido.
  • Determinar los límites del proceso a describir.

Los pasos a seguir para construir el diagrama de flujo son :

  • Establecer el alcance del proceso a describir. De esta manera quedará fijado el comienzo y el final del diagrama. Frecuentemente el comienzo es la salida del proceso previo y el final la entrada al proceso siguiente.
  • Identificar y listar las principales actividades/subprocesos que están incluidos en el proceso a describir y su orden cronológico.
  • Si el nivel de detalle definido incluye actividades menores, listarlas también.
  • Identificar y listar los puntos de decisión.
  • Construir el diagrama respetando la secuencia cronológica y asignando los correspondientes símbolos.
  • Asignar un título al diagrama y verificar que esté completo y describa con exactitud el proceso elegido.


Diagramas Básicos de Flujo Gramas


http://www.mis-algoritmos.com/images/stories/flowcharting/start-end.jpg

Inicio o fin del programa

http://www.mis-algoritmos.com/images/stories/flowcharting/steps.jpg

Pasos, procesos o líneas de instruccion de programa de computo

http://www.mis-algoritmos.com/images/stories/flowcharting/input-output.jpg

Operaciones de entrada y salida

http://www.mis-algoritmos.com/images/stories/flowcharting/decision.jpg

Toma de desiciónes y Ramificación

http://www.mis-algoritmos.com/images/stories/flowcharting/conector.jpg

Conector para unir el flujo a otra parte del diagrama

http://www.mis-algoritmos.com/images/stories/flowcharting/magnetic.jpg

Cinta magnética

http://www.mis-algoritmos.com/images/stories/flowcharting/magnetic%20disc.jpg

Disco magnético

http://www.mis-algoritmos.com/images/stories/flowcharting/conector-off-page.jpg

Conector de pagina

http://www.mis-algoritmos.com/images/stories/flowcharting/arrows.jpg

Líneas de flujo

http://www.mis-algoritmos.com/images/stories/flowcharting/anotation.jpg

Anotación

http://www.mis-algoritmos.com/images/stories/flowcharting/display.jpg

Display, para mostrar datos

http://www.mis-algoritmos.com/images/stories/flowcharting/Display-print.jpg

Envía datos a la impresora



 

Estructuras de control

En lenguajes de programación, las estructuras de control permiten modificar el flujo de ejecución de las instrucciones de un programa.

Con las estructuras de control se puede:

  • De acuerdo a una condición, ejecutar un grupo u otro de sentencias (If-Then-Else y Select-Case)
  • Ejecutar un grupo de sentencias mientras exista una condición (Do-While)
  • Ejecutar un grupo de sentencias hasta que exista una condición (Do-Until)
  • Ejecutar un grupo de sentencias un número determinado de veces (For-Next)
  • Etc

Todas las estructuras de control tienen un único punto de entrada y un único punto de salida. Las estructuras de control se puede clasificar en : secuenciales, iterativas y de control avanzadas. Esto es una de las cosas que permite que la programación se rija por los principios de la programación estructurada.

Los lenguajes de programación modernos tienen estructuras de control similares. Básicamente lo que varía entre las estructuras de control de los diferentes lenguajes es su sintaxis, cada lenguaje tiene una sintaxis propia para expresar la estructura.

Otros lenguajes ofrecen estructuras diferentes, como por ejemplo los comandos guardados.

Tipos de estructura de control

Antecendentes

El término "estructuras de control", viene del campo de la ciencia computacional. Cuando se presentan implementaciones de Java para las estructuras de control, nos referimos a ellas con la terminología de la Especificación del lenguaje Java, que se refiera a ella como instrucciones.

Ejecución secuencial

Pero por lo general las instrucciones se ejecutan una después de la otra, en el orden en que están escritas, es decir, en secuencia. Este proceso se conoce como ejecución secuencial.

Transferencia de control

En lenguajes de programación por excelencia como C y/o C++, el programador puede especificar que las siguientes instrucciones a ejecutarse tal vez no sea la siguiente en secuencia. Esto se conoce como transferencia de control. Hay que tener en cuenta que la instrucción goto es una palabra reservada pero no se utiliza ni se recomienda. Un programa bien estructurado no necesita de esta instrucción. Si sabes programar no utilizaras goto.

Estructura de control: selección if simple

Se trata de una estructura de control que permite redirigir un curso de acción según la evaluación de una condición simple, sea falsa o verdadera. Por ejemplo: Escribir un programa en Java que compare dos números e indique si cuál es mayor, menor, mayor y/o igual, menor y/o igual, o si son iguales:

  String strComparacion = "";

...

  if( numero1 == numero2 )

     strComparacion += numero1 + " == " + numero2;

  if( numero1 > numero2 )

     strComparacion += numero1 + " > " + numero2;

  if( numero1 < numero2 )

     strComparacion += numero1 + " < " + numero2;

  if( numero1 >= numero2 )

     strComparacion += numero1 + " >= " + numero2;

  if( numero1 <= numero2 )

     strComparacion += numero1 + " <= " + numero2;

  System.out.println(strComparacion);

...

If-Then-Else

La estructura selectiva permite la realización de una instrucción u otra según un criterio, solo una de estas instrucciones se ejecutara.

Ejemplo:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSE

      PRINT a ; "no es mayor que" ; b

   END IF

Esta instrucción selectiva puede presentar dos mensajes, uno a es mayor que b, y el otro a no es mayor que b, solo uno de ellos será presentado, según el resultado de la comparación de a y b, si el resultado de a > b es cierto, se presenta el primer mensaje, si es falso el segundo, las palabras IF, THEN, ELSE, END IF; son propias de la instrucción (palabra reservadas) que tienen un significado en el lenguaje, sirven de separadores, y el usuario no debe utilizarlas salvo para este fin.

  • IF señala el comienzo de la instrucción condicional, y se espera que después esté la condición de control de la instrucción.
  • THEN señala el fin de la condición, y después estará la instrucción a realizar si la condición es cierta.
  • ELSE separa la instrucción que se ejecutará si la condición es cierta de la que se ejecutará si es falsa.
  • END IF indica que la instrucción condicional finaliza y el programa seguirá su curso.

Ampliemos un poco el ejemplo anterior:

   IF a > b THEN

      PRINT a ; "es mayor que" ; b

   ELSEIF a < b THEN

      PRINT a ; "es menor que" ; b

   ELSE

      PRINT a ; "es igual que" ; b

   END IF

Este ejemplo nos permite considerar situaciones en las que tenemos más de dos alternativas. En este caso hemos considerado tres, pero hay situaciones en las que deben considerarse más casos y para ellos se puede repetir las veces que queramos la parte ELSEIF.

 

Si la condición es verdadera, se ejecuta el bloque de sentencias 1, de lo contrario, se ejecuta el bloque de sentencias 2.

   IF (Condición) THEN

      (Bloque de sentencias 1)

   ELSE

      (Bloque de sentencias 2)

   END IF

Select-Case

  • Se evalúa la expresión, dando como resultado un número.
  • Luego, se recorren los "Case" dentro de la estructura buscando que el número coincida con uno de los valores.
  • Es necesario que coincidan todos sus valores.
  • Cuando se encuentra la primera coincidencia, se ejecuta el bloque de sentencias correspondiente y se sale de la estructura Select-Case.
  • Si no se encuentra ninguna coincidencia con ningún valor, se ejecuta el bloque de sentencias de la sección "Case Else".

   SELECT (Expresión)

      CASE Valor1

         (Bloque de sentencias 1)

      CASE Valor2

         (Bloque de sentencias 2)

      CASE Valor n

         (Bloque de sentencias n)

      CASE ELSE

         (Bloque de sentencias "Else")

   END SELECT

Do-While

Mientras la condición sea verdadera, se ejecutarán las sentencias del bloque.

   DO WHILE (Condición)

      (Bloque de sentencias)

   LOOP

que también puede expresarse:

   WHILE (Condición)

      (Bloque de sentencias)

   WEND

Do-Until

Se ejecuta el bloque de sentencias, hasta que la condición sea verdadera

   DO

      (Bloque de sentencias)

   LOOP UNTIL (Condición)

For-Next

  • Primero, se evalúan las expresiones 1 y 2, dando como resultado dos números.
  • La variable del bucle recorrerá los valores desde el número dado por la expresión 1 hasta el número dado por la expresión 2.
  • El bloque de sentencias se ejecutará en cada uno de los valores que tome la variable del bucle.

   FOR (Variable) = (Expresión1) TO (Expresión2) STEP (Salto)

      (Bloque de sentencias)

   NEXT


Estructuras anidadas

Las estructuras de control básicas pueden anidarse, es decir pueden ponerse una dentro de otra.


 

Ejercicios:

Operaciones Aritméticas Básicas (+, -, *, /)

Operaciones de Comparación( <, >, <>, <=, >=, etc.)

Operaciones Aritméticas complejas (Mod, \, ^,)

Operaciones de Relación (And, Or, Not)

Operador lógico

Los operadores lógicos son utilizados por la lógica proposicional para admitir o rechazar proposiciones. En programación de ordenadores se utilizan para combinar valores lógicos (Verdadero/Falso) y obtener nuevos valores lógicos que determinen el flujo de control de un algoritmo o programa.

Tablas de Verdad

El comportamiento de un operador lógico suele definirse mediante su correspondiente tabla de verdad, en ella se muestra el resultado que produce la aplicación de un determinado operador a uno o dos valores lógicos. Las operaciones lógicas más usuales son:


  • NO lógico (NOT) o negación:

Operador unario (aplicado a un único operando). Cambia el valor de verdad de verdadero (V) a falso (F) y viceversa.

p

NOT p

V

F

F

V

 

 

 

 

 

  • O lógica (OR) o disyunción:

Operador n-ario (aplicado a 2 o más operandos). Si todos los operandos son F devuelve F; si hay alguno que sea V devuelve V.

p

q

p OR q

V

V

V

V

F

V

F

V

V

F

F

F

 

 

 

 

  • Y lógica (AND) o conjunción:

Operador n-ario . Si todos los operandos son V devuelve V; si hay alguno que sea F devuelve F.

p

q

p AND q

V

V

V

V

F

F

F

V

F

F

F

F

 

 

  • O-eXclusiva lógica (XOR):

Operador binario (aplicado a dos operandos). Devuelve V cuando ambos operandos son distintos y F cuando son iguales.

p

q

p XOR q

V

V

F

V

F

V

F

V

V

F

F

F

 


Los 16 operadores lógicos binarios pueden ser definidos a través de la siguiente Tabla de Verdad :

p

q

T

~p

~q

\leftrightarrow

\vee

\not\leftrightarrow

q

\not\leftarrow

p

\not\rightarrow

\wedge

F

T

T

T

F

T

F

T

F

T

F

T

F

T

F

T

F

T

F

T

F

T

T

F

F

T

T

F

F

T

T

F

F

T

T

F

F

F

T

T

T

T

T

F

F

F

F

T

T

T

T

F

F

F

F

F

F

T

T

T

T

T

T

T

T

F

F

F

F

F

F

F

F


Donde:

  • T : tautología
  • ↑ : negación alternativa, incompatibilidad, no ambos, exclusión, "NAND"
  • → : condicional, implicación (simple), "IMP"
  • ~ : negación, "NOT"
  • ← : implicación inversa
  • \leftrightarrow : bicondicional, implicación doble, equivalencia, "EQV", "XNOR"
  • ↓ : negación conjunta, "NOR"
  • \vee: disyunción, "Ó", "OR"
  • \not\leftrightarrow : disyunción exclusiva, contravalencia, "XOR"
  • \not\leftarrow : negación del condicional inverso
  • \not\rightarrow : negación del condicional
  • \wedge : conjunción, "Y", "AND"
  • F : contradicción

 

 

Č
ċ
Dfd.rar
(363k)
Hugo Omar Martinez,
6/1/2010 9:17
Ċ
Hugo Omar Martinez,
6/1/2010 6:56
ċ
manualdfd.pdf
(1283k)
Hugo Omar Martinez,
9/2/2010 8:33
Comments