UNIDAD IV: LENGUAJE DE DISEÑO DE ALGORITMOS ESTRUCTURAS DE CONTROL ASIGNATURA: INTRODUCCIÓN A LA COMPUTACIÓN CARRERAS: LICENCIATURA Y PROFESORADO EN CIENCIAS DE LA COMPUTACIÓN DEPARTAMENTO DE INFORMÁTICA FACULTAD DE CIENCIAS FÍSICO MATEMÁTICA Y NATURALES UNSL 1 4.1. Definición de variables El Lenguaje de Diseño de Algoritmos (LDA) cuenta con dos tipos de objetos: constantes y variables. En el caso de las variables debemos tener en cuenta que las mismas tienen como atributos, un nombre que las identifica y el tipo que indica un conjunto de posibles valores que puede almacenar. De lo anterior, surge la siguiente pregunta: ¿Cómo sabe el procesador cuáles son y de qué tipo son las variables que el algoritmo utilizará para resolver el problema? Es decir, se necesita especificar, por cada variable, el respectivo nombre y tipo. El tipo es necesario para poder reservar un lugar de memoria (una casilla) que contenga adecuadamente los posibles valores. El nombre es necesario para que puedan ser referenciadas (encontradas) cuando se las necesite (por ejemplo, en una asignación) en cualquier acción primitiva en la que pueda aparecer una variable. En respuesta a la pregunta anterior, el LDA provee una regla de escritura para indicarle al procesador nombre y tipo de las variables que se usarán en el algoritmo. Proceso <nombre> Definir <var1>, <var2>, ... ,<varN> Como (Real|Entero|Logico|Caracter); ------FinProceso Se puede observar que se comienza el algoritmo con la palabra Proceso seguido del nombre del algoritmo <nombre>. En la línea siguiente se comienzan a definir las variables que se utilizarán a lo largo del algoritmo. Se utiliza la palabra reservada Definir seguido del nombre o nombres (separados por comas) de las variables de uno de los siguientes tipos (Real|Entero|Logico|Caracter) que se encuentra a la derecha de la palabra Como. Se finaliza cada definición con el símbolo ;. Si se desean definir variables de varios tipos, se utilizarán varias líneas de la forma “Definir <var1>, <var2>, ... ,<varN> Como (Real|Entero|Logico|Carácter);”, al menos, una línea por cada tipo de variable definida. Veamos algunos ejemplos. Ejemplo 1: Proceso Primera_definición Definir edad Como Entero; Definir altura, peso Como Real; Definir sexo Como Caracter; edad <- 25; altura <- 1.68; sexo <- “F”; FinProceso En el Ejemplo 1, se puede ver la regla utilizada para definir variables: después de la palabra reservada Definir va el nombre de la variable y después de la palabra reservada Como se coloca el tipo. Se definieron una variable de tipo entero (edad), dos variables de tipo real (altura y peso) y una variable de tipo caracter (sexo). Estas variables forman el ambiente del algoritmo, el cual se expresa de la siguiente manera: 2 Objeto Tipo Descripción edad Variable de tipo entero. Contiene una edad. altura Variable de tipo real. Contiene una altura. peso Variable de tipo real. Contiene un peso. sexo Variable de tipo caracter. Contiene un sexo. Si se utilizaran constantes significativas se deben agregar al ambiente. Los identificadores, o nombres de variables, deben constar sólo de letras y números, comenzando siempre con una letra y no pueden ser palabras reservadas. Más abajo, en el algoritmo del ejemplo, después de las declaraciones, sólo se realizan tres asignaciones, una a cada variable declarada. Si bien el algoritmo no resuelve ningún problema específico, nos permite visualizar cómo se realizan las declaraciones. Supongamos ahora que el algoritmo del Ejemplo 1 es cambiado por: Ejemplo 2: Proceso Segunda_definición Definir altura, peso Como Real; Definir sexo Como Caracter; edad <- 25; altura <- 1.68; sexo <- “F”; FinProceso ¿Qué problemas podemos detectar aquí? En otras palabras, ¿será capaz el procesador de entender y ejecutar este algoritmo? Claramente, la respuesta es NO porque la variable edad es desconocida para el procesador y por lo tanto, no tiene casilla asignada en el ambiente para almacenar un valor de ningún tipo. Consideremos ahora un ejemplo un tanto más práctico, en el sentido que pretendemos que el procesador realice una tarea que resuelva un problema particular. Supongamos que se quiere diseñar un algoritmo para calcular las raíces de una ecuación cuadrática donde los coeficientes de dicha ecuación son a=2.0; b=3.0; y c=1.0. Recordemos que la fórmula para calcular dichas raíces es: − b ± b 2 − 4ac 2a El algoritmo para calcular las dos raíces, dados los valores de a, b y c, se da a continuación: Ejemplo 3: Proceso Raíces Definir a, b, c Como Real; Definir res1, res2 Como Real; a <- 2.0; 3 b <- 3.0; c <- 1.0; res1 <- ( -1 * b + RC(b^2 - 4*a*c))/(2*a); res2 <- ( -1 * b - RC(b^2 – 4*a*c))/(2* a); FinProceso Antes de analizar el algoritmo Raíces en detalle es importante observar que las variables a, b y c fueron declaradas en una sola línea, lo único que se necesitó fue un separador (la coma “,”) para poder diferenciar un nombre de otro. De igual manera se hizo con las variables res1 y res2 ya que son del mismo tipo. Ahora, el algoritmo Raíces parece calcular como corresponde las dos raíces de la ecuación dados los valores de a, b y c. Sin embargo, ¿nos servirá de algo el algoritmo tal cual está diseñado? La respuesta es NO y la razón es la siguiente: el algoritmo procesa un conjunto de datos, pero el resultado o resultados que el usuario espera recibir no son comunicados de ninguna manera. Esto es, el algoritmo no da un respuesta explícita para que el usuario pueda visualizar el resultado (en este caso, el usuario necesitaría saber cuáles son los valores de las variables res1 y res2). En síntesis, el problema detectado aquí es que no existen, hasta el momento, acciones que permitan realizar una interacción del usuario con el algoritmo al momento de la ejecución. Por interacción, queremos significar la posibilidad de ingresar datos a pedido (ENTRADA) o visualizar datos resultantes de los cálculos (SALIDA). Éstas, son dos acciones básicas de gran importancia para la comunicación de datos y serán explicadas en la siguiente sección. 4.2. Entrada-Salida de datos 4.2.1. Entrada de datos Un valor que no pertenece al ambiente del algoritmo puede introducirse al mismo, mediante una acción, que llamaremos lectura. Lectura, es toda acción que permite la entrada de uno o más valores al ambiente del algoritmo a través de un dispositivo. Una lectura es una asignación, en el sentido que toma valores del medio externo y lo asigna a las variables del ambiente. La lectura es una acción primitiva. En el LDA la lectura se nota de la siguiente manera: Leer <variable1>, <variable2>, ...,<variableN>; Esta acción lee N valores desde el mundo exterior, por ejemplo, desde el teclado y los asigna a las N variables mencionadas, en el orden en que aparecen en la primitiva. 4.2.2. Salida de datos Un valor puede comunicarse al mundo exterior, por ejemplo, a través de un dispositivo de salida. Llamaremos escritura a la acción primitiva que permite la salida de valores a través de un dispositivo. Esta acción toma uno o más valores y lo comunica al medio externo. En el LDA la notaremos de la siguiente manera: Escribir <expr1>, <expr2>, ..., <exprN>; Además permite mostrar carteles informativos al usuario (encerrados entre comillas dobles) los cuales pueden intercalarse con las expresiones (separados por comas). Por ejemplo: 4 Escribir “cartel informativo”, <expr1>; Esta acción primitiva transmite valores del ambiente del algoritmo al mundo externo al mismo, por ejemplo a la pantalla, es decir, muestra los valores obtenidos de evaluar las N expresiones. Dado que puede incluir una o más expresiones, puede mostrar uno o más valores. A los efectos de aumentar la legibilidad de un algoritmo antes del uso de una primitiva de lectura suele usarse una de escritura en la cual se aclara lo que está esperando el algoritmo que ingrese el usuario. Ejemplo: si un algoritmo espera que un usuario ingrese un número entero, esto se expresa: Escribir “Ingrese un número entero”; Leer Num; El mensaje que aparece en la pantalla es: Ingrese un número entero y el procesador queda esperando que por el teclado se entre un número entero el cual se almacenará en la variable Num. Análogamente cuando el algoritmo va a mostrar algún resultado, por ejemplo la cantidad promedio de milímetros de agua de lluvias caída en un determinado mes, el diseñador del algoritmo escribirá: Escribir “El promedio de milímetros de agua de lluvias del mes de Enero fue: ”, prom; Suponiendo que la variable prom tiene almacenado el valor 150, el resultado de la ejecución de esta acción primitiva mostrará en la pantalla: El promedio de milímetros de lluvias del mes de Enero fue: 150 Es importante destacar que, en el ambiente, cuando resulte conveniente, pueden nombrarse también los Datos Auxiliares. Aunque no son los requeridos por el problema, sirven como etapa intermedia entre los Datos de Entrada y los Resultados o Datos de Salida. Ejemplo 4: Proceso Raíces Definir a, b, c como Real; Definir res1, res2 como Real; Escribir “Ingrese coeficiente (a)”; Leer a; Escribir “Ingrese coeficiente (b)”; Leer b; Escribir “Ingrese coeficiente (c)”; Leer c; res1 <- ( -1 * b + RC( b ^ 2 – 4 *a *c )) / (2 * a); res2 <- ( -1 * b - RC( b ^ 2 – 4 * a * c)) / (2 * a); Escribir “Las raíces calculadas son: ”, res1, res2; FinProceso Con esta nueva versión del algoritmo Raíces podemos, por un lado, resolver una cuestión muy importante: visualizar el resultado incluyendo un mensaje “Las raíces calculadas son:” para una mejor comprensión de la SALIDA del algoritmo. Por otro lado, a través de la acción primitiva de ENTRADA, hemos incluido en el algoritmo la posibilidad de que realicen los cálculos de las raíces para más de un conjunto de datos. Recordemos que en el Ejemplo 3, el cálculo se hacía para a=2.0, 5 b=3.0 y c=1.0. En esta versión lo podemos hacer para los números anteriores y para cualquier otro conjunto de números ingresados por el usuario al momento de ejecutarse las acciones Leer. 4.3 Estructuras de control Estructurar el control de un conjunto de acciones detalladas en un algoritmo es brindar mecanismos que permitan indicar el orden en que las mismas van a ser llevadas a cabo. Una de las mayores potencias de un procesador proviene de su capacidad de tomar decisiones y de determinar qué acción realizar al momento de ejecutar un algoritmo sobre la base de los valores de algunos de los datos que se leen, o bien, de los resultados de los cálculos que se realizan. Vamos a explicar tres conceptos muy importantes relacionados con estructuras de control: • Secuencial • Condicional • Repetición Estas acciones no modifican el ambiente sino el orden en que el procesador ejecuta las acciones primitivas. 4.3.1 Estructura de Control Secuencial Cuando no se indique lo contrario, el flujo de control de ejecución de un algoritmo seguirá la secuencia implícita del mismo. Entendemos por secuencia implícita que las acciones se ejecutan en el orden en que son escritas en el algoritmo, es decir, desde la primera hacia la última ("desde arriba hacia abajo y de izquierda a derecha"). Al terminar de ejecutarse una acción se pasa a la inmediata siguiente que está perfectamente determinada y, así siguiendo, hasta alcanzar la última acción del algoritmo. Por ejemplo, las siguientes acciones primitivas representan una secuencia: I <- 1; Leer numero; f <- numero + I; Lo mismo podría visualizarse gráficamente a través de lo que se conoce como un Diagrama de Flujo1 que sirve para visualizar todos los posibles órdenes de ejecución de un algoritmo. En él las acciones primitivas que modifican el ambiente se escriben dentro de rectángulos. El ejemplo anterior quedaría expresado con el siguiente diagrama: I <- 1; Leer numero; f <- numero + I; 1 Los diagramas de flujo son una herramienta que permite representar visualmente qué operaciones se requieren y en qué secuencia se deben efectuar para solucionar un problema dado. Es la representación gráfica, mediante símbolos especiales, de los pasos o procedimientos de manera secuencial y lógica que se deben realizar para solucionar un problema dado. Facilitan la comprensión de problemas complicados y sobre todo aquellos en que sus procesos son muy largos. 6 4.3.2 Estructura de Control Condicional Un algoritmo permite resolver problemas de una misma clase. Sin embargo, en la mayoría de las clases de problemas, no es posible hallar un conjunto de acciones secuenciales que permitan resolver el problema. Recordemos que algunas acciones pueden tener que llevarse a cabo sólo para algunas instancias o, lo que es lo mismo, sólo si ciertas condiciones se satisfacen. Cuanto más general intente ser nuestro algoritmo es posible que deba considerar más alternativas. Los algoritmos, en determinados momentos, requieren ser selectivos en lo que respecta a las acciones que deben seguir, basándose en una respuesta de un determinado cuestionamiento que se formuló para la solución del problema planteado. En esta asignatura veremos dos tipos de estructura de control condicional: Condicional Simple y Condicional Múltiple. 4.3.2.1 Condicional Simple Nuestro LDA debe proveer algún mecanismo para expresar que un conjunto de acciones debe ejecutarse sólo bajo ciertas condiciones. El condicional permitirá que una o un conjunto de acciones primitivas se ejecuten sólo si cierta condición se cumple. Por ejemplo: Si n > 0 entonces decrementar n en 1 quiere decir que sólo restaremos 1 a n si n es un número positivo (n > 0). Las condiciones prevén las distintas situaciones que pueden presentarse en la resolución del problema. El condicional permite que la ejecución de cierto conjunto de acciones quede sometida a una condición. Supongamos que X e Y son dos variables enteras, cada una un valor entero previamente asignado. El problema planteado es mostrar por pantalla el mayor valor. Esto es, si X > Y debe escribirse el valor de X; en caso contrario, el valor de Y. En este caso, es evidente que existen secuencias de acciones alternativas: “escribir el valor de X” o “escribir el valor de Y”. La elección acerca de cuál de los dos valores escribir depende de si el valor de X es o no mayor que el valor de Y. El diagrama de flujo asociado con esta acción condicional es: F X>Y Escribir Y; V Escribir X; donde X > Y es una condición que se debe evaluar. El resultado de esta acción completa es que el mayor de los dos valores de las variables X o Y, es el que se escribirá. Por ejemplo, supongamos que X tiene el valor 8 e Y el valor 3. Como 8 es mayor que 3, la condición X > Y es Verdadera y, por lo tanto se escribirá el valor 8 como resultado de la acción primitiva Escribir X;. 7 En este ejemplo sencillo hemos analizado la estructura de control condicional. El formato algorítmico de dicha estructura y su correspondiente diagrama de flujo es: Si <condición> Entonces F <alternativa verdadera>; <condición> V Sino <alternativa falsa>; <alternativa verdadera>; <alternativa falsa>; FinSi El inicio de la estructura comienza con la palabra reservada Si y el final con la palabra reservada FinSi. Ahora podemos reescribir el ejemplo anterior de la siguiente manera: Si X > Y Entonces Escribir X; Sino Escribir Y; FinSi Tanto la condición como cada una de las alternativas de la estructura pueden ser más complejas, por ejemplo, la alternativa verdadera y la alternativa falsa pueden consistir de una secuencia de acciones primitivas en lugar de una única acción (como en el ejemplo dado). La condición, a su vez, puede consistir de una condición compuesta. La estructura condicional se considera como un ente completo, es decir, al que se ingresa en el punto en el cual la condición se evalúa. Una vez evaluada la condición se toma por una de las alternativas y, luego, el control pasa a la acción primitiva que sigue al delimitador FinSi (si dicha acción existe). Otro ejemplo: Enunciado: Calcular la raíz cuadrada de un número, si éste no es negativo; en caso contrario no realizar cálculo alguno. Ambiente del algoritmo: Objeto a Tipo Descripción Variable de entrada-salida de Como variable de entrada contendrá tipo entero. el número del cual se quiere calcular la raíz cuadrada; como variable de salida, contendrá la raíz cuadrada. Algoritmo: Versión 1: t1. Definir las variables a ser utilizadas por el algoritmo. 8 t2. Leer el número del cual se desea calcular la raíz cuadrada, guardándolo en la variable a. t3. Si su valor es positivo o cero entonces t3.1. Calcular la raíz cuadrada usando la función primitiva RC( ) t3.2. Guardar el valor de la raíz en la variable a t3.3. Escribir en pantalla el valor de la raíz sino hacer nada. Versión 2: (final) Proceso raíz_cuadrada // t1. Definir a Como Entero; // t2. Escribir “Ingrese el valor”; Leer a; // t3. Si a >= 0 Entonces // t3.1. y t3.2. a <- RC(a); // t3.3. Escribir “La raíz cuadrada es: ”, a; FinSi FinProceso En el algoritmo anterior las frases u oraciones escritas después de // representan comentarios y sirven para documentar un algoritmo. Además el algoritmo anterior es, a la vez, un ejemplo donde un dato de entrada puede también ser utilizado como dato de salida. Puede suceder que, si la condición es falsa, no existan acciones a ejecutar (como en el ejemplo anterior). En estos casos, en la construcción algorítmica no aparece el delimitador Sino y el formato de la construcción condicional y su correspondiente diagrama de flujo es: Si <condición> Entonces <alternativa verdadera>; F <condición> V FinSi <alternativa verdadera>; 9 Anidamiento de estructuras de control condicional Hasta ahora, los algoritmos vistos sólo presentan una decisión para realizar un determinado proceso; sin embargo, en algunas ocasiones es necesario elaborar estructuras condicionales en cascada o anidadas. Esto significa que después de haber realizado una comparación selectiva es necesario realizar otra comparación selectiva como resultado de la primera condición. Analicemos el siguiente esquema, donde: p y q son condiciones y a, b, c y d, son acciones. Si p Entonces a; Sino b; Si q Entonces c; Sino d; FinSi FinSi Veamos el resultado de todas las posibles ejecuciones de este algoritmo: Predicados Acciones a p q Ejecutar VERDADERO VERDADERO a VERDADERO FALSO a FALSO VERDADERO b, c FALSO FALSO b, d Estas instrucciones se pueden visualizar gráficamente a través de un diagrama de flujo: F p a b F d q V V c 10 A continuación se ejemplifica el uso de la estructura de control condicional anidada. Enunciado: Los operarios de una empresa trabajan en tres turnos: uno matutino, cuyo código es 1, otro vespertino cuyo código es 2 y el otro nocturno cuyo código es 3. Se desea calcular el jornal para un operario sabiendo que, para el turno nocturno, el pago es de $5 la hora y para el turno vespertino es de $3 la hora y para el matutino es de $2 la hora. En este último caso, si el día es domingo se paga un adicional de $1 por hora. Primero deberíamos analizar las diferentes fórmulas para calcular el jornal: • Fórmula 1 (para el turno nocturno): jornal = 5 * horas trabajadas • Fórmula 2 (para el turno vespertino): jornal = 3 * horas trabajadas • Fórmula 3a (turno diurno, no es domingo): jornal = 2 * horas trabajadas • Fórmula 3b (turno diurno, domingo): jornal = (2 + 1) * horas trabajadas. Ambiente del algoritmo: Objeto Tipo Descripción horas Variable de entrada, numérico (entero). de tipo Almacena la cantidad de horas trabajadas en un día, por un operario. turno Variable de entrada, numérico (entero). de tipo Almacena el código del turno. Variable caracter. entrada, de tipo Almacena si el día es domingo. Si su valor es “d”, indica que es día domingo, sino tiene el valor “n” Variable de salida, numérico (entero). de tipo Almacena el valor de la paga que debe efectuarse por jornal. dia jornal de Algoritmo: Versión 1: t1. Definir las variables a ser utilizadas por el algoritmo. t2. Leer datos de entrada. t3. Calcular el jornal. t4. Informar resultados. Como las acciones de este algoritmo no son primitivas, aplicaremos la técnica de Refinamientos Sucesivos. Versión 2: t1. Definir las variables a ser utilizadas por el algoritmo. t2.1. Leer las horas trabajadas. t2.2. Leer el código del turno. t2.3. Leer el código del día. t3. Si el turno es nocturno entonces 11 t3.1. Calcular el jornal usando la fórmula 1 sino si el turno es vespertino entonces t3.2. Calcular el jornal usando la fórmula 2 sino t3.3. Calcular el jornal usando la fórmula 3 finsi finsi t4. Escribir el valor del jornal Como la acción calcular el jornal usando la fórmula 3 no refleja todavía las restricciones del problema debemos realizar un nuevo refinamiento: Versión 3: t1. Definir las variables a ser utilizadas por el algoritmo. t2.1. Leer las horas trabajadas. t2.2. Leer el código del turno. t2.3. Leer el código del día. t3. Si el turno es nocturno entonces t3.1. Calcular el jornal usando la fórmula 1 sino si el turno es vespertino entonces t3.2. Calcular el jornal usando la fórmula 2 sino si el día no es domingo entonces t3.3.1. Calcular el jornal usando la fórmula 3a sino t3.3.2. Calcular el jornal usando la fórmula 3b finsi finsi finsi t4. Escribir el valor del jornal Versión 4 (final): Proceso Jornales //t1. Definir horas, turno, jornal Como Entero; 12 Definir dia Como Caracter; //t2.1. Escribir “Ingrese las horas trabajadas: ”; Leer horas; //t2.2. Escribir “Ingrese el código del turno: ”; Leer turno; //t2.3. Escribir “Ingrese el código del día: ”; Leer dia; Si turno = 3 Entonces //t3.1. jornal <- 5 * horas ; Sino Si turno = 2 Entonces //t3.2. jornal <- 3 * horas; Sino Si dia <> “d” Entonces //t3.3.1. jornal <- 2 * horas; Sino //t3.3.2. jornal <- (2 + 1) * horas; Finsi FinSi FinSi //t4. Escribir “El jornal del operario es: “, jornal; FinProceso Para ejecutar un algoritmo vamos a utilizar una tabla de ejecución. Dicha tabla contendrá tantas columnas como variables se hayan definido, más una columna que se utiliza para mostrar lo que aparecerá en la pantalla. Al definir las variables, el valor inicial que poseen las variables es indeterminado y se representa con el siguiente símbolo “⊥”. Supongamos que queremos ejecutar cuatro veces el algoritmo Jornales con los siguientes datos de entrada (estos valores se almacenarán en las variables al ejecutarse las instrucciones de lectura): Ejecución 1 Ejecución 2 Ejecución 3 Ejecución 4 horas: 8 horas: 12 horas: 10 horas: 7 turno: 1 turno: 2 turno: 3 turno: 1 dia: “n” dia: “n” dia: “n” dia: “d” 13 Sólo en los ejemplos presentados en esta unidad se mostrará en la primera columna qué instrucción se va ejecutando en cada paso de la ejecución. Ejecución 1: Instrucción Definir horas, turno, jornal Como Entero; horas turno ⊥ ⊥ dia jornal Pantalla ⊥ ⊥ Definir dia Como Caracter; Ingrese las horas trabajadas: 8 Escribir “Ingrese las horas trabajadas: ”; 8 Leer horas; Ingrese el código del turno: 1 Escribir “Ingrese el código del turno: ”; 1 Leer turno; Ingrese el código del día: n Escribir “Ingrese el código del día: ”; “n” Leer dia; ¿turno = 3? -> NO ¿turno = 2? -> NO ¿dia <> “d”? -> SI 16 jornal <- 2 * horas; El jornal del operario es: 16 Escribir “El jornal del operario es: “, jornal; Ejecución 2: Instrucción Definir horas, turno, jornal Como Entero; horas turno ⊥ ⊥ dia jornal Pantalla ⊥ ⊥ Definir dia Como Caracter; Ingrese las horas trabajadas: 12 Escribir “Ingrese las horas trabajadas: ”; 12 Leer horas; Ingrese el código del turno: 2 Escribir “Ingrese el código del turno: ”; 2 Leer turno; Ingrese el código del día: n Escribir “Ingrese el código del día: ”; “n” Leer dia; ¿turno = 3? -> NO ¿turno = 2? -> SI 36 jornal <- 3 * horas; El jornal del operario es: 36 Escribir “El jornal del operario es: “, jornal; Ejecución 3: Instrucción Definir horas, turno, jornal Como Entero; horas turno ⊥ ⊥ jornal Pantalla ⊥ ⊥ Definir dia Como Caracter; Ingrese las horas trabajadas: 10 Escribir “Ingrese las horas trabajadas: ”; Leer horas; dia 10 14 Ingrese el código del turno: 3 Escribir “Ingrese el código del turno: ”; 3 Leer turno; Ingrese el código del día: n Escribir “Ingrese el código del día: ”; “n” Leer dia; ¿turno = 3? -> SI 50 jornal <- 5 * horas; El jornal del operario es: 50 Escribir “El jornal del operario es: “, jornal; Ejecución 4: Instrucción Definir horas, turno, jornal Como Entero; horas turno ⊥ ⊥ dia jornal Pantalla ⊥ ⊥ Definir dia Como Caracter; Ingrese las horas trabajadas: 7 Escribir “Ingrese las horas trabajadas: ”; 7 Leer horas; Ingrese el código del turno: 1 Escribir “Ingrese el código del turno: ”; 1 Leer turno; Ingrese el código del día: d Escribir “Ingrese el código del día: ”; “d” Leer dia; ¿turno = 3? -> NO ¿turno = 2? -> NO ¿dia <> “d”? -> NO 21 jornal <- (2 + 1) * horas; El jornal del operario es: 21 4.3.2.2 Condicional Múltiple Con frecuencia existen más de dos alternativas posibles, por ejemplo, en una ecuación de segundo grado el discriminante puede ser negativo, nulo o positivo. Este problema se puede resolver utilizando estructuras alternativas simples o dobles anidadas o en cascada, pero este tipo de solución añade complejidad al algoritmo y hace difícil la lectura del algoritmo. La estructura condicional múltiple ofrece una solución más simple y compacta. Para esta estructura se consulta el valor almacenado en una variable que puede tomar n valores enteros distintos (1, 2, 3,..., n). A cada valor corresponde una acción (o conjunto de acciones) diferente, lo que significa que el flujo de ejecución seguirá un camino distinto entre los n posibles caminos dependiendo del valor de la variable de control. En el LDA la estructura condicional múltiple se escribe: Segun <variable> Hacer <número1>: <acciones1> <número2>, <número3>: <acciones2> <...> <númeron>: <accionesn> De Otro Modo: <accionesO> FinSegun 15 El diagrama de flujo correspondiente es el siguiente: valor <variable>? <número2>, <número1>: <número3>: <acciones1> <acciones2> <númeron>: ... De Otro Modo: <accionesn> <accionesO> Cada opción está formada por uno o más números separados por comas, dos puntos y una secuencia de acciones. Si una opción incluye varios números, la secuencia de instrucciones asociada se debe ejecutar cuando el valor de la variable es igual a uno de esos números. Opcionalmente, se puede agregar una opción final (De Otro Modo), cuya secuencia de instrucciones asociada se ejecutará sólo si el valor almacenado en la variable no coincide con ninguna de las opciones anteriores. Si analizamos el algoritmo anterior (Jornales) podemos observar que el cálculo del jornal depende del turno que puede tomar los valores 1, 2 ó 3. Por lo tanto, estamos ante un problema que puede resolverse usando una selección múltiple y podemos reescribir dicho algoritmo de la siguiente manera: Proceso Jornales Definir horas, turno, jornal Como Entero; Definir dia Como Caracter; Segun turno Hacer 1: Si dia <> “d” Entonces jornal <- 2 * horas; Sino jornal <- (2 + 1) * horas; FinSi 2: jornal <- 3 * horas; 3: jornal <- 5 * horas; De Otro Modo: Escribir “Ingresó un turno inválido”; jornal <- 0; FinSegun Escribir jornal; FinProceso Si analizamos los dos algoritmos vemos que el último es más compacto y claro. En este caso se usó la opción De Otro Modo para avisarle al usuario que ingresó un valor de turno inválido. ¿Por qué fue 16 necesario asignar un valor cero a la variable jornal? Porque si el usuario hubiese ingresado un valor inválido para turno no se le hubiere asignado ningún valor a dicha variable, es decir, jornal tendría un valor indefinido y al querer imprimir su valor el procesador se detendría y daría un error. Ejemplo: Enunciado: Un banco ha decidido aumentar el límite de crédito de las tarjetas de crédito de sus clientes. Para esto considera que si su cliente tiene tarjeta tipo 1, el aumento será de 25%; si tiene tipo 2, será de 35%; si tiene tipo 3, de 40% y para cualquier otro tipo, de 50%. Se solicita diseñar un algoritmo en LDA y representar su diagrama de flujo para determinar el nuevo límite de crédito que tendrá una persona en su tarjeta. Ambiente del algoritmo: Objeto Tipo Descripción TT Variable de entrada, de tipo entero Almacena el tipo de tarjeta. LA Variable de entrada, de tipo real Almacena el límite actual de crédito. AC Variable de auxiliar, de tipo real Almacena el aumento de crédito. NL Variable de salida, de tipo real Almacena el nuevo límite de crédito. Notar que las variables que se utilicen dentro del algoritmo para realizar cálculos y que no sean de entrada y/o de salida son consideradas variables auxiliares. En el ambiente anterior, AC es una variable auxiliar que se utiliza para almacenar el aumento de crédito. La solución de este problema se puede plantear con un condicional múltiple, dado que el elemento selector, que es el tipo de tarjeta (TT), es de tipo entero. Algoritmo: Versión 1: t1. Definir las variables a ser utilizadas por el algoritmo. t2. Leer datos de entrada. t3. Calcular el aumento de límite de crédito. t4. Mostrar el nuevo límite. Versión 2: t1. Definir las variables a ser utilizadas por el algoritmo. t2.1. Leer el tipo de tarjeta (TT). t2.2. Leer el límite actual de crédito (LA). t3. Según el tipo de tarjeta ingresado: t3.1. TT = 1, calcular aumento del 25% t3.2. TT = 2, calcular aumento del 35% t3.3. TT = 3, calcular aumento del 40% 17 t3.4. En otro caso, calcular aumento del 50% t4.1. Calcular el nuevo límite. t4.2. Mostrar por pantalla el nuevo límite. Versión 3 (final): Proceso Aumento_Tarjeta //t1. Definir TT Como Entero; Definir LA, AC, NC Como Real; //t2.1. Escribir “Ingrese el tipo de tarjeta: ”; Leer TT; //t2.2. Escribir “Ingrese el límite actual de crédito: ”; Leer LA; Segun TT Hacer //t3.1. 1: AC <- LA * 0.25; //t3.2. 2: AC <- LA * 0.35; //t3.3. 3: AC <- LA * 0.40; //t3.4. De Otro Modo: AC <- LA * 0.50; FinSegun //t4.1. NL <- LA + AC; //t4.2. Escribir “El nuevo límite de crédito es: “, NL; FinProceso Supongamos que queremos ejecutar cuatro veces el algoritmo Jornales con los siguientes datos de entrada (estos valores se almacenarán en las variables al ejecutarse las instrucciones de lectura): Ejecución 1 Ejecución 2 TT: 2 TT: 5 LA: 1000 LA: 2000 Ejecución 1: Instrucción Definir TT Como Entero; TT LA AC NC Pantalla ⊥ 18 ⊥ Definir LA, AC, NC Como Real; ⊥ ⊥ Ingrese tipo de tarjeta: 2 Escribir “Ingrese el tipo de tarjeta: ”; 2 Leer TT; Ingrese el límite actual de crédito: 1000 Escribir “Ingrese el límite actual de crédito: ”; 1000 Leer LA; ¿TT = 1? -> NO ¿TT = 2? -> SI 350 AC <- LA * 0.35; 1350 NL <- LA + AC; Escribir “El nuevo límite de crédito es: “, El nuevo límite de crédito es: 1350 NL; Ejecución 2: Instrucción Definir TT Como Entero; TT LA AC NC ⊥ ⊥ ⊥ ⊥ Definir LA, AC, NC Como Real; Ingrese tipo de tarjeta: 5 Escribir “Ingrese el tipo de tarjeta: ”; Leer TT; 5 Ingrese el límite actual de crédito: 2000 Escribir “Ingrese el límite actual de crédito: ”; Leer LA; Pantalla 2000 ¿TT = 1? -> NO ¿TT = 2? -> NO ¿TT = 3? -> NO AC <- LA * 0.50; NL <- LA + AC; Escribir “El nuevo límite de crédito es: “, 1000 3000 El nuevo límite de crédito es: 2000 NL; 19 Hasta el momento, las soluciones planteadas a los problemas propuestos han sido para una persona, un objeto o cosa, pero siempre de manera unitaria. Sin embargo, debemos considerar que cuando se plantean problemas como calcular un sueldo cabe la posibilidad de que el cálculo se tenga que hacer para dos o más empleados. Si bien es un proceso de cálculo que por lógica debe ser el mismo para cada uno, puede existir la posibilidad de que los datos que determinan ese sueldo sean los que cambien. También se puede considerar el problema de calcular el monto de una llamada realizada por una persona, pero también se pueden considerar N llamadas efectuadas por la misma persona, donde lo que puede cambiar es el tiempo, o la tarifa, lo cual puede depender de alguna condición. De igual forma se pueden presentar muchos casos donde el proceso se debe repetir varias veces. Por tal motivo se emplean estructuras denominadas repetitivas, de ciclo o de bucle, e independientemente del nombre que se les aplique, lo que importa es que permiten que un proceso pueda realizarse N veces, donde sólo cambien los datos que se utilizan en el proceso. 4.3.3 Estructura de Control de Repetición Las estructuras de repetición permiten la ejecución de una lista o secuencia de acciones o instrucciones en forma iterativa o repetitiva. El número de veces que la secuencia de acciones se ejecutará se puede especificar de manera explícita o a través de una condición lógica. A cada ejecución de la secuencia de acciones se le conoce como una iteración. Existen tres tipos principales de estructuras de repetición: la estructura Mientras-Hacer, la estructura y la estructura Para-Hasta. Repetir-Hasta Que El objetivo de esta teoría es presentar las diferentes estructuras de repetición, analizar las diferencias entre ellas y reconocer la conveniencia de uso de cada una de ellas. 4.3.3.1 Estructura de repetición Mientras-Hacer El formato de esta estructura de control en el LDA es: Mientras <condición> Hacer <acciones>; FinMientras En esta estructura de control la palabra FinMientras es un delimitador que se utiliza para indicar el fin de la secuencia de acciones a repetir. La cantidad de veces que se ejecutará las <acciones> o el cuerpo de la repetición es 0, 1, 2, ..., n. Dicha cantidad no es conocida de antemano sino que depende del valor de verdad de la <condición>. La <condición> es evaluada antes de la ejecución de la secuencia <acciones>. Si el resultado es verdadero, <acciones> se ejecuta y luego, se vuelve a evaluar la <condición>; si dicha condición resulta falsa, finaliza la repetición, es decir, se ejecutará la primera acción primitiva que siga a FinMientras (si ésta existe). En el caso en que la condición evalúe la primera vez como falsa, la secuencia de acciones no será ejecutada, lo cual quiere decir que el número de repeticiones o iteraciones de este bloque será cero. Si la condición siempre evalúa a verdadero, la secuencia de acciones se ejecutará indefinidamente, es 20 decir, un número infinito de veces. A fin de evitarlo, las instrucciones del cuerpo del ciclo deben contener alguna acción que modifique la o las variables involucradas en la condición, de modo que ésta, en algún momento deje de ser verdadera y así finalice la ejecución del ciclo. El correspondiente diagrama de flujo es: <condición> F V <acciones> Ejemplo: Enunciado: Se requiere un algoritmo en LDA para obtener la suma de cinco números enteros ingresados por teclado. Ambiente del algoritmo: Objeto Tipo C Variable de auxiliar, de tipo entero Se utiliza como contador de 5 números. nro Variable de entrada, de tipo entero Se utiliza para almacenar cada número entero ingresado por teclado. Variable de salida, de tipo entero Se utiliza para almacenar la suma de los 5 números ingresados por teclado. suma Descripción Algoritmo: Versión 1: t1. Definir las variables a ser utilizadas por el algoritmo. t2. Inicializar la variable contador C y la variable suma. t3. Mientras no se hayan ingresado 5 números, solicitar un número por teclado (nro) y actualizar el valor de suma, sumando su valor actual con el valor actual de nro. t4. Mostrar la suma de los 5 números ingresados. Versión 2: t1. Definir las variables a ser utilizadas por el algoritmo. t2.1. C<-1; t2.1. suma<-0; 21 t3. Mientras C<=5 Hacer t3.1. Solicitar un número y almacenarlo en nro. t3.2. Actualizar suma, sumando su valor actual con el valor actual de nro. t3.3. Incrementar en 1 la variable C. t4. Mostrar el contenido de la variable suma. Versión 3 (final): Proceso Suma_de_5_nros //t1. Definir C, nro, suma Como Entero; //t2.1. C <- 1; //t2.2. suma <- 0; //t3. Mientras C<=5 Hacer //t3.1. Escribir “Ingrese un número entero: ”; Leer nro; //t3.2. suma <- suma + nro; //t3.3. C <- C + 1; FinMientras //t4. Escribir “La suma de los 5 números ingresados es: “, suma; FinProceso Se puede observar que el contador del ciclo C se inicializa en uno, posteriormente se verifica que éste sea menor o igual a 5, que es la cantidad de veces que se deben ejecutar las acciones del cuerpo de la iteración (cinco veces). Dentro del cuerpo de la iteración, se lee un nuevo valor en nro, se acumula en suma y el contador se incrementa en 1. En general, toda iteración debe tener un valor inicial, un incremento y un verificador que establezca el límite de ejecución. Vamos a realizar una ejecución para el algoritmo Suma_de_5_nros con los siguientes datos de entrada: 5 8 4 3 5. Instrucción Definir C, nro, suma Como Entero; C <- 1; suma <- 0; C nro suma ⊥ ⊥ ⊥ Pantalla 1 0 ¿C<=5? -> SI 22 Ingrese un número entero: 5 Escribir “Ingrese un número entero:”; 5 Leer nro; 5 suma <- suma + nro; 2 C <- C + 1; ¿C<=5? -> SI Ingrese un número entero: 8 Escribir “Ingrese un número entero:”; 8 Leer nro; 13 suma <- suma + nro; 3 C <- C + 1; ¿C<=5? -> SI Ingrese un número entero: 4 Escribir “Ingrese un número entero:”; 4 Leer nro; 17 suma <- suma + nro; 4 C <- C + 1; ¿C<=5? -> SI Ingrese un número entero: 3 Escribir “Ingrese un número entero:”; 3 Leer nro; 20 suma <- suma + nro; 5 C <- C + 1; ¿C<=5? -> SI Ingrese un número entero: 5 Escribir “Ingrese un número entero:”; 5 Leer nro; 25 suma <- suma + nro; 6 C <- C + 1; ¿C<=5? -> NO Escribir “La suma de los 5 números ingresados es: “, suma; La suma de los 5 números ingresados es: 25 4.3.3.2 Estructura de repetición Repetir-Hasta Que El formato de esta estructura de control en el LDA es: Repetir <acciones>; Hasta Que <condición> La instrucción Repetir-Hasta Que ejecuta una secuencia de instrucciones (<acciones>) hasta que la <condición> sea verdadera. Al ejecutarse esta estructura de repetición, las <acciones> que forman el cuerpo de la repetición se 23 ejecutan una vez y luego se evalúa la <condición>. Si la condición es falsa, el cuerpo del ciclo se ejecuta nuevamente y se vuelve a evaluar la condición. Esto se repite hasta que la condición sea verdadera. Notar que, dado que la condición se evalúa al final, las acciones del cuerpo del ciclo siempre serán ejecutadas al menos una vez. Además, a fin de evitar repeticiones infinitas, el cuerpo del ciclo debe contener alguna acción que modifique a la o las variables involucradas en la condición de modo que en algún momento la condición sea verdadera y finalice la ejecución del ciclo. El diagrama de flujo correspondiente a esta estructura es el siguiente: <acciones> <condición> V F Supongamos ahora que se solicita realizar un algoritmo en LDA para obtener la suma de cinco números enteros ingresados por teclado pero utilizando la estructura de repetición Repetir-Hasta Que. El ambiente y las versiones 1 y 2 del algoritmo Suma_de_5_nros serían similares, sólo cambiaría la versión final. Versión 3 (final): Proceso Suma_de_5_nros_con_RepetirHastaQue //t1. Definir C, nro, suma Como Entero; //t2.1. C <- 1; //t2.2. suma <- 0; //t3. Repetir Escribir “Ingrese un número entero: ”; Leer nro; suma <- suma + nro; C <- C + 1; Hasta Que C > 5 //t4. 24 Escribir “La suma de los 5 números ingresados es: “, suma; FinProceso Como ejercicio, realizar la ejecución del algoritmo Suma_de_5_nros_con_RepetirHastaQue con los mismos datos que se ejecutó el algoritmo Suma_de_5_nros y observar que se obtienen los mismos resultados. Muchas veces en nuestros algoritmos es necesario realizar una validación de los datos ingresados por los usuarios antes de realizar cualquier acción. La validación no es más que determinar si el valor(es) ingresado(s) cumple(n) con alguna(s) característica(s). Por ejemplo, validar que un valor ingresado por el usuario esté en un rango (mayor que 0 y menor que 70). Las validaciones se las puede hacer a través de ciclos repetitivos. Uno de los que puede ser empleado es el Repetir-Hasta Que. Ejemplo: Elaborar un algoritmo en LDA que reciba como entrada un número y verifique si es un número comprendido entre 0 y 10; sino es así, se debe volver a solicitar un número hasta que se ingrese un valor correcto. Ambiente del algoritmo: Objeto Tipo nro Variable de entrada, de tipo entero Descripción Almacena el número a validar. Algoritmo: Versión 1: t1. Definir la variable a ser utilizada por el algoritmo. t2. Hasta que no se ingrese un número mayor o igual a 0 y menor o igual a 10, volver a solicitar un número. t3. Mostrar el cartel “Número correcto”. Versión 2 (final): Proceso Validacion //t1. Definir nro Como Entero; //t2. Repetir Escribir “Ingrese un número: ”; Leer nro; Hasta Que nro >= 0 & nro <= 10 //t3. 25 Escribir “Número correcto”; FinProceso Supongamos que en una ejecución del algoritmo el usuario ingresa los siguientes números -15 12 7. Entonces la ejecución del algoritmo será: Instrucción Definir nro Como Entero; nro Pantalla ⊥ Ingrese un número: -15 Escribir “Ingrese un número: ”; -15 Leer nro; ¿nro >= 0 & nro <= 10? -> NO Ingrese un número: 12 Escribir “Ingrese un número: ”; 12 Leer nro; ¿nro >= 0 & nro <= 10? -> NO Ingrese un número: 7 Escribir “Ingrese un número: ”; 7 Leer nro; ¿nro >= 0 & nro <= 10? -> SI Escribir “Número correcto”; Número correcto 4.3.3.3 Estructura de repetición Para-Hasta El formato de esta estructura de control en el LDA es: Para <variable> <- <inicial> Hasta <final> [Con Paso <paso>] Hacer <acciones>; FinPara Esta estructura de control repetitiva se emplea cuando se sabe de antemano cuántas veces se repetirán las acciones que conforman el cuerpo de la repetición (<acciones>). Al ingresar a la estructura, la variable <variable> (llamada variable de control de la repetición) recibe el valor inicial <inicial> y se evalúa si el valor almacenado en <variable> alcanzó el valor final indicado por <final>. Si esto no así, se ejecutan las <acciones> que forman el cuerpo del ciclo. Luego, se incrementa la variable <variable> en <paso> unidades y se vuelve a evaluar la condición. Si ésta es falsa se repite hasta que <variable> alcance al valor <final>. Los [ ] que encierran a [Con Paso <paso>] (en la definición de la estructura) se interpreta como que la cláusula puede escribirse o no, es decir, que es opcional. Si se omite la cláusula Con Paso <paso>, la variable <variable> se incrementará automáticamente en 1. <paso> puede ser un valor positivo o negativo y puede estar determinado por una constante o variable de tipo entero. El diagrama de flujo correspondiente es: 26 <variable> <- <inicial> <variable> no alcanzó el valor <final>? (*) (*) F V <acciones> Incrementar <variable> (*) (*) Estas acciones se realizan automáticamente. No se debe inicializar, ni incrementar explícitamente la variable de control <variable> y tampoco escribir la condición. Recomendación: no modificar la variable de control <variable> en ninguna de las acciones que forman las <acciones> del ciclo Para-Hasta. Recuerde que en el propio ciclo se define el <paso>. Supongamos que necesitamos una estructura de repetición Para-Hasta que muestre los números enteros comprendidos entre el 1 y el 10 en orden ascendente. La estructura y su correspondiente diagrama de flujo se muestran a continuación: I <- 1 I <= 10 F Para I <- 1 Hasta 10 Hacer Escribir I; FinPara V Escribir I; I <- I + 1; 27 Supongamos ahora que necesitamos mostrar los números enteros comprendidos entre el 1 y el 10 en orden descendente. Como en la definición de la estructura de repetición Para-Hasta podemos utilizar <paso> para incrementar la variable de control, en este caso <paso> puede ser -1 para realizar la muestra de los números en orden descendente. La estructura y su correspondiente diagrama de flujo se muestran a continuación: I <- 10; I >= 1 F Para I <- 10 Hasta 1 Con Paso -1 Hacer Escribir I; FinPara V Escribir I; I <- I + (-1); Notar que, a diferencia del ejercicio de la muestra ascendente, al tener un paso negativo la condición (que se genera automáticamente) evalúa por >=. ¿Y si quisiéramos mostrar los números pares comprendidos entre el 1 y el 10? Podríamos utilizar <inicial> igual a 2 y el <paso> igual a 2 para recorrer los números pares. La estructura y su correspondiente diagrama de flujo se muestran a continuación: I <- 2; I <= 10 F Para I <- 2 Hasta 10 Con Paso 2 Hacer Escribir I; FinPara V Escribir I; I <- I + 2; Verificar que los valores mostrados por pantalla son 2, 4, 6, 8, 10. 28 Supongamos ahora que se solicita realizar un algoritmo en LDA para obtener la suma de cinco números enteros ingresados por teclado pero utilizando la estructura de repetición Para-Hasta. El ambiente y las versiones 1 y 2 del algoritmo Suma_de_5_nros serían similares, sólo cambiaría la versión final. Versión 3 (final): Proceso Suma_de_5_nros_con_ParaHasta //t1. Definir C, nro, suma Como Entero; //t2.1. No se necesita esta tarea ya que C pasaría a ser la variable de control de la estructura y se // inicializa automáticamente //t2.2. suma <- 0; //t3. Para C <- 1 Hasta 5 Hacer Escribir “Ingrese un número entero: ”; Leer nro; suma <- suma + nro; FinPara //t4. Escribir “La suma de los 5 números ingresados es: “, suma; FinProceso Como ejercicio, realizar la ejecución del algoritmo Suma_de_5_nros_con_ParaHasta con los mismos datos que se ejecutó el algoritmo Suma_de_5_nros y observar que se obtienen los mismos resultados. Ejemplo: Enunciado: Dados 10 números enteros ingresados por el usuario se pide diseñar un algoritmo en LDA que calcule por separado el promedio de los números pares y el producto de los impares, mostrando como salida el promedio, el producto y además la cantidad de números pares e impares ingresados. Ambiente del algoritmo: Objeto I num cpares cimpares Tipo Descripción Variable de control, de tipo entero Sirve como variable de control de la estructura Para-Hasta. Variable de entrada, de tipo entero Almacena los números ingresados por el usuario. Variable de salida, de tipo entero Almacena la cantidad de números pares ingresados. Variable de salida, de tipo entero Almacena la cantidad de números impares ingresados. 29 spares pimpares Variable auxiliar, de tipo entero Almacena la suma de los números pares. Variable auxiliar, de tipo entero Almacena el producto de los números impares. Algoritmo: Versión 1: t1. Definir las variables a ser utilizadas por el algoritmo. t2. Inicializar las variables que correspondan. t3. Hasta que no se hayan ingresado 10 números enteros t3.1. Solicitar un número entero. t3.2. Si el número es par entonces incrementar en uno el contador de números pares y sumar el número par sino incrementar en uno el contador de números impares y calcular el producto de los números impares. t4. Imprimir la cantidad de números pares y su valor promedio. t5. Imprimir la cantidad de números impares y su producto. Versión 2 (final): Proceso SumaYPromedio // t1. Definir I, num, cpares, cimpares, spares, pimpares Como Entero; // t2. cpares <- 0; cimpares <- 0; spares <- 0; pimpares <- 1; // t3. Para I <- 1 Hasta 10 Con Paso 1 Hacer //t3.1. Escribir “Ingrese un número: ”; Leer num; // t3.2. Si num % 2 = 0 Entonces cpares <- cpares + 1; spares <- spares + num; Sino cimpares <- cimpares + 1; pimpares <- pimpares * num; FinSi FinPara // t4. 30 Escribir “Cantidad de números pares: ”, cpares; Escribir “Valor promedio de los números pares: ” , spares / cpares; // t5. Escribir “Cantidad de números impares: ”, cimpares; Escribir “Producto de los números impares: ”, pimpares; FinProceso Supongamos que en una ejecución del algoritmo el usuario ingresa los siguientes números 8 9 15 -20 10 2 120 5 -1 50. Entonces la ejecución del algoritmo será: Tarea Definir I, num, cpares, cimpares, I ⊥ num cpares cimpares spares pimpares ⊥ ⊥ ⊥ ⊥ Pantalla ⊥ spares, pimpares Como Entero; 0 cpares <- 0; 0 cimpares <- 0; 0 spares <- 0; 1 pimpares <- 1; I <- 1 1 ¿I <= 10? -> SI Ingrese un número: 8 Escribir “Ingrese un número: ”; 8 Leer num; ¿num % 2 = 0? -> SI 1 cpares <- cpares + 1; 8 spares <- spares + num; FinPara 2 ¿I <= 10? -> SI Ingrese un número: 9 Escribir “Ingrese un número: ”; 9 Leer num; ¿num % 2 = 0? -> NO 1 cimpares <- cimpares + 1; 9 pimpares <- pimpares * num; FinPara 3 ¿I <= 10? -> SI Ingrese un número: 15 Escribir “Ingrese un número: ”; 15 Leer num; ¿num % 2 = 0? -> NO 2 cimpares <- cimpares + 1; 135 pimpares <- pimpares * num; FinPara … (se continúa con la ejecución hasta la décima iteración) FinPara 4 9 -1 5 4 120 -675 10 31 ¿I <= 10? -> SI Ingrese un número: 50 Escribir “Ingrese un número: ”; 50 Leer num; ¿num % 2 = 0? -> SI 6 cpares <- cpares + 1; 170 spares <- spares + num; 11 FinPara ¿I <= 10? -> NO Escribir “Cantidad de números pares: ”, cpares; Escribir “Valor promedio de los números pares: ” , spares / cpares; Escribir “Cantidad de números impares: ”, cimpares; Escribir “Producto de los números impares: ”, pimpares; Cantidad de números pares: 6 Valor promedio de los números pares: 28.33 Cantidad de números impares: 4 Producto de los números impares: -675 En el ejemplo sólo se pidieron como entrada 10 enteros, pero también podría haberse solicitado que el usuario ingrese además la cantidad de enteros que desea ingresar y almacenar esta cantidad en la variable N. ¿Qué parte del algoritmo anterior se modificaría? También usaremos este ejemplo para ejemplificar dos usos comunes de una variable: como contador y acumulador. Contador Es una variable cuyo valor se modifica en una unidad constante cada vez que ocurre un evento. La modificación consiste en incrementar o decrementar el valor del contador. Se debe inicializar el contador antes de utilizarlo. En el algoritmo SumaYPromedio se utilizaron dos variables con esta finalidad: cpares y cimpares las cuales fueron inicializadas en cero antes del ingreso a la estructura Para-Hasta y luego en cada iteración fueron incrementadas en uno cuando correspondía. ¿Por qué fue necesario inicializarlas con un valor cero? Resumiendo el uso de un contador implica la realización de las siguientes operaciones: ● Inicialización: contador <- valor_inicial; ● Incremento: contador <- contador + constante; ó ● Decremento: contador <- contador - constante; Acumulador 32 Es una variable cuyo valor se modifica, en una cantidad variable, cada vez que ocurre un evento. La modificación puede ser incrementar o decrementar su valor. Al igual que los contadores, los acumuladores deben ser inicializados antes de utilizarse. En el algoritmo SumaYPromedio utilizamos dos variables como acumuladores spares y pimpares, las cuales fueron inicializadas con 0 y 1 respectivamente ¿Por qué se inicializaron con valores distintos? En spares se fue acumulando la suma de los números pares y en pimpares el producto de los números impares. Resumiendo, las operaciones que se realizan sobre un acumulador son: ● Inicialización acumulador <- valor_inicial; ● Sumador (incremento) acumulador <- acumulador + valor; ó ● Restador (decremento) acumulador <- acumulador – valor; ó ● Multiplicador (incremento) acumulador <- acumulador * valor; ó ● Divisor (decremento) acumulador <- acumulador / valor; Ya definidas las distintas estructuras de repetición, analizaremos a través de un ejemplo la correspondencia que existe entre ellas. 4.3.3.4 Correspondencia entre ciclos En la teoría matemática de programación sólo es necesario un tipo de estructura de repetición. En esta sección se explican las correspondencias que hacen posible esta afirmación, tomando como ciclo de referencia la estructura Mientras. Correspondencia entre el ciclo Mientras-Hacer y el ciclo Repita-Hasta Que La diferencia fundamental entre las iteraciones realizadas con la estructura Mientras-Hacer y Repita-Hasta Que, es que en el segundo se ejecuta por lo menos una vez las <acciones> del cuerpo de la iteración, mientras que en el primero existe la posibilidad de que no se ejecute alguna vez. El ejecutar las <acciones> una vez antes del ciclo Mientras-Hacer y negar la <condición> permite modelar un ciclo Repita-Hasta Que, es decir: 33 Repetir <acciones> Hasta Que <condición> <acciones> Mientras ¬<condición> Hacer <acciones> FinMientras Correspondencia entre el ciclo Para-Hasta y el ciclo Mientras-Hacer Formalmente, un ciclo Para-Hasta es una forma abreviada de un ciclo Mientras-Hacer, precedido por una asignación y que en cada iteración incrementa una variable. Por lo tanto, el siguiente ciclo ParaHasta: Para <variable> <- <inicial> Hasta <final> [Con Paso <paso>] Hacer <acciones>; FinPara es una forma abreviada de: a) Con paso positivo b) Con paso negativo <variable> <- <inicial>; <variable> <- <inicial>; Mientras <variable> <= <final> Hacer Mientras <variable> >= <final> Hacer <acciones>; <acciones>; <variable> <- <variable> + <paso>; <variable> <- <variable> + <paso>; FinMientras FinMientras Si al usar la estructura Para-Hasta se omite el paso, en el Mientras-Hacer debe incrementarse en 1 la <variable>, es decir, <variable> <- <variable> + 1;. El siguiente ejemplo se resuelve usando las distintas estructuras de repetición. Verificar que tienen el mismo comportamiento. Ejemplo: Diseñar un algoritmo en LDA que imprima los números pares en orden descendente entre 1 y 100. Solución 1 Proceso Ejemplo Solución 2 Proceso Ejemplo Solución 3 Proceso Ejemplo Definir I Como Entero; Definir I Como Entero; Definir I Como Entero; Para I <- 100 Hasta 2 Con Paso -2 Hacer I <- 100; I <- 100 ; Mientras I >= 2 Hacer Repetir Escribir I ; FinPara Escribir I ; Escribir I ; FinProceso I <- I - 2 ; I <- I – 2 ; FinMientras FinProceso Hasta Que I < 2 FinProceso 4.3.3.5 ¿Cuándo usar estructuras de control definido o indefinido? 34 La estructura de repetición Para-Hasta se conoce comúnmente como estructura de control definido, ya que los valores iniciales y finales especificados para la variable contadora que controla el ciclo determina de manera exacta el número de veces que se ejecuta el mismo. Tanto el valor <inicial> como el <final> pueden estar determinados utilizando constantes de tipo entero o variables de tipo entero. Cuando se utilicen variables, se debe asegurar que almacenen valores válidos. Para utilizar un ciclo Para-Hasta, al resolver un algoritmo se debe determinar el número exacto de veces que se va a ejecutar el ciclo. En el ejemplo anterior de calcular los números pares desde 2 a 100, se conoce el límite inferior y superior de la repetición y el paso, entonces se sabe que se ejecutará exactamente 50 veces (¿por qué?). Por otro lado, tanto la estructura Mientras-Hacer como Repita-Hasta Que se conocen como estructuras de control indefinido, puesto que a priori no se conoce la cantidad de veces que se ejecutarán porque dependen de una condición. La estructura Mientras-Hacer permite ejecutar una secuencia de acciones mientras que la evaluación de una expresión lógica de cómo resultado verdadero y dicha secuencia de acciones puede ejecutarse cero o más veces. La estructura Repita-Hasta Que permite ejecutar una secuencia de acciones por lo menos una vez. Luego evalúa la condición y la secuencia de acciones sólo se ejecutará mientras la condición sea falsa. Anidamiento de estructuras de control repetitiva De la misma forma que es posible incluir dentro de una estructura condicional otra estructura condicional, también es posible insertar una estructura de repetición en el interior de otra estructura de repetición. Las reglas de anidamiento son similares en ambos casos: la estructura interna debe estar totalmente contenida dentro de la estructura externa, no permitiéndose el solapamiento. A continuación se presentan distintos ejemplos del uso de estructuras de control anidadas: Ejemplo: Enunciado: Se conoce la población de cada una de las cinco ciudades más importantes de veintiocho países y se desea identificar e imprimir la población de la ciudad más grande (en número de habitantes) de cada país. El tamaño de la población de cada ciudad es un dato ingresado por el usuario. Ambiente del algoritmo: Claramente se desprende del enunciado que vamos a necesitar dos repeticiones. Ambas con número de repeticiones conocidas: una repetición para controlar los 28 países y otra para controlar las 5 ciudades más importantes de cada país. Por lo tanto podemos utilizar dos estructuras de repetición del tipo Para-Hasta, que tendrán dos variables de control, una para cada ciclo: J para controlar el número de país y K para controlar el número de ciudad. Además se necesita una variable para ir guardando el tamaño de población de cada ciudad, que podemos llamar tampobl y una variable para guardar el tamaño de la mayor ciudad (en cantidad de habitantes) de cada país, que llamaremos mayor. Sintetizando el ambiente sería: Objeto Tipo Descripción 35 J K tampobl Variable de control, de tipo entero Controla la repetición del número de país. Variable de control, de tipo entero Controla la repetición del número de ciudad. Variable de entrada, de tipo entero Contiene la cantidad de habitantes de cada ciudad. Variable de salida, de tipo entero Contiene la cantidad de habitantes de la ciudad de mayor tamaño para un país dado. mayor Algoritmo: Versión 1: t1. Definir las variables a ser utilizadas por el algoritmo. t2. Mientras no se hayan ingresado los datos para los 28 países t2.1. Inicializar mayor (mayor<-0;) t2.2. Mientras no se hayan ingresado las 5 ciudades más importantes de cada país t2.2.1. Solicitar tamaño de población (tampobl) t2.2.2. Si tamaño de población ingresado es mayor que mayor entonces mayor <tampobl t2.3. Informar el mayor número de habitantes de las ciudades del país ingresado. Versión 2 (final): Proceso Ciudades //t1. Definir J, K, tampobl, mayor Como Entero; //t2. Para J <- 1 Hasta 28 Hacer //t2.1. mayor <- 0 ; //t2.2. Para K <- 1 Hasta 5 Hacer //t2.2.1. Escribir “Ingrese tamaño de población”; Leer tampobl; //t2.2.2. Si tampobl > mayor Entonces mayor <- tampobl; FinSi FinPara //t2.3. Escribir “El mayor número de habitantes del país ”, J ,“ es: ” ,tampobl; 36 FinPara FinProceso En el algoritmo anterior notar que en ambos Para-Hasta se omitió el paso ya que cuando se omite la variable de control se incrementa automáticamente en 1. Queda como actividad para el alumno construir una tabla de ejecución para el algoritmo Ciudades. Se sugiere usar para la prueba 4 países y 3 ciudades para cada país, quedando a su elección el tamaño de cada ciudad. Ejemplo: Enunciado: Diseñar un algoritmo en LDA que permita encontrar los tres primeros números perfectos. Un número es perfecto cuando la suma de sus divisores enteros positivos (menores a sí mismo) es igual al número considerado. Por ejemplo, el número 6 es perfecto porque sus divisores son 1, 2, 3 y su suma es 1+2+3 = 6. Necesitamos encontrar los 3 primeros números perfectos pero no sabemos cuánto vamos a iterar hasta encontrarlos. Esto nos lleva a usar una estructura de repetición Mientras-Hacer porque no podemos usar una estructura Para-Hasta. Este Mientras-Hacer estará controlado por la cantidad de números perfectos (variable cuentanp) que encuentre. Además vemos que el problema no requiere de ningún dato de entrada. Por lo tanto, debemos ir generando los números (variable numgen) y para cada uno de ellos verificar si es o no perfecto. Para hacer esto debo calcular sus divisores (variable div) e ir sumándolos (variable sumdiv) y ¿cuántas veces debo hacer esto? Comenzar por el divisor 1 hasta el número generado menos 1, entonces esto lo podemos hacer usando un Para-Hasta que tiene como variable de control a div y al terminar el Para-Hasta controlar si la suma de los divisores es igual al número generado. Ambiente del algoritmo: Objeto cuentanp numgen Tipo Variable auxiliar, de tipo entero Cuenta los números perfectos generados (variable de control del Mientras-Hacer). Variable auxiliar, de tipo entero Contiene generados. Variable auxiliar, de tipo entero Contiene los posibles divisores de los números generados (variables de control del Para-Hasta). Variable auxiliar, de tipo entero Contiene la suma de los divisores. div sumdiv Descripción los distintos números Algoritmo: Versión 1: t1. Definir las variables a ser utilizadas por el algoritmo. t2. Incializar la variable de control (cuentanp) del Mientras-Hacer en 1. 37 t3. Incializar la variable numgen en 0. t4. Mientras no se hayan encontrado los 3 primeros números perfectos t4.1. Generar número (numgen). t4.2. Inicializar el sumador de divisores. t4.3. Mientras no se encuentren los divisores de numgen desde 1 hasta numgen-1. t4.3.1. Si es div es divisor de numgen entonces sumarlo en el sumador de los divisores (sumdiv). t4.4. Si la suma de los divisores es igual al número generado (numgen) entonces mostrar e incrementar en 1 la variable de control del Mientras-Hacer. numgen Versión 2 (final): Proceso TresPerfectos //t1. Definir cuentanp, div, numgen, sumdiv Como Entero; //t2. cuentanp <- 1; //t3. numgen <- 0; //t4. Mientras cuentanp <=3 Hacer //t4.1. numgen <- numgen + 1; //t4.2. sumdiv <- 0; //t4.3. Para div <- 1 Hasta numgen -1 Hacer //t4.3.1. Si numgen % div = 0 Entonces sumdiv <- sumdiv+div; FinSi FinPara //t4.4. Si sumdiv = numgen Entonces Escribir numgen; cuentanp <- cuentanp +1 ; FinSi FinMientras FinProceso Verificar (utilizando PSeInt) que el algoritmo propuesto genera la siguiente salida 6 28 496. El Mientras-Hacer más externo ¿podría reemplazarse por un Repetir-Hasta Que? Piense como justificaría su respuesta y escriba el algoritmo alternativo. Ejemplo: 38 Enunciado: Una empresa vende 5 artículos distintos, identificados con los códigos 1 a 5. La empresa desea conocer los montos de venta de cada artículo por día y el monto total de la venta diaria (es decir de todos los artículos). El algoritmo debe dar la posibilidad de ingresar más de un día a voluntad del usuario. También se debe controlar que el código de artículo ingresado sea correcto. En un ejemplo anterior hemos visto una de las formas posibles de validar datos de entrada usando una estructura de repetición Repetir-Hasta Que. Para validar que el código de artículo que ingrese sea correcto usaremos la misma idea. Si no fuera correcto se pedirá un nuevo ingreso. A los efectos de permitir que el usuario elija cuando quiere finalizar, le vamos a solicitar que ingrese una “S” o “s” para seguir y una “N” o “n” si quiere finalizar. Por lo tanto, para esta repetición usaremos una estructura Mientras-Hacer. Necesitamos una variable para guardar si el usuario desea seguir o no, de tipo caracter (variable continuar); también debemos conocer cuando finaliza un día (variable undia) y tendremos otra repetición del tipo Mientras-Hacer. Necesitamos otra variable entera para almacenar el código del artículo (variable codigo), una variable real para almacenar el monto de venta de un artículo (variable monto) y cinco variables acumuladoras reales (variables art1, art2, art3, art4 y art5) para sumar los montos de cada uno de los artículos. El ambiente se define como: Ambiente del algoritmo: Objeto Tipo Descripción continuar Variable caracter de entrada, de tipo Contiene la respuesta del usuario para saber si se continúa con el ingreso. undia Variable caracter de entrada, de tipo Indica si finaliza un día. codigo Variable de entrada, de tipo entero Contiene el código del artículo. Monto Variable de entrada, de tipo real Contiene el monto ingresado. Variable auxiliar, de tipo real Acumulador. Contiene la suma de los montos del artículo 1. Variable auxiliar, de tipo real Acumulador. Contiene la suma de los montos del artículo 2. Variable auxiliar, de tipo real Acumulador. Contiene la suma de los montos del artículo 3. Variable auxiliar, de tipo real Acumulador. Contiene la suma de los montos del artículo 4. Variable auxiliar, de tipo real Acumulador. Contiene la suma de los montos del artículo 5. art1 art2 art3 art4 art5 Algoritmo: Versión 1: t1.1. Definir las variables undia, continuar como caracter. t1.2. Definir la variable código como entero. t1.3. Definir las variables monto, art1, art2, art3, art4 y art5 como reales. 39 t2. Consultar si desea seguir procesando y guardar respuesta en continuar. t3. Mientras el usuario desee seguir procesando días t3.1. Inicializar acumuladores. t3.2. Asignarle a la variable undia una “N” o “n” (significa que NO se finalizó con el día) t3.3. Mientras no finalice un día t3.3.1. Mientras no se ingrese un código correcto t3.3.1.1. Solicitar ingreso del código del artículo. t3.3.2. Solicitar e ingresar monto de venta. t3.3.3. Dependiendo del valor del código, acumular en el acumulador correspondiente sumándole monto. t3.3.4. Solicitar si finalizó un día. t3.4. Mostrar las ventas de cada artículo y mostrar la venta total del día ingresado. t3.5. Solicitar si desea procesar otro día. Versión 2 (final): Proceso Ventas //t1.1. Definir undia, continuar Como Caracter; //t1.2. Definir codigo Como Entero; //t1.3. Definir monto, art1, art2, art3, art4, art5 Como Real; //t2. Procesamiento de días Escribir “Desea procesar otro día” ; Leer continuar; //t3. Mientras continuar = “S” | continuar = “s” Hacer // Procesamiento de un día //t3.1. art1 <- 0; art2 <- 0; art3 <- 0; art4 <- 0; art5 <- 0; //t3.2. undia <- “n”; //t3.3. Mientras undia = “N” | undia = “n” Hacer // t3.3.1. Validación de código Repetir Escribir “Ingrese código de artículo”; 40 Leer codigo; Hasta Que codigo >= 1 & codigo <= 5 // t3.3.2. Escribir “Ingrese monto de venta”; Leer monto; // t3.3.3. Segun codigo Hacer 1: art1 <- art1 + monto; 2: art2 <- art2 + monto; 3: art3 <- art3 + monto; 4: art4 <- art4 + monto; 5: art5 <- art5 + monto; FinSegun //t3.3.4. Escribir “Finalizó las compras de un día?”; Leer undia; FinMientras //del procesamiento de un día //t3.4. Escribir “Total de ventas de artículo 1 ”, art1; Escribir “Total de ventas de artículo 2 ”, art2; Escribir “Total de ventas de artículo 3 ”, art3; Escribir “Total de ventas de artículo 4 ”, art4; Escribir “Total de ventas de artículo 5 ”, art5; Escribir “Total de ventas del día: ”, art1 +art2 + art3 + art4 + art5; //t3.5. Escribir “Desea procesar otro día?”; Leer continuar; FinMientras // termina el procesamiento de los días FinProceso Construir la tabla de ejecución del algoritmo Ventas con los siguientes datos de entrada: s 1 100 n -1 2 150 n 3 500 s S 5 300 n 4 250 s N 41
© Copyright 2025 ExpyDoc