ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Antes de incorporar conceptos de programación, debemos hacer hincapié en la importancia que tiene el desarrollo de la imaginación, para ser capaces de idear la sucesión de hechos que se dan en un proceso. Por ejemplo: Imaginemos el procedimiento para cambiar una cubierta de un vehículo: ¿Qué sucesos involucra? 1º Saber qué cubierta está pinchada. 2º Abrir el baúl. 3º Si tengo cubierta de auxilio, sacarla; en caso contrario pedir ayuda. 4º Verificar el estado del auxilio. Si está en condiciones: 4.1. Buscar, hasta encontrar, las herramientas necesarias para cambiar la cubierta. 4.2. Asegurarse de que el vehículo no se desplace. 4.3. Aflojar los bulones. 4.4. Colocar el criquet en el lugar que corresponda. 4.5. Elevar el vehículo. 4.6. Extraer bulones y cubierta. 4.7. Colocar la cubierta en condiciones y ajustar los bulones. 4.8. Bajar el vehículo. 4.9. Asegurar los bulones. 4.10. Retirar los tacos/piedras puestos para fijar el vehículo. 4.11. Guardar cubierta pinchada, herramientas, y eventuales tacos. 4.12. Fin. 5º En caso de que la cubierta de auxilio no esté en condiciones, deberá llevarse a reparar, para luego efectuar el paso 4. Esto que acabamos de describir puede llamarse “algoritmo para cambiar una cubierta pinchada”. Así podemos definir: . Algoritmo: manera formal y sistemática de representar la descripción de un proceso. Secuencia ordenada de pasos - sin ambigüedades -, repetible, que es solución de un determinado problema Las características fundamentales que debe cumplir todo algoritmo son: a) Debe ser preciso e indicar el orden de realización de cada paso b) Debe estar definido (si se repite n veces los pasos se debe obtener siempre el mismo resultado) c) Debe ser finito (debe tener un número finito de pasos) d) Es independiente del lenguaje de programación que se utilice La definición de un algoritmo debe describir tres parte Entrada, Proceso, Salida. 1º 2º 3º 4º 5º 6º 7º 8º 9º 10º 11º 12º Desarrollemos ahora el algoritmo para preparar una ensalada de frutas: Disponer los ingredientes: azúcar, frutas (manzana, banana, ananá, naranja, cereza, uva, durazno). Disponer los utensilios: cuchillo, tablita, ensaladera profunda, exprimidor y jarrita. Lavar meticulosamente toda la fruta. Seleccionar 4 naranjas, cortarlas por la mitad, exprimirlas y guardar el jugo en la jarrita. Tomar una fruta. Si es naranja, manzana o durazno, cortarla en cuartos y pelarla con el cuchillo. Si es banana, pelarla con la mano. Si es ananá, corlarla en rodajas, y apoyando cada una en la tablita, quitar con el cuchillo la cáscara. Tomar cada racimo de uvas, y separarlas, colocándolas en la ensaladera. Quitar los cabos a las cerezas y colocarlas en la ensaladera. Cortar las frutas peladas en cubos y colocarlos en la ensaladera. Rociar el azúcar en forma de lluvia sobre la fruta que está en la ensaladera. APUNTES TEÓRICOS -1- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación 13º Agregar el jugo exprimido. 14º Revolver cuidadosamente para que no se deshaga la banana. 15º Fin. (Disfrute su ensalada). Podrá apreciarse que en este algoritmo los términos son precisos y a veces redundantes, a fin de cumplir con una especificación formal de los pasos. Obviamente, el desarrollo de nuestros contenidos estará orientado a problemas no domésticos, por lo que estos ejemplos persiguen un fin ilustrativo. Nuestro objetivo final será la construcción de algoritmos que funcionen y hagan aquello para lo que fueron desarrollados. Usted habrá escuchado hablar de programas de computadora; ¿Qué relación tienen éstos con los algoritmos que acabamos de definir? Un programa es la suma del/de los algoritmo/s y las especificaciones necesarias para que éste emita un resultado. En términos formales: Programa = estructuras de datos + estructuras de control Fases para la construcción de un programa 0. Entender el problema (esto implica hacer un mapa mental del problema y abarcarlo como un todo). 1. Análisis del problema (esta etapa implica armar el modelo del problema y abstraerlo en sus distintas estructuras). 2. Programar el modelo de solución propuesto (en pseudocódigo). 3. Codificarlo en un lenguaje de computadora. 4. Cargarlo en la computadora para su ejecución y ajuste. 5. Darle mantenimiento a lo largo de su vida útil. Las fases 0 y 1 equivalen al trabajo de diseño que realiza un arquitecto. Luego de conversar con su cliente sobre el objetivo de la edificación a construir, indaga sobre las características globales de esta última (ubicación geográfica, cantidad de pisos, presupuesto disponible, materiales, superficie cubierta, etc.) y a partir de ello construye la maqueta que presenta al cliente, y amplía el nivel de detalles para la confección de los planos (fase 2). Las fases 3, 4 y 5 equivalen a la construcción de la vivienda, con los mismos pormenores que en la construcción de un programa. A medida que lo vamos haciendo, el cliente propone nuevos detalles que alteran el ritmo de la programación, con la diferencia que es mucho más fácil rehacer software, que tirar una pared y levantar otra en otra parte (por ejemplo). Si se trata de software de calidad, los cambios son mucho más fáciles de realizar. Inicialmente utilizaremos pseudocódigo para programar. Este lenguaje se utiliza para escribir algoritmos que luego serán codificados para su ejecución en computadoras. Veremos algunas convenciones que deberán respetarse, para evitar ambigüedades en el desarrollo de los mismos. También utilizaremos metapalabras, que son palabras que representan un objetivo específico, por lo que además de restringir su uso a dicho objetivo, deberán ir subrayadas. Las metapalabras que utilizaremos son las siguientes: hacer cadena entonces escribir escribirln no procedimiento registro repetir termina tipos abrir lógico sino leer programa y variables archivo hasta opción entero cerrar arreglo mientras si función ó constantes fin comienza de real El objetivo de cada una de ellas va anexo a este apunte. APUNTES TEÓRICOS -2- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Como habrá podido observar, la ecuación de la programación estructurada cuenta con Estructuras de Datos, y Estructuras de Control. Comenzaremos nuestro estudio con las primeras mencionadas: Estructuras de Datos Los datos que maneja un programa pertenecen a un tipo determinado. Este tipo tiene asociado un conjunto de operaciones posibles (lo que podríamos llamar su álgebra). Nosotros manejaremos tipos simples estándares, y algunos de los tipos compuestos ó estructurados. Simple Estructurado entero real lógico carácter cadena arreglo multi-dimensional registro archivo secuencial arreglo uni-dimensional En esta primera etapa de estudio utilizaremos los tipos simples, y la cadena como un conjunto de caracteres. Más adelante desarrollaremos los contenidos de los tipos estructurados. Entero: tipo que se utiliza para representar valores enteros, Ejemplos: 18 30 1997 (una edad) (días en el mes) (año en curso) Real: tipo que se utiliza para representar valores del conjunto de números reales. Ejemplos: 37.18 3.14159 9.8 (una cuota en pesos) (pi) (aceleración de la gravedad) Lógico: tipo que se utiliza para representar valores booleanos(verdadero, falso). Ejemplos: verdadero falso (estoy estudiando programación) (estoy descansando en el Caribe) Carácter: tipo que se utiliza para representar los distintos caracteres empleados tanto para expresiones aritmético-lógicas como para graficación. Se escribe entre apóstrofes. Ejemplos: 'S' (ese mayúscula) '∗' (asterisco) '#' (numeral) '&' (ampersand) Cadena: tipo utilizado para expresar palabras. APUNTES TEÓRICOS -3- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Debe ir encerrada entre apóstrofes. Ejemplos: 'la luna es blanca' 'Lógica y Programación' 'N' Ahora bien, un programa tiene sentido si desarrolla un algoritmo para más de un dato. De allí surge la necesidad de representar los datos mediante variables. Variable: elemento fundamental que representa a los datos a ser procesados mediante un algoritmo. Su contenido es variable en el tiempo. Desde el punto de vista de las computadoras, son direcciones de memoria en las que se almacenan los datos que procesa un programa. A cada variable le corresponde su tipo; puede haber más de una variable de un mismo tipo, pero a cada variable le corresponde un único tipo. Identificador: nombre único asociado a cada variable. Ejemplos: identificador tipo edad estudié cuota apellido_y_nombre ángulo respuesta días_en_el_mes letra titulo entero lógico real cadena real carácter entero carácter cadena Estructuras de Control Son construcciones lógicas que dirigen el flujo de acciones que efectuará el procesador sobre los datos que maneja un programa, los que estarán organizados en estructuras de datos. Existen tres estructuras básicas de control, que a su vez pueden combinarse entre sí para formar estructuras más complejas. Ellas son: secuenciación, selección e iteración. Al hablar de estructuras de control se hace necesario definir qué es un enunciado y qué una condición. Enunciado: sentencia o instrucción que representa una operación elemental sobre ninguna, una o más variables. Según el número de acciones que se realizan sobre ésta/s, los enunciados se clasifican en nulo(ninguna acción), simple (una sola acción), ó compuesto (más de una). El enunciado nulo tiene un uso particular que veremos oportunamente. La operación de asignación es un enunciado simple, que se representa mediante el signo ←. El formato de dicho enunciado es: id_variable "←" expresión. Esto significa que el valor de la expresión se "almacena" en la variable identificada por el "id_variable" Ejemplos: mes← 'agosto' año ← 1997 APUNTES TEÓRICOS -4- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación pi ← 3.14159 entendí ← verdadero Ejemplos: escribir x leer x abrir archi cerrar archi x ← x+2 Estos son enunciados simples Vimos que un enunciado es compuesto si implica más de una operación sobre una o más variables. Al tratarse de un enunciado, debemos agrupar dichas acciones para su tratamiento como único. Esto se logra encerrando las mismas entre paréntesis. Las metapalabras utilizadas para este fin son comienza y termina. Ejemplos • • comienza leer x y←x+3 escribir x, y y ← y ∗ 4 + 89 / x escribir y escribir 'se terminó' termina comienza escribir '¿Cuál es tu nombre?' leer nombre escribir nombre, ' , ¿Cuántos años tenés?' leer edad termina Condición: expresión lógica, la que por su condición de tal, podrá tomar los valores verdadero o falso; Ejemplos: x<7 a=b (a>b) ∧ (x<7) no fin(archi) Veamos entonces cada una de las estructuras de control, con ejemplos de aplicación, simbolizando con e los enunciados y con c las condiciones. secuenciación: sucesión de enunciados que se ejecutan uno a continuación del otro. e0 e1 e2 ... en Ejemplos: • leer x x ← x+2 escribir x • x←0 Observación: un único enunciado ya es una secuenciación APUNTES TEÓRICOS -5- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Selección: sentencia que evalúa una expresión, y en función de los valores de ésta, dirige el flujo del proceso. Según el tipo de la expresión, como del número de valores posibles que pueda tener, se definen dos formas de selección: Selección dicotómica: enunciado formado por una expresión booleana, (verdadera ó falsa) y dos alternativas disjuntas de flujo de control. Simbólicamente: si c entonces sino e1 e2 lo cual se entiende así: en el flujo de control, se evalúa el valor de certeza de c. Si es cierto, ejecuta e1 y continúa con el flujo del programa. Si c es falso, ejecuta e2 y continúa con el flujo del programa Ejemplos: si x>0 entonces escribir x, ‘positivo’ sino escribir x, ‘nulo ó negativo’ si fin (archi) entonces parar←verdadero parar← falso sino Selección Múltiple: enunciado formado por una expresión entera, cuyo resultado pertenece a un conjunto de opciones, y según el cual se ejecuta uno sólo de los enunciados alternativos. Simbólicamente: opción valor de valor1: e1 valor2: e2 valor3: e3 .............. valorn: en termina opción Ejemplos: • opción 'I' 'V' 'X' 'L' 'C ' 'D' 'M' romano de : número ← 1 : número ← 5 : número ←10 : número ← 50 : número ←100 : número ←500 : número ←1000 termina opción • opción mes de enero, marzo, mayo, julio, agosto, octubre, diciembre : días ← 31 febrero : días ← 28 abril, junio, setiembre, noviembre : días ←30 termina opción APUNTES TEÓRICOS -6- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Iteración: construcción que indica la repetición de un grupo de enunciados de acuerdo al valor de determinada condición. Según el orden de ejecución del enunciado, como así también del número prefijado o no de repeticiones, veremos que existen tres formas de iteración: 1. ITERACIÓN MIENTRAS mientras c hacer e El enunciado e se ejecuta mientras la condición c sea verdadera. Dicha condición es evaluada antes de ejecutar por primera vez el enunciado. Si el valor lógico de la condición es falso inicialmente, dicho enunciado no se ejecutará. Ejemplo 1: En este caso, si el valor que se lee de x es mayor que 5, lo decrementa leer x en dos, tantas veces mientras el valor obtenido sea mayor que 5. En mientras x>5 hacer x←x-2 cambio, si es 5 o menos, no se ejecuta el mientras Ejemplo 2: total ← 0 cantidad ← 0 En este caso, se repite la lectura de unidamientras (total ≤ 1235) ν (cantidad < 15) hacer des, se las cuenta y acumula mientras la comienza suma sea menor o igual a 1235 o se hayan leer unidades contado 15. Cuando alguna de las dos concantidad ← cantidad + 1 diciones es falsa, imprime el total y la cantitotal ← total + unidades dad termina escribir total , cantidad Ejemplo 3: leer x mientras x < 8 hacer x Este mientras nunca va a terminar si el primer valor que ingresa es menor que 8. ¿por qué? x-3 2. ITERACIÓN REPETIR repetir e hasta c El enunciado e se ejecuta hasta que la condición c sea verdadera. Una vez que la condición es verdadera, termina la iteración. Cabe aclarar que la evaluación de la condición se realiza después de haber ejecutado el enunciado, lo que permite la ejecución de éste último al menos una vez. Ejemplo 1: Traza leer x Tiempo X repetir T1 8 x←x/2 T2 4 hasta x<2 T3 2 T4 1 Ejemplo 2 : sum_altura ← 0 sum_edad ← 0 sum_talle ← 0 canti_per ← 0 repetir leer nombre, edad, talle, altura canti_per ←canti_per +1 sum_altura ← sum_altura + altura sum_edad ← sum_edad + edad sum_talle ← sum_talle + talle hasta canti_per = 80 Este segmento lee nombre, edad, talle y altura de 80 personas APUNTES TEÓRICOS -7- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación 3. ITERACIÓN PARA para valor ← limite_inf hasta limite_sup hacer e donde valor es una variable de tipo entero , cuyo contenido varía desde límite_inf hasta límite_sup, incrementándose en uno para cada ejecución de e . Así, la primera vez se ejecuta tomando el valor limite_inf , luego limite_inf +1 (si esto es menor o igual a limite_sup), y así sucesivamente hasta tomar el valor limite_sup. Ejemplo1: Para j ← 1 hasta 8 hacer escribir j + 3 La salida será: 4, 5, 6, 7, 8, 9, 10, 11 Ejemplo 2: Para k ← 3 hasta 15 hacer comienza línea ← k columna ← k + 10 leer carácter escribir línea, columna, carácter termina Atención: Si observamos los distintos ejemplos anteriores, veremos que cada ciclo se ejecuta en forma finita, es decir, que a partir de cierta condición, el bucle finaliza. A esto se le dice "satisfecho el ciclo". En el caso del mientras, ocurre cuando la condición se hace falsa. En el caso del repetir hasta, ocurre cuando la condición se hace verdadera. Para ello debe haber una sentencia que modifique correctamente el valor lógico de la condición. Si esto no ocurre, estamos en presencia de un ciclo infinito. Al construir una estructura iterativa de estos tipos, debemos poner especial cuidado en que el bucle finalice, Ejemplo: x←3 mientras x<5 hacer escribir x nunca estará "satisfecho", porque x nunca dejará de ser menor que 5, es decir, el valor lógico de la condición es siempre verdadero. El resultado de su ejecución será escribir x infinitamente. Veamos otro caso: dato ← 3 repetir dato ← dato + 5 suma ← suma + 12 escribir dato, suma hasta dato < 7 Este "ciclo" es infinito pues dato se incrementa en cinco (partiendo del valor 3), por lo que dato < 7 nunca será verdadero. Estos errores son muy severos en la programación, y para resolverlos, se debe “apagar” la computadora. Ya estamos en condiciones de escribir un algoritmo: • Dados tres números enteros positivos, leídos en forma ascendente, desarrollar el algoritmo que determine: ⇒ si forman triángulo ⇒ si es equilátero, isósceles o escaleno ⇒ el área del mismo Recordemos las distintas fases para la construcción de un algoritmo: debemos primero entender el problema. ¿Qué características tiene el ingreso de los datos? ¿Ordenados, enteros, etc.? APUNTES TEÓRICOS -8- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación ¿Qué condición deben cumplir los datos para formar un triángulo? ¿Cuándo es equilátero, isósceles, escaleno? ¿Cuál es la fórmula de su superficie? Una vez resueltos esos interrogantes, nos ponemos a escribir el algoritmo. comienza { comienza el algoritmo } leer lado1, lado2, lado3 dato_válido ← (lado1< lado2 ) Λ (lado2 < lado3) {aquí debo controlar que ingresen en orden ascendente. si no cumplen esa condición, pido otros datos, y así repetidamente hasta que la cumplan, por lo tanto, debo utilizar un ciclo} mientras ∼ dato_válido hacer comienza escribir 'sus datos no ingresaron en forma ascendente. Ingrese una nueva terna' leer lado1, lado2, lado3 dato_valido ← (lado1< lado2) Λ (lado2 < lado3) termina { ya tengo seguridad de que los datos son correctos. Esto pasa a ser la pre-condición para el algoritmo} { ahora controlo si forman triángulo. En caso afirmativo, determino su tipo} triángulo ← (lado1< lado2 + lado3) Λ(lado2 < lado1 + lado3) Λ (lado3 < lado1 + lado2) si no triángulo entonces escribir 'sus datos no determinan un triángulo' sino comienza si (lado1 = lado2) Λ (lado2 = lado3 ) entonces mensaje ← 'equilátero' sino si (lado1 = lado2) ν (lado2 = lado3) entonces mensaje ← 'isósceles ' mensaje ←'escaleno' sino escribir 'sus datos determinan un triángulo', mensaje 2 lado1 lado2² − 2 lado1 * alt u ra superficie ← 2 escribir 'El área de su triángulo es', superficie termina altura ← termina {finaliza el algoritmo} Nótese el detalle de los comentarios. Estos deben ir encerrados entre llaves { } , y se utilizan para clarificar la acción de cada enunciado. Regla fundamental de la composición de estructuras: Es posible combinar las estructuras de control de secuenciación, selección e iteración utilizando para tal fin, las mismas estructuras. APUNTES TEÓRICOS -9- ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Ejemplo1: e0 e1 si c1 entonces mientras c2 hacer comienza e2 e3 e4 termina sino e5 e6 Ejemplo 2: e0 mientras c1 hacer comienza si c2 entonces comienza e1 e2 e3 termina sino e4 e5 Ejemplo 3 • El siguiente algoritmo calcula e imprime el total de lluvia caída (de más de 5 mm³) y la tempe- ratura promedio de aquellas menores que 35°C. total_lluvia ← 0 total_temp ← 0 canti_est ←0 leer estación, lluvia, temperatura mientras estación ≠ 0 hacer comienza canti_est ← canti_est + 1 si lluvia < 5 entonces escribir 'no me interesa' sino total_lluvia ←total_lluvia + lluvia si temperatura > 35 entonces escribir '¡¡qué calor!!' sino total_temp ← total_temp + temperatura leer estación, lluvia, temperatura termina escribir 'la lluvia caída en el año es', total_lluvia escribir 'el promedio de temperaturas es', total_temp / canti_est ¿ Cuándo termina el ingreso de datos? El criterio para finalizar el ingreso de datos lo establece el programador, en función del modelo que esté programando. Habrá casos en los que un valor determinado define la finalización de un proceso (por ejemplo el día 365 de un año), o el carácter <N> en una respuesta a la pregunta de ‘¿desea ingresar más datos?’, o un cero ingresado como denominador de una división. En fin, las situaciones son muy particulares como para establecer un criterio general. Podrá observarse en cada caso la forma de resolverlo. Ejemplo • Ingresan datos hasta que la suma de los mismos sea mayor que 12345. suma ← 0 repetir leer dato suma ← suma + dato hasta suma > 12345 • Suma datos mientras el operador lo desee. suma ← 0 escribir '¿Desea ingresar datos? Pulse <S> ó <N>' leer respuesta mientras respuesta = 'S' hacer comienza leer dato APUNTES TEÓRICOS - 10 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación suma ← suma + dato escribir '¿Desea ingresar más datos? Pulse <S> ó <N>' leer respuesta termina escribir 'la suma de sus datos es', suma • Calcula cocientes de datos mientras el denominador sea distinto de 0. leer numerador leer denominador mientras denominador ≠ 0 hacer comienza n u merador den omin ador escribir 'El resultado de la división es ',cociente leer numerador leer denominador termina cociente ← • Calcula la productoria de los N primeros números naturales. leer N {N>0} Productoria ← 1 Cantidad ← 1 mientras Cantidad ≤ N hacer comienza Productoria ← Productoria ∗ Cantidad Cantidad ← Cantidad + 1 termina escribir ' el producto de los primeros', N , 'números naturales es', Productoria Variables de uso particular Usted habrá observado que en los distintos algoritmos de la suma, como en el de la Productoria utilizamos variables que "acumulan" valores, como así también utilizamos otras que "cuentan". Estas variables se denominan Acumulador y Contador respectivamente. Sus nombres conceptuales indican la función que cumplen en un algoritmo. Obviamente estas deberán inicializarse en el momento oportuno. Hay otra variable que tiene un comportamiento particular, y se utiliza con mucha frecuencia en todo tipo de algoritmo. Se trata de la "marca", también conocida como "llave", "flag", "bandera", "switch" o cualquier término que signifique indicador. Marca: variable cuyos valores son indicadores de situaciones particulares Ejemplos: • El siguiente algoritmo lee un día y la presión correspondiente y determina el día en que se registró la mínima presión, imprimiendo ambos resultados. marca ← verdadero mientras haya datos hacer comienza leer día, presión si marca entonces comienza dia_min ← día mínimo ← presión APUNTES TEÓRICOS - 11 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación marca ← falso termina sino si presión < mínimo entonces comienza dia_min ← día mínimo ← presión termina termina escribir 'El día ',dia_min, ' se registró la mínima presión de ',mínimo,' hectopascales.' En este caso la marca toma el valor verdadero para el primer par de datos que se necesita como punto de comparación. APUNTES TEÓRICOS - 12 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación • El siguiente algoritmo lee un número y determina si es primo o no divisor ← 2 primo ← verdadero leer numero mientras primo ∧ (divisor < n u mero ) hacer Dejamos al lector el análisis del objetivo de la marca primo. n u mero si * divisor = numero entonces primo ← falso divisor sino divisor ← divisor + 1 escribir numero si primo entonces 'es primo' sino 'no es primo' Consistencia En todos los procesos es imprescindible que la información que ingresa sea consistente, es decir válida con respecto al dato que representa; corresponde al programa de ingreso de datos dicha verificación. Consistencia: proceso de verificación de la validez de la información que ingresa. • Calcula el factorial de un número entero positivo. leer número { a continuación consistimos el valor de numero, que debe ser mayor o igual que cero} mientras número < 0 hacer comienza escribir 'Dato no válido' escribir 'Ingrese otro número' leer número termina { número es mayor o igual que cero }{precondición para el factorial} factorial ← 1 genera ← 1 mientras genera ≤ número hacer comienza factorial ← factorial ∗ genera genera ← genera + 1 termina escribir 'el factorial de ' , número, 'es', factorial { factorial contiene el factorial de número} { postcondición del factorial } • Ingresa nº_alumno, edad, peso, estatura. Finaliza cuando nº_alumno es cero. leer nº_alumno, edad, peso , estatura mientras nº_alumno ≠ 0 hacer comienza { controla la edad} mientras (edad < 17 ) ∨ (edad > 110) hacer APUNTES TEÓRICOS - 13 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación comienza escribir 'Dato no válido' escribir 'Ingrese otra edad' leer edad termina { controla el peso} mientras (peso < 30 ) ∨ (peso > 100) hacer comienza escribir 'Dato no válido' escribir 'Ingrese otro peso' leer peso termina { controla la estatura} mientras (estatura < 1,40 ) ∨ (estatura > 2,10) hacer comienza escribir 'Dato no válido' escribir 'Ingrese otra estatura' leer estatura termina escribir nº_alumno, edad, peso , estatura leer nº_alumno, edad, peso , estatura termina Estructura General de un Programa Hasta el momento hemos trabajado con los algoritmos, sin dar ninguna especificación acerca de las variables que intervienen en él. Dentro de las premisas a respetar en la programación estructurada, está la de presentar las definiciones y/o declaraciones según un orden preestablecido. A saber: Programa <nombre> Constantes { lista de constantes que utilizaremos en el programa} Tipos {lista de tipos no estándares que utilizaremos en el programa} Variables { lista de variables, con su tipo, que utilizaremos en el programa} Procedimientos y/o Funciones {módulos que utilizaremos en el programa} comienza {el programa principal} { lista de enunciados del programa} termina { el programa principal } Donde: <nombre> es el identificador del programa { lista de constantes que utilizaremos en el programa} es la lista de identificadores cuyo contenido no se modifica el la ejecución del programa; Ejemplos: pi=3.14159 mi_nombre='patricia' mi_fecha_nac='30/02/21' días_año_98= 365 APUNTES TEÓRICOS - 14 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación { lista de tipos que utilizaremos en el programa} es la lista de tipos que define cada programador según sus necesidades. Ejemplos: par = (0,1) días_semana=(lun, mar, mier, jue, vie, sab, dom) útiles =(lápiz, goma, cuaderno, regla, birome) natural=1.maximo_entero negativo = -maximo_entero..-1 { lista de variables que utilizaremos en el programa} es la lista de los identificadores de las variables globales del programa. Variable global: aquella cuyo alcance de utilización es tanto el programa principal, como los módulos contenidos en él. módulos contenidos en el programa son las unidades en las que dividimos el problema, y que luego del ejemplo veremos detalladamente. El siguiente programa lee e imprime el número combinatorio de "m" elementos tomados de a "n", finalizando el ingreso de datos cuando m = n, y ambos sean cero. El rango de valores que pueden tomar es de cero a cincuenta. Ejemplo Programa combinatorio Constantes Cátedra = 'Lógica y Programación' Año_curso='1997' Tipos intervalo = 0..50 Variables válido : lógico m , n: intervalo m_aux, n_aux, mn_aux : intervalo m_fac, n_fac, mn_fac : real mn_dif : intervalo combi : real comienza {programa Principal} repetir valido ← falso leer m, n { hago consistencia de los datos } mientras no válido hacer si (m < n) ∨ (m < 0) ∨ (n < 0) entonces leer m,n sino válido ← verdadero { los datos son válidos } { calculo el factorial de m } m_aux←1 m_fac ← 1 mientras m_aux ≤ m hacer comienza m_fac←m_fac ∗ m_aux m_aux ← m_aux + 1 termina { calculo el factorial de n } APUNTES TEÓRICOS - 15 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación n_aux←1 n_fac ← 1 mientras n_aux ≤ m hacer comienza n_fac←n_fac ∗ n_aux n_aux ← n_aux + 1 termina { calculo el factorial de m-n } mn_dif ← m - n mn_aux←1 mn_fac ← 1 mientras mn_aux ≤ mn_dif hacer comienza mn_fac←mn_fac ∗ mn_aux mn_aux ← mn_aux + 1 { calculo el número combinatorio e imprimo el resultado } combi← m_fac/n_fac/mn_fac escribir 'la combinación de ', m, 'tomados de a ', n, 'es ', combi hasta (m=n) ∧ (m=0) termina {programa Principal} Obsérvese que, dentro del programa, ha sido necesario repetir en tres oportunidades el segmento de código utilizado para calcular el factorial de un número: n!, m! y (m-n)!. Esto puede simplificarse re-escribiendo el programa de la siguiente forma: Programa combinatorio Constantes Cátedra='Lógica y Programación' Año_curso='1997’ Tipos intervalo=0..50 Variables m,n:intervalo m_fac, n_fac, mn_fac : real mn_dif : intervalo combi : real funcion factorial (numero: entero): entero Variables num_aux : intervalo num_fac: real { número ≥ 0 } comienza num_aux ←1 num_fac ← 1 mientras num_aux ≤ numero hacer comienza num_fac ← num_fac ∗ num_aux num_aux ← num_aux + 1 termina factorial ← num_fac { asigno el resultado a la función } { factorial contiene el factorial de numero } termina { fin funcion factorial } procedimiento leo_controlo(ref m, n: intervalo) Variables valido: lógico APUNTES TEÓRICOS - 16 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación comienza valido ← falso leer m, n { hago consistencia de los datos } mientras no válido hacer si (m < n) ∨ (m < 0) ∨ (n < 0) entonces leer m,n sino válido ← verdadero termina { fin procedimiento leer_valores } { m y n son válidos } comienza {programa Principal} repetir leo_y_controlo(m,n) m_fac ← factorial(m) n_fac ← factorial(n) mn_dif ← m - n mn_fac ← factorial(mn_dif) { calculo el número combinatorio e imprimo el resultado } combi ← m_fac/n_fac/mn_fac escribir 'la combinación de ', m, 'tomados de a ', n, 'es ', combi hasta (m=n) ∧ (m=0) termina {programa Principal} Como puede observarse, en este último ejemplo hemos resuelto la repetición de código que se presentaba en el ejemplo anterior mediante el uso de una función que calcula el factorial de un número. Bastó con definir sólo una vez la función, y luego invocarla las veces necesarias con los diferentes argumentos de los cuales se quería conocer el factorial. También podrá observarse el uso de un procedimiento para leer y controlar la información. Ese control es la consistencia de la misma. Teniendo en cuenta este comportamiento, podemos definir: función: bloque de instrucciones cuyo objetivo es devolver al módulo que la invoca, un valor de un tipo predefinido. La función genera una dirección de memoria asociada a su identificador, y el valor que ésta produce, se almacena en esa dirección. procedimiento: bloque de instrucciones al que se invoca para producir un valor, más de uno o ninguno. Estos valores son referenciados por el módulo llamador. Un procedimiento o una función puede ser llamado desde el programa principal o desde otro procedimiento o función. Una de las diferencias conceptuales entre función y procedimiento está dada por su forma de invocación: Una función puede invocarse indistintamente desde una Incorrecto sentencia de impresión, de asignación y desde un condicional, teniendo en cuenta que nunca puede invocarse en forma directa. • factorial(n) En nuestro ejemplo: Correcto • leer factorial(n) • n_fac ← factorial(n) • mientras factorial(numero) > 1 hacer ... Un procedimiento, por otro lado, debe invocarse en forma directa, es decir, mediante una sentencia de procedimiento, la que consta del nombre del mismo y de los parámetros actuales. Ejemplo: Correcto Incorrecto leer_valores(n,m) x ← leer_valores(n,m) APUNTES TEÓRICOS - 17 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Veremos que la interacción entre los módulos se realiza a través de argumentos ó parámetros, los que contienen ó referencian las direcciones de los valores de comunicación entre los módulos. En la sentencia de invocación están los parámetros actuales, los cuales se corresponden con una dirección de memoria. En el encabezamiento de función o procedimiento están los parámetros formales. A su vez, estos pueden ser parámetros valor y por referencia. Parámetro formal: identificador con tipo, en función del cual se define el procedimiento ó función Ejemplo En la función factorial, <número> es el parámetro formal. En leo_y_controlo, los parámetros formales son <m> y <n> Los parámetros formales son los utilizados en la declaración del procedimiento, y son llamados también ficticios, porque no tienen posiciones de memoria asignadas sino hasta la invocación del procedimiento. Parámetro actual: identificador de variable utilizado en la invocación del procedimiento ó función, siendo dicha variable global al módulo que se llama. Ejemplo Al llamar a factorial cada vez, lo hacemos usando una variable global: m, n, mn_dif ; las tres son el parámetro actual en cada llamado. El identificador de los parámetros formales es independiente del identificador de los actuales, por lo tanto, pueden ser iguales ó distintos. Lo que sí debe respetarse es el orden, número y tipo. Ejemplo Sea el siguiente encabezamiento de procedimiento: ⇒ Procedimiento pepe( ref ola:real; ref katre:entero; titulo:cadena) ola, katre y título son parámetros formales. Ahora bien, supongamos que invoco a pepe de la siguiente manera: ⇒ pepe( dato, valor, encabezamiento). dato debe ser una variable real. valor debe ser una variable entera encabezamiento debe ser una variable cadena. Bajo estas definiciones, no puedo llamar a pepe así: ⇒ pepe(encabezamiento, dato, valor) Veamos ahora la diferencia conceptual entre parámetro valor y parámetro por referencia, parámetro valor : es aquel cuyo contenido no se modifica al ejecutarse el módulo invocado, ya que éste utiliza una copia del contenido de la dirección de memoria correspondiente. El parámetro valor actual puede ser una constante. parámetro por referencia: es aquel cuyo contenido puede inicializarse ó modificarse al ejecutarse el módulo invocado. Esto ocurre pues el módulo trabaja con la dirección de memoria del parámetro actual correspondiente, y el p. formal hace referencia a esa dirección. El actual debe ser siempre una variable. APUNTES TEÓRICOS - 18 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Otra diferencia entre función y procedimiento está dada por la cantidad de parámetros que devuelven al módulo llamador: Una función devuelve un único valor contenido en la dirección asociada al identificador de la función, mientras que un procedimiento puede devolver uno, ninguno o más de un valor. Si fuera el caso en el que un procedimiento devuelve un valor o más, esto último está contenido en la dirección de los parámetros actuales correspondientes. Ejemplos: • El siguiente procedimiento imprime títulos y totales: Procedimiento Impresión(Total_ventas:real, Num_Emp,Cant_ventas:entero, Premio:real) Variables bonif:real {en esta variable calculo la bonificación por las ventas} comienza escribir'El total de ventas del empleado ',Num_Emp, 'es ', Total_ventas, '$' escribir'Las unidades vendidas fueron', Cant_ventas bonif ← (Total_ventas ∗ Premio)/100 escribir 'Su Premio por ventas realizadas es', bonif ,'$' termina Obsérvese que este procedimiento no referencia ninguna dirección al módulo que lo llamó. Todos los parámetros formales que utiliza son por valor. La siguiente es una sentencia de procedimiento que llama a Impresión. { en el bloque anterior a este llamado, se calculó el total de las ventas y se contaron las unidades de las mismas; asimismo, se leyó el porcentaje de bonificación que le corresponde} Impresión(Ventas, Nro_Emp, Unidades, Porcentaje) • El siguiente procedimiento lee y controla los coeficientes de un polinomio de tercer grado. Procedimiento leo_controlo(ref a1,a2,a3,a4:real) comienza leer a1,a2,a3,a4 mientras a1 = 0 hacer comienza escribir 'dato no válido', 'ingrese a1' leer a1 termina termina Obsérvese que este módulo produce 4(cuatro) valores, y a él no ingresa ningún valor desde el módulo que lo invocó; es decir, que los parámetros formales que necesita son sólo por referencia. La siguiente es una sentencia de procedimiento que lo invoca. leo_controlo(c1 , c2 , c3,, c4) • El siguiente procedimiento actualiza la fecha, si ésta es anterior al 31/12/2000. Procedimiento Actualizo( ref día: día_válido, ref mes:mes_válido, año:año_válido) { considero que está definido el tipo día_válido, mes_válido y año_válido y que el procedimiento consistir controla que los valores que ingresan estén en el rango permitido para día, mes y año} constantes año_hoy=2000 Variables día_hoy: día_válido mes_hoy: mes_válido comienza si año < año_hoy entonces APUNTES TEÓRICOS - 19 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación comienza leer día_hoy, mes_hoy consistir (día_hoy, mes_hoy) año ← año_hoy mes ← mes_hoy día ← día_hoy termina termina Actualizo (día, mes, año) En este caso, si al invocar Actualizo los contenidos son: [día]=15 [mes]=1 [año]=2000, entonces el procedimiento no produce ningún cambio, y las variables conservan su contenido. En cambio, si los contenidos son: [día]=15 [mes]=10 zará los contenidos de las variables, pasando éstas a ser: [día]=25 [mes]=7 (esto fue impreso el 25/7/2000) [año]=94, entonces el procedimiento actuali[año]=2000 NÚMEROS ALEATORIOS En el mundo real, ocurren sucesos determinados, todos los días, como por ejemplo levantarnos, higienizarnos, desayunar, salir de la casa al trabajo, al estudio o a cualquier otro evento previamente conocido. Y puede ocurrir que esa mañana estemos con fiebre, malestar por algún virus presente en nuestro organismo, o también puede ocurrir que estemos muy bien y al querer higienizarnos descubramos que no está la pasta dentífrica, o desapareció el cepillo de dientes, o el peine, o ...... También puede ocurrir que después de levantarnos perfectamente y de higienizarnos sin inconvenientes, al preparar el desayuno descubramos que cortaron el gas , o que no hay más yerba, o mate, etc. Etc. En síntesis, aún frente a sucesos determinados, es probable que ocurran otros no previstos. Los primeros corresponden a los sucesos determinísticos, y los segundos a los sucesos aleatorios. Un suceso es determinístico cuando la probabilidad de que ocurra es del 100%, es decir que hay certeza de que ocurra. Mientras que un suceso es aleatorio en caso contrario. A estos fenómenos comúnmente se les dice al azar. Veamos a continuación ejemplos de ambos fenómenos. DETERMINÍSTICO ALEATORIO Todos los días tengo hambre Que me contagie una gripe en una reunión de amigos, en la que alguien está afectado Se rompe un plato de porcelana cuando lo tiro al piso Pongo un vaso en el borde de la mesada. La probabilidad de que se rompa es del 50 % (*) Se rompe un vidrio de una ventana cuando le Cae un plato al piso. La probabilidad de que tiran una piedra con fuerza se rompa es de 60 % (**) Choco al auto que va delante de mí al frenar y descubrir que los frenos están rotos La probabilidad de que los frenos estén rotos es del 10/00 Es mi cumpleaños y lo festejaré con mis amigos Hay un 30% de probabilidad de que en mi cumpleaños tenga que viajar a Bs. As. APUNTES TEÓRICOS - 20 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación El segundo parcial es el 4 de noviembre El 15 de octubre a las 23.30 se desató un huracán en la Patagonia (*) Esta probabilidad depende de los movimientos que haya en la cocina, de la edad de los que se movilizan en ella, y de la torpeza en su desplazamiento. Si en la cocina hay niños, seguramente esa probabilidad aumente, y si hay adolescentes, tal vez se convierta en un suceso determinístico (**) Esta probabilidad depende de la calidad, la forma y el material del plato. Ahora bien, qué tiene que ver este concepto con la informática. Ocurre que con frecuencia tendremos que manejar dicho concepto, ya sea para simular un fenómeno, para acceder aleatoriamente a un elemento, para generar números aleatorios, etc. Etc. .Como concepto, pertenece a la rama Estadística de la Matemática Aplicada, por lo que en ella lo estudiarán con profundidad. Generalmente se utilizan recursos azarosos para asignar probabilidades a un suceso, por ejemplo: • La probabilidad de que salga cara en la moneda es 0.50, y se usa dicho lanzamiento para asignar probabilidad de esa magnitud. • La probabilidad de que salga un as en el dado es 1/6, por lo que se usa dicho lanzamiento para asignar probabilidad de esa magnitud. • La probabilidad de que salga un caballo de espada es 1/42 (contando los comodines es un mazo común) por lo que se usa dicha extracción para asignar probabilidad de esa magnitud. Nosotros simplemente definiremos una función matemática que permite generar números aleatorios uniformemente distribuídos (es decir que tienen la misma probabilidad de salir). Esta función es recurrente, y se define así: xi = F(x i-1) donde x0 es el valor inicial, llamado semilla y x0 ≥ 0 A su vez, se necesitan otros parámetros, cuyo fundamento matemático escapa del dominio de este desarrollo, y simplemente los definiremos y aplicaremos. Estos son: a multiplicador (a ≥ 0) c incremento (c ≥ 0) m módulo (m > x0, m > a , m > 0) La función con la que nosotros trabajaremos para definir una sucesión de números aleatorios es: x n+1 = ( axn + c ) mod m , donde mod es el operador matemático entero módulo p que definimos en el Anexo Matemático. Esta fórmula produce números enteros entre 0 y m. Supongamos que elegimos arbitrariamente x0 = 3, a = 7, c = 5 y m = 10 La sucesión sería: 3 6 7 4 que se repite cíclicamente. Nosotros elegiremos el valor m = 2 15 = 32768 c puede ser nulo a debe ser de un orden de magnitud comparable con m, y también hay una teoría de “mejor elección” que está fuera de nuestro dominio de conocimiento Así, la fórmula con incremento nulo será: x n+1 = axn mod m Para obtener la tabla de números aleatorios uniformemete distribuídos (ri) , se divide xn por m - obteniéndose números reales entre 0 y 1Los lenguajes de programación de alto nivel, tienen incorporada dicha función, denominada RANDOM. Nosotros la definiremos en seudocódigo. APUNTES TEÓRICOS - 21 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Cadenas • DEFINICIÓN Una cadena es una secuencia finita de caracteres alfanuméricos, el primero de los cuales es alfabético, y se caracteriza por tener una longitud. La longitud de una cadena es el número de caracteres que posee. • DECLARACIÓN DE VARIABLES DE TIPO CADENA La declaración de variables de tipo cadena se realiza de manera similar a la de otros tipos, indicando el nombre de la variable, el tipo predefinido (cadena) y la longitud máxima de caracteres que podrá contener. tipos palabra: cadena(40) variables encabezamiento, titulo: palabra • OPERACIONES Existen varias operaciones predefinidas para su uso con cadenas. Concatenación: Acción por la que se obtiene una cadena formada por la yuxtaposición de los caracteres de los operandos cadenas. El símbolo operador es el +. Ejemplo: texto ‘Juan’ + ‘consulta’ + ‘ dudas’ da como resultado la cadena ‘ Juan consulta dudas’ en la variable texto. parrafo encabezamiento + ‘ ‘ + titulo da como resultado la cadena ‘Primer Parcial 30/02/2050’ en la variable parrafo, si la variable encabezamiento contiene ’Primer Parcial’ y titulo contiene ’30/02/2050’ Funciones: LONG(cadena): devuelve la longitud de la cadena. Ejemplos: variable cadena contenido sentencia de asignación pali ‘pepe’ longi titulo ‘Día del libro’ longi long(titulo) encabeza ‘Primer Parcial’ long(pali) resultado: variable contenido entera longi 4 longi 13 canti_letras long(titulo) canti_letras 14 CADENA(número): devuelve una cadena que contiene el número que le fue pasado como parámetro a la función, pero en formato alfanumérico. APUNTES TEÓRICOS - 22 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación variable tipo contenido sentencia de asignación edad entero 18 cad_edad precio entero 75 cad_precio densidad real cad_densi 12.356 cadena(edad) cadena(precio) variable resultado(tipo cadena) cad_edad ‘18’ cad_precio ‘75’ contenido cadena(densidad) cad_densi ’12.356’ NUMERO(cadena): devuelve el valor numérico de la cadena. Si la cadena contiene caracteres no numéricos, la función devuelve 0. variable tipo contenido sentencia de asignación numero(titu1) variable resultado titu1 cadena ‘18’ edad titu2 cadena ‘75’ precio titu3 cadena ‘12.356’ densidad numero(titu3) densidad titu4 cadena ‘resultados’ valor numero(titu4) numero(titu2) tipo contenido edad entero 18 precio entero 75 valor real 12.356 entero 0 SUBCADENA(cadena,posición,long): devuelve una cadena formada por “long” cantidad de caracteres tomados de “cadena” a partir de “posición” variable contenido cadena titu1 ‘telecomunicaciones’ pal Subcadena(titu1,5,14) variable resultado contenido (tipo cadena) pal ‘comunicaciones’ titu2 ‘empapado’ pal Subcadena("titu2",3,4) pal ‘papa’ cad_ num ‘12.356’ p_entera p_entera ‘12’ cad_ num ‘12.356’ p_decimal sentencia de asignación Subcadena(cad_num, 1, 2) Subcadena(cad_num, 4, 3) p_decimal ‘356’ BUSCAR(cadena_fuente,cadena): devuelve la posición a partir de la cual se encuentra “cadena” dentro de “cadena_fuente”. Si “cadena” no es una subcadena de “cadena_fuente”, la función devuelve el valor 0. APUNTES TEÓRICOS - 23 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación titu1 ‘tengo hambre’ posi buscar(titu1,’hambre’) variable resultado(tipo entero) posi titu2 ‘este ejemplo’ lugar lugar 6 cad_num ‘12.356’ l_punto buscar(cad_num, ‘.’) l_punto 3 l_punto buscar(cad_precio,’.’) l_punto 0 variable cadena contenido cad_precio ‘$123,56’ sentencia de asignación buscar(titu2, ‘ejem’) contenido 7 Procedimientos: INSERTAR(cadena, ref cadena_fuente,posición): inserta “cadena” a partir de “posición” en “cadena_fuente”. Ejemplo: Insertar(’García’, nombre,6) si [nombre]=‘José Rodríguez’, esta variable pasa a ser ‘José García Rodríguez’ Insertar(’no ‘, frase ,4,) si [frase] = ‘Yo soy un estudiante’, luego de Insertar queda [frase]=‘Yo no soy un estudiante’ BORRAR(ref cadena_fuente,posición_ini,cant): borra ‘cant’ cantidad de caracteres de ‘cadena_fuente’ a partir de ‘posición_ini’. procedure Delete(var S: String; Index: Integer; Count:Integer); Ejemplo: Borrar( comic,5,3) si [comic]= ‘Picapiedra’, después de Borrar queda [comic]= ‘Picadra’ Borrar(título,1,14) si [título]= ‘Algorítmica y programación’ después de Borrar queda [título]= ‘programación’ Comparación de Cadenas: Las cadenas pueden compararse haciendo uso de los operadores de comparación y se admiten las siguientes alternativas: = (igual) Dos cadenas son iguales cuando cada elemento de ambas cadenas coincide. nombre = ‘Alberto’ será verdadero cuando nombre esté definido como cadena de siete o más caracteres y contenga el texto ‘Alberto’ <> (distinto) APUNTES TEÓRICOS - 24 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Una cadena es distinta de otra cuando al menos uno de sus caracteres lo es. ‘z’ <> ‘Zeta’ es verdadero, ‘PC’ <> ‘PC ‘ es verdadero (porque posee un espacio), ‘hola’ <> ‘HOLA’ es verdadero, porque las letras mayúsculas son distintas de las minúsculas. Cuando dos cadenas comiencen igual, el primer carácter distinto es el que decidirá sobre el valor de certeza de la comparación (por menor o mayor). < (menor) Una cadena es menor que otra cuando los caracteres que la componen son ‘menores’ (ordinalmente hablando) que los de la segunda. ‘a’ < ‘b’ es verdadero, ‘Z’ < ‘A’ es falso; ‘programación’ < ‘programar’ es verdadero. > (mayor) Una cadena es mayor que otra cuando los caracteres que la componen son ‘mayores’ (ordinalmente hablando) que los de la segunda ‘c’ > ‘b’ es verdadero, ‘F’ > ‘Z’ es falso; ‘programar’ > ‘programador’ es verdadero ‘papel’ < ‘papelon’ es verdadero APLICACIÓN A CADENAS DE NÚMEROS: Dígito Verificador Todos los sistemas de información se basan en el uso de una clave única de acceso a la misma, la cual debe tener un comportamiento biunívoco, es decir, para determinada información hay una única clave de acceso a ésta, y esa clave permite acceder sólo a dicha información. Por ejemplo: ⌦ El número del Documento Nacional de Identidad ⌦ El número de cuenta de una Caja de Ahorros ⌦ El número de cuenta de una Cuenta Corriente ⌦ El número de afiliación a una AFJP ⌦ El CUIL ⌦ El CUIT Y podríamos seguir mencionando cientos de claves que pueden ser por Ud. conocida. ¿ Alguna vez se preguntó qué pasa si se equivoca al escribir uno de los dígitos de cualquiera de esas claves? ¿ y si está en un sistema computarizado, y pulsa una tecla errónea? ¿Qué pasa?. Para ello existe el Dígito verificador. Éste se integra a la clave, como un último dígito, a continuación de una barra ( / ), y es lo que permite detectar algún error en el ingreso de los dígitos de la clave. Ud. se preguntará qué pasa si uno se equivoca en más de un dígito. En estos casos la probabilidad de detección del error es muy alta, y depende del procedimiento elegido para generar el dígito verificador. ¿ Cómo se integra este dígito a la clave ? Al darse el alta a cualquier clave del sistema, se aplica el procedimiento a la misma, y se concatena el resultado en la posición n+1 de la clave. A partir de ese momento, sea cual fuere la operación que se realice en el sistema, el usuario ingresa los n+1 dígitos. El programa calcula el procedimiento con los n dígitos de la clave, y verifica que coincida el resultado con el n+1 ingresado. En caso afirmativo, acepta la clave ingresada; sino, emite un mensaje. Veamos a continuación, uno de los tantos algoritmos de obtención del Dígito Verificador. Sea la siguiente distribución de dígitos, de una clave compuesta por 8: posición 1 2 3 4 5 6 7 8 clave 1 1 3 7 2 2 0 1 Paso 1 Paso 2 1 + 7 9 + 2 + 1 =11 11 x 3 =33 APUNTES TEÓRICOS - 25 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Paso 3 1 + 3 + 2 Paso 4 + 0 =6 33 + 6 =39 Paso 5 DV=1 Procedimiento: La posición de los dígitos que conforman un código pueden ser numerados de izquierda a derecha, de modo que el dígito verificador ocupa el último lugar (n+1). Los pasos para calcular el dígito verificador son los siguientes: 1. Comenzando desde la posición 2 del número, sume todos los dígitos que se encuentran en posiciones pares. 2. Multiplique el resultado por 3. 3. Comenzando desde la posición 1 del número, sume las posiciones impares. 4. Sume el resultado del paso 2 al del paso 3 5. El dígito verificador es el número más pequeño que, sumado al valor del paso cuatro, da como resultado un múltiplo de 10. En nuestro ejemplo, la clave quedará formada como: 11372201/1 Apliquemos nuestro procedimiento a otras claves: Clave original 15830824 23456735 12456779 13457558 33455648 Clave con dígito verificador 1 5 8 3 0 8 2 4/9 2 3 4 5 6 7 3 5/5 1 2 4 5 6 7 7 9/3 1 3 4 5 7 5 5 8/0 3 3 4 5 5 6 4 8/8 RECURSIÓN Habrá podido observar que al definir la función factorial, utilizamos la variable num_fac para generar la productoria, y luego asignarla a <factorial>, y tal vez se habrá preguntado por qué no se usó el identificador factorial directamente. Esto se debe a una propiedad, llamada recursión (ó recursividad), que permite que todo módulo -bajo ciertas condiciones-, se invoque a sí mismo. Tiene un uso muy frecuente en la programación de funciones matemáticas, que de por sí son recursivas, como la función factorial conocida. Veamos cómo se define ésta matemáticamente: X! = x * (x-1)! 1 si x > 0 si x = 0 Respondiendo a ese modelo, podemos definir : función fact(x:entero) : entero comienza si x = o entonces fact ← 1 fact ← x * fact(x - 1) sino termina Nótese que la escritura del seudocódigo de la función es análoga a la definición del factorial. En particular, esta propiedad se aplica cuando el modelo a programar es recursivo. La recursión debe ser finita, es decir, debe haber por lo menos una salida no-recursiva del procedimiento o función. En el caso anterior, se produce cuando x=0. En Estructuras de Datos y Algoritmos veremos Recursión con mayor profundidad. APUNTES TEÓRICOS - 26 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Tipos estructurados Cuando definimos estructuras de datos pudimos observar que existen tipos simples estándares y tipos estructurados o compuestos. Hasta ahora nos hemos manejado con tipos simples (entero, real, carácter, etc.), pero su utilización no es apropiada para la resolución de ciertos tipos de problemas. Es por esto que existe la posibilidad de definir y utilizar tipos estructurados, entre los que se encuentran los arreglos, registros, cadenas, archivos, y otros que veremos oportunamente. Arreglos En muchas ocasiones necesitamos agrupar variables que almacenen datos de un mismo tipo. Supongamos, por ejemplo, que deseamos registrar la temperatura promedio mensual durante un año en la ciudad de Comodoro Rivadavia. Si utilizáramos los tipos de datos que conocemos hasta ahora, necesitaríamos declarar 12 variables reales distintas, una por cada mes, para almacenar dicha información. Es útil poder contar con alguna estructura que nos permita agrupar estos datos bajo un mismo nombre, y acceder individualmente a cada uno de ellos. Esta estructura existe, y se denomina arreglo. Arreglo: conjunto de celdas unidireccionables, las que almacenan elementos de un único tipo. Se puede acceder directamente a cada una mediante su posición en el arreglo, la que está determinada por el o los índices Los arreglos se clasifican en dos grupos: • unidimensionales (llamados también vectores): poseen una única dimensión, es decir, cada posición es accesible mediante un único índice. En nuestro ejemplo de las temperaturas promedio, necesitaríamos indicar sólo el mes para obtener la temperatura promedio del mismo. • multidimensionales (por ejemplo, las matrices): poseen más de una dimensión, lo que equivale a decir que cada elemento dentro de ellos se direcciona mediante dos o más índices. Las matrices son un caso particular de los arreglos multidimensionales, pues poseen 2 dimensiones. Para ilustrar este concepto, consideremos ahora la necesidad de registrar las temperaturas promedio mensuales de los últimos 4 años. Podríamos utilizar una tabla como la que sigue: Ene Feb Mar Abr May Jun Jul Ago Sep Oct Nov Dic 1994 1995 1996 1997 Para acceder a un dato de esta tabla necesitamos especificar el año y el mes, es decir, necesitamos dos índices. El ejemplo anterior responde a una definición bidimensional (matriz), pero podríamos necesitar arreglos de más de dos dimensiones, como en el siguiente caso: deseamos mantener la información de las temperaturas promedio mensuales de los últimos 3 años por provincia. En este caso necesitamos un arreglo tridimensional, al cual se acceda mediante 3 índices: provincia, año y mes, Como conclusión podemos destacar que si bien en esta asignatura sólo utilizaremos arreglos unidimensionales y bidimensionales, es posible definirlos n-dimensionales. APUNTES TEÓRICOS - 27 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Arreglos Unidimensionales: Vectores • DECLARACIÓN DE UN TIPO VECTOR Para poder utilizar una variable de tipo vector es necesario declarar este tipo en la sección de declaración de tipos del programa y luego declarar la variable como de ese tipo. La declaración del tipo se realiza de la siguiente forma: Tipos <identificador_de_tipo> = Arreglo (n) de <tipo_elemento> donde <identificador_de_tipo> es el nombre que se asigna al tipo y n es la cantidad de elementos del tipo <tipo_elemento> que puede contener el arreglo. Cabe aclarar que <tipo_elemento> puede ser cualquier estructura de dato (simple o compuesta) Ejemplo: Tipos VEC_ENT = arreglo(100) de enteros En este caso hemos declarado un tipo denominado VEC_ENT que define un arreglo unidimensional de 100 elementos de tipo entero. • DECLARACIÓN DE VARIABLES DE UN TIPO VECTOR Variables <identificador_de_variable>:<tipo_vector> donde <identificador_de_variable> es el nombre que se desea asignar a la variable y <tipo_vector> es el identificador del tipo definido previamente. Ejemplo: Tipos VEC_REAL = arreglo(12) de reales Variables VECTOR_TEMPERATURAS : VEC_REAL El acceso a una componente determinada del vector se realiza indicando el nombre de la variable acompañado de un subíndice encerrado entre paréntesis, el cual indicará la posición dentro del vector. VECTOR_TEMPERATURAS 29.5 28.0 27.9 22.6 15.2 14.1 12.9 9.7 14.4 18.6 23.1 31.4 1 2 3 4 5 6 7 8 9 10 11 12 INDICE En nuestro ejemplo, si queremos hacer referencia a la temperatura de Abril y suponiendo que cada posición de VECTOR_TEMPERATURAS almacena la temperatura del mes cuyo número corresponde con el índice, usamos la notación: VECTOR_TEMPERATURAS(4) Si queremos asignar una nueva temperatura al mes de Diciembre, que se almacena en la posición 12 del vector, expresamos: VECTOR_TEMPERATURAS(12) ← 31.4 • OPERACIONES SOBRE VECTORES Lectura: equivale a leer cada una de las componentes del vector individualmente. APUNTES TEÓRICOS - 28 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Ejemplo: Procedimiento LEO_VECTOR ( N:entero; ref VEC : VEC_REAL ) Variables i:entero Comienza para i ← 1 hasta N hacer leer VEC(i) Termina Impresión: equivale a imprimir cada una de las componentes del vector en forma individual. Procedimiento IMP_VECTOR (N:entero; VEC:VEC_REAL) Variables i:entero Comienza para i ← 1 hasta N hacer escribir VEC(i) Termina Procesamiento de un vector: veamos algunos ejemplos de procesamiento de vectores. Ejemplo 1: Procedimiento CUENTA_NULOS (N:entero; VEC:VEC_REAL; ref CANT:entero) { Este procedimiento cuenta la cantidad de componentes nulas que tiene el vector y la almacena en CANT } Variables i : entero Comienza CANT ← 0 para i ← 1 hasta N hacer si VEC(i) = 0 entonces CANT ← CANT+1 Termina Ejemplo 2: Procedimiento MAX_MIN (N:entero; VEC:VEC_REAL; ref Pos_MAX, Pos_MIN: entero) { Este procedimiento obtiene la posición de los valores máximo y mínimo de un vector, } Variables i : entero Comienza POS_MAX ← 1 POS_MIN ← 1 para i ← 2 hasta N hacer { comenzamos con la segunda componente del vector porque la primera es utilizada para asignar el valor inicial a Pos_MIN y a Pos_MAX } si VEC(i) < VEC(POS_MIN ) entonces POS_MIN ← i sino si VEC(i) > VEC(POS_MAX) entonces POS_MAX ← i APUNTES TEÓRICOS - 29 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Termina Ejemplo 3: Procedimiento GENERA_VECTOR (N:entero; REF VEC: VEC_REAL) {El siguiente procedimiento almacena en cada componente del vector la raíz cuadrada de un valor leído} Variables VALOR, i : entero Comienza para i ← 1 hasta N hacer Comienza leer VALOR VEC(i) ← Termina VALOR Termina Importante: es necesario distinguir entre lectura y generación de vectores. Cuando se lee un vector los valores que corresponden a cada componente del vector han sido ingresados como componentes de un vector Si no es así, el vector es generado con valores de variables de un uso particular. ORDENAMIENTO Y BÚSQUEDA SOBRE VECTORES Ordenar un vector significa reubicar sus componentes de tal forma que se cumpla alguna relación de orden (menor < , menor ó igual ≤, mayor >, mayor ó igual ≥ ) entre todas sus componentes. En diversas aplicaciones se necesita tener ordenadas las componentes del vector según algún criterio (en forma ascendente o descendente), por lo que veremos a continuación varios métodos utilizados para tal fin. Consideraremos en todos los casos una ordenación ascendente, pero es muy sencillo adaptar los métodos para otro criterio de ordenación. 1.- Método de Ordenamiento por Selección Este método buscar el menor elemento del vector y lo coloca en la primera posición; luego el menor entre los restantes -del vector- y lo ubica en la segunda posición, y así sucesivamente hasta llegar a un vector de dimensión 1 Los pasos para ordenar un vector aplicando este método se pueden esquematizar así: 1. Buscar el menor elemento entre los n que componen el vector. 2. Intercambiar dicho elemento con el que se encuentra en la 1º posición. 3. Encontrar el elemento mínimo entre los n-1 restantes, e intercambiarlo con el que se encuentre en la posición 2. 4. Repetir este proceso con los n-2 elementos restantes, y así sucesivamente hasta que el proceso se realice entre 1 componente del vector. Veamos a continuación cómo se transforma el vector X= 36 24 10 6 12 Posiciones inicial Mínimo 1 2 3 4 5 36 24 10 6 12 APUNTES TEÓRICOS - 30 - 6 ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Primera iteración 6 24 10 36 12 10 Segunda iteración 6 10 24 36 12 12 Tercera iteración 6 10 12 36 24 24 Cuarta iteración 6 10 12 24 36 A partir del vector inicial obtenemos el mínimo elemento que es 6 y está en la 4º posición; en la primera iteración lo intercambiamos con el elemento que se encuentra en la 1º posición. De los 4 elementos restantes, obtenemos el menor, que es 10 y se encuentra en la 3º posición. Lo intercambiamos en la segunda iteración con el elemento de la posición 2. Así continuamos hasta que el vector esté ordenado. Para simplificar la codificación del algorítmo utilizaremos una función que calcula la posición del mínimo elemento de un vector. Función Posi_Mínimo (VEC_LOCAL:VEC_ENTERO; N,POSI_PRIM: entero) : entero {Calcula la posición del mínimo elemento de un vector VEC_LOCAL de N elementos} Variables i, i_min: entero Comienza i_min ← POSI_PRIM para i ← POSI_PRIM + 1 hasta N hacer si VEC_LOCAL(i) < VEC_LOCAL(i_min) entonces i_min ← i Posi_Mínimo ← i_min Termina El siguiente algoritmo nos permite aplicar el método de selección a un vector: Procedimiento Seleccion (ref VEC:VEC_ENTERO; DIM:entero) { DIM es la cantidad de elementos del vector } Variables i,posi_min,auxiliar: entero Comienza para i ← 1 hasta DIM - 1 hacer Comienza posi_min ← Posi_Mínimo(VEC, DIM, i ) auxiliar ← VEC(i) VEC(i) ← VEC(posi_min) VEC(posi_min) ← auxiliar Termina Termina 2.- Método de Ordenamiento BURBUJA Este método se basa en el principio de comparar pares de componentes contiguas e intercambiarlas entre sí, si fuera necesario, hasta que estén todas ordenadas. Podría decirse que los valores mayores “burbujean” hasta el final de la lista, y los pequeños se “hunden” hacia el principio de la lista. Consideremos un ejemplo concreto en el que ordenaremos un vector de 5 posiciones: Posiciones 1 2 3 4 5 inicial 36 24 10 6 12 Primera iteración 24 10 6 12 36 Segunda iteración 10 6 12 24 36 APUNTES TEÓRICOS - 31 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Tercera iteración 6 10 12 24 36 Cuarta iteración 6 10 12 24 36 En la primera iteración se comparan VEC(1)=36 y VEC(2)=24. Como 36 > 24 se intercambian entre sí. Luego se comparan VEC(2)=36 y VEC(3)=10. Al ser 36 > 10, nuevamente se intercambian. El proceso continua en forma similar hasta realizar todas las comparaciones. Se observa que al final de la primera iteración el elemento 36 “burbujeó” hasta el final del vector. Se incluyeron en el gráfico todas las iteraciones para que el lector pueda realizar el seguimiento de este método de ordenación. El algoritmo para ordenar mediante el método de burbuja es el siguiente: Procedimiento Burbuja1 (ref VEC:VEC_ENTERO; DIM:entero) { DIM es la cantidad de elementos del vector } Variables i,j,aux: entero Comienza para i ← 1 hasta DIM hacer para j ← 1 hasta DIM - i hacer si VEC(j) > VEC(j+1) entonces { deben intercambiarse los elementos } comienza aux ← VEC(j) VEC(j) ← VEC(j+1) VEC(j+1) ← aux termina Termina Obsérvese que si en una iteración no se realizan intercambios, significa que el vector ya está ordenado. Podríamos desear interrumpir las iteraciones si se verifica la condición descrita. A continuación se presenta una versión del algortimo de ordenamiento burbuja que testea si se realizaron intercambios o no para saber si el vector ya está ordenado y de esta manera no continuar el proceso. Procedimiento Burbuja2( ref VEC:VEC_ENTERO; DIM:entero) { DIM es la cantidad de elementos del vector } Variables i,tope,aux: entero cambio: lógico Comienza tope ← DIM cambio ← verdadero mientras tope > 1 ∧ cambio hacer comienza cambio ← falso para i ← 1 hasta tope -1 hacer si VEC(j) > VEC(j+1) entonces { deben intercambiarse los elementos } comienza aux ← VEC(j) VEC(j) ← VEC(j+1) VEC(j+1) ← aux cambio ← verdadero termina tope ← tope -1 termina Termina APUNTES TEÓRICOS - 32 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación 3.- Método de Ordenamiento por Inserción. Este método de ordenamiento se basa en comparaciones y desplazamientos sucesivos. Cada elemento del vector es insertado en el lugar correspondiente respecto a los otros elementos ya ordenados. Inicialmente se ordenan los dos primeros elementos. Luego, se compara el tercer elemento con los ya ordenados para buscar la posición que le corresponda respecto a los mismos. Si fuese necesario, se desplazan los elementos posteriores hacia la derecha para liberar la posición del vector donde se insertará el elemento considerado. Se repite esta operación con todos lo elementos restantes. A continuación aplicaremos el método a nuestro vector: Posiciones 1 2 3 4 5 inicial 36 24 10 6 12 Primera iteración 24 36 10 6 12 Segunda iteración 10 24 36 6 12 Tercera iteración 6 10 24 36 12 Cuarta iteración 6 10 12 24 36 En la primera iteración se comparan VEC(1)=36 y VEC(2)=24. Como 36 > 24, se intercambian. En la segunda iteración se considera VEC(3)=10, y al compararlo con los dos elementos ya ordenados, se encuentra que debe ubicarse en la primer posición del vector. Se desplazan un lugar a la derecha los elementos que se encuentran en las dos primeras posiciones para liberar la posición 1, donde se ubica el 10. En la tercera iteración comparamos VEC(4)=6 con los tres anteriores, ya ordenados. Encontramos que, por ser menor que 10, debería colocarse en la 1º posición. Entonces desplazamos los elementos 10, 24 y 36 una posición a la derecha para poder hacerlo. Siguiendo el razonamiento anterior, VEC(5)=12 debe ubicarse entre el 10 y el 24, por lo que desplazamos el 24 y el 36 un lugar a la derecha para colocar el 12. El algoritmo que nos permite ordenar un vector mediante este método es el siguiente: Procedimiento Inserción (ref VEC:VEC_ENTERO; DIM:entero) Variables i,j,k,aux:entero Comienza si VEC(1) > VEC(2) entonces comienza aux ← VEC(1) VEC(1) ← VEC(2) VEC(2) ← aux termina para i ← 3 hasta DIM hacer comienza k←1 mientras VEC(k) < VEC(i) ∧ k < i hacer k←k+1 aux ← VEC(i) para j ← i decremento k + 1 hacer VEC(j) ← VEC(j - 1) APUNTES TEÓRICOS - 33 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación VEC(k) ← aux termina Termina 4.- Método de Ordenamiento De a Pares El principio de este método es el siguiente: se toman los elementos de las posiciones 1 y 2 del vector y se los ordena, colocando el mayor de ellos en la posición 2. Luego se repite el procedimiento con los elementos de las posiciones 3 y 4, 5 y 6, etc. Una vez recorrido todo el vector aplicando el proceso descrito, se realiza la misma operación comenzando con el par de elementos de las posiciones 2 y 3, luego 4 y 5, etc. Se continúan aplicando estos dos procesos en forma alternada hasta que el vector esté ordenado. Posiciones 1 2 3 4 5 inicial 36 24 10 6 12 Primera iteración 24 36 6 10 12 Segunda iteración 24 6 36 10 12 Tercera iteración 6 24 10 36 12 Cuarta iteración 6 10 12 24 36 Para saber si el vector ya está ordenado, utilizamos una marca que indica si se produjeron cambios. Si no los hubo, el vector ya está ordenado. Procedimiento Ordena_Pares (ref VEC: VEC_ENTERO; DIM: entero) Variables hay_cambio, primera_vez: lógico posi_comienzo, i, AUX: entero Comienza primera_vez ← verdadero hay_cambio ← verdadero posi_comienzo ← 1 mientras hay_cambio ∨ primera_vez hacer comienza hay_cambio ← falso i ← posi_comienzo mientras i < DIM hacer comienza si VEC(i) > VEC(i+1) entonces comienza aux ← VEC(i) VEC(i) ← VEC(i+1) VEC(i+1) ← aux hay_cambio ← verdadero termina i ← i+2 termina si posi_comienzo = 1 entonces posi_comienzo ← 2 APUNTES TEÓRICOS - 34 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación sino comienza posi_comienzo ← 1 primera_vez ← falso termina termina Termina 5.- Método de Ordenamiento de la Sacudida El principio de este método es el mismo que el del ordenamiento BURBUJA, con la diferencia que el límite de comparación, en lugar de ir decrementándose en 1 en cada iteración, se fija en la posición del vector donde se realizó el último cambio, evitando comparaciones sobre elementos ya ordenados. Posiciones Límite 1 2 3 4 5 inicial 36 24 10 6 12 Primera iteración 24 10 6 12 36 5 Segunda iteración 10 6 12 24 36 4 Tercera iteración 6 10 12 24 36 2 Cuarta iteración 6 10 12 24 36 En el ejemplo se observa que hasta la segunda iteración el comportamiento del método de ordenamiento es similar al burbuja, pero en la tercera pude verse la diferencia: el límite superior (tope) no se decrementa en uno, sino que contiene la posición del último elemento que fue intercambiado. Procedimiento Sacudida (ref VEC:VEC_ENTERO; DIM:entero) { DIM es la cantidad de elementos del vector } Variables i,tope,aux,posi: entero cambio: lógico Comienza tope ← DIM posi ← 1 cambio ← verdadero mientras tope > 1 ∧ cambio hacer comienza cambio ← falso para j ← 1 hasta tope -1 hacer si VEC(j) > VEC(j+1) entonces { deben intercambiarse los elementos } comienza { y registrarse el nuevo límite } aux ← VEC(j) VEC(j) ← VEC(j+1) VEC(j+1) ← aux cambio ← verdadero posi ← j termina tope ← posi termina Termina APUNTES TEÓRICOS - 35 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación 6.- Método de Ordenamiento Shell Este método se basa en comparar pares de elementos que se encuentren almacenados en posiciones separadas por una distancia D, y se los intercambia, si fuera necesario, para su ordenamiento. En la primera iteración, D=(N+1)/2, con lo cual se comparan el elemento ubicado en la posición I con el que está en la posición I+D, con 1 ≤ I < D. En las sucesivas iteraciones, se redefine D como (D+1)/2 (la mitad del D anterior). Como siempre se está comparando el elemento I con el I+D, en cada redefinición de D se incrementa la cantidad de comparaciones al doble. Cuando D es 1, el método se convierte en burbuja. Posiciones 1 2 3 4 5 6 7 8 9 inicial 36 24 10 6 12 31 33 40 45 Primera iteración D=5 31 24 10 6 12 36 33 40 45 Segunda iteración D=3 6 12 10 31 24 36 33 40 45 Tercera iteración D=2 6 12 10 31 24 36 33 40 45 Cuarta iteración 6 10 12 24 31 33 36 40 45 D=1 En el ejemplo propuesto arriba, se observa que en la primera iteración, con D=5 porque (N+1)/2 = (9 + 1)/2 = 5, se comparan los elementos que se encuentran en las posiciones 1 y 6 y se los intercambia, porque 31 < 36. Luego se comparan los elementos de las posiciones 2 y 7, 3 y 8, y 4 y 9, y se intercambian si es necesario. En la segunda iteración D = (D+1)/2 = (5+1)/2 = 3. Se sigue entonces idéntico procedimiento que en la primera iteración, tomando ahora los pares de posiciones (1,4), (2,5), (3,6), (4,7), (5,8) y (6,9), comparándolos e intercambiándolos cuando sea el caso. En la tercera iteración D=2, y en la cuarta 1, con lo que equivale al método burbuja. Procedimiento Shell (ref VEC : VEC_ENTERO ; DIM:entero) Variables D,i,aux:entero Comienza D ← [(DIM+1)/2] mientras D > 1 hacer comienza para i ← 1 hasta DIM-D hacer si VEC(i) > VEC(i+D) entonces comienza aux ← VEC(i) VEC(i) ← VEC(i+D) VEC(i+D) ← aux termina D ← [(D+1)/2] termina Burbuja(VEC, DIM) Termina BÚSQUEDA En muchas aplicaciones es necesario buscar un elemento dentro de una determinada estructura de datos (vector, matriz, archivo, etc.). Puede resultar que en la búsqueda encontremos dicho elemento, pudiendo indicar dónde, o que no lo encontremos. APUNTES TEÓRICOS - 36 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación De acuerdo a las características de la búsqueda, podemos diferenciar dos métodos: ♦ Búsqueda lineal: consiste en recorrer secuencialmente la estructura de datos a partir del primer ele- mento y comparar cada elemento con el buscado hasta encontrarlo o hasta que no queden elementos para comparar. Si ocurre este último caso, la búsqueda ha terminado sin éxito. ♦ Búsqueda binaria: generalmente mucho más rápido que el anterior, este método requiere que la estruc- tura de datos sobre la que se realizará la búsqueda se encuentre ordenada. Compara el elemento buscado con el el elemento central de la estructura . Si el elemento buscado coincide con el elemento central, se termina la búsqueda. Si el elemento buscado es menor que el central, se considera la primera mitad de la estructura, y se ubica el elemento central de dicha mitad, y se lo compara con el buscado. Se repite este proceso hasta que se encuentra el elemento buscado o hasta que no queden más elementos por comparar. Ejemplo: búsqueda lineal sobre un vector no ordenado Procedimiento Buscar (VEC:VEC_ENTERO; ELEMENTO,DIM:entero; ref POSI:entero) { POSI contendrá la posición del vector en la que se encontró el elemento buscado -ELEMENTO- o 0 si no se encontró } Variables i:entero Comienza POSI ← 0 i←1 mientras (POSI = 0) y (i ≤ DIM) hacer si VEC(i) = ELEMENTO entonces POSI ← i sino i ← i+1 Termina Ejemplo: búsqueda lineal sobre un vector ordenado La eficiencia de la búsqueda lineal puede mejorar si se realiza sobre un vector ordenado, porque sólo será necesario recorrer el vector hasta la posición donde se encuentre el elemento buscado o uno mayor a éste. Procedimiento Buscar (VEC:VEC_ENTERO; ELEMENTO,DIM:entero; ref POSI:entero) { POSI contendrá la posición del vector en la que se encontró el elemento buscado -ELEMENTO- o 0 si no se encontró. El vector está ordenado } Variables i:entero Comienza POSI ← 0 i←0 terminado ← falso mientras (i ≤ DIM) y no terminado hacer comienza i←i+1 si VEC(i) = ELEMENTO entonces comienza APUNTES TEÓRICOS - 37 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación POSI ← i terminado ← verdadero termina sino si VEC(i) > ELEMENTO entonces comienza terminado ← verdadero POSI ← 0 termina termina Termina Ejemplo: búsqueda binaria Procedimiento Busqueda_binaria (VEC:VEC_ENTERO; ELEMENTO,DIM:entero; ref POSI:entero) { POSI contendrá la posición del vector en la que se encontró el elemento buscado -ELEMENTO- o 0 si no se encontró. VEC está ordenado de menor a mayor } Variables inicial, final, punto_medio:entero encontrado: lógico Comienza inicial ← 1 final ← DIM encontrado ← falso POSI ← 0 { si el elemento no se encuentra, posi ya está en 0 } mientras inicial ≤ final ∧ no encontrado hacer comienza punto_medio ← [(inicial + final)/2] si VEC(punto_medio) = ELEMENTO entonces comienza POSI ← punto_medio encontrado ← verdadero termina sino si VEC(punto_medio) > ELEMENTO entonces final ← punto_medio -1 { el elemento está en la 1º mitad } sino inicial ← punto_medio + 1 { el elemento está en la 2º mitad } termina Termina Inicialmente, punto_medio es la posición central del vector (Inicial=1 , Final=DIM). Si el elemento buscado es mayor que el correspondiante a la posición de punto_medio, se fija Inicial como la posición siguiente a punto_medio (se descarta la primer mitad del vector). Si por el contrario, el elemento buscado es menor que de la posición de punto_medio, se toma como Final la posición anterior a punto_medio, desechándose la segunda mitad del vector. El nuevo punto medio es la posición central del vector comprendido entre las posiciones Inicial y Final. Si al comparar el elemento de la posición punto_medio con el buscado encontramos que ambos coinciden, ha finalizado la búsqueda de manera exitosa. Cuando la posición inicial es mayor que la final significa que el elemento buscado no se encuentra dentro del vector. APUNTES TEÓRICOS - 38 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Arreglos Bidimensionales : Matrices Una matriz es un tipo de datos estructurado, un caso particular de arreglos multidimensionales. Está formada por una colección finita de elementos, todos del mismo tipo ordenados en dos dimensiones. Para acceder a cada componente de la matriz se utilizan dos índices, el primero referencia la posición del elemento en la primera dimensión (filas) y el segundo índice se refiere a la posición del elemento en la segunda dimensión (columnas). • DEFINICIÓN DE UN TIPO MATRIZ Para poder utilizar una variable de tipo matriz es necesario declarar este tipo en la sección de declaración de tipos del programa y luego declarar la variable como de ese tipo. La declaración del tipo se realiza de la siguiente forma: Tipos <identificador_de_tipo> = Arreglo (m,n) de <tipo_elemento> donde: • <identificador_de_tipo> es el nombre que se asigna al tipo, • m es la cantidad de elementos de <tipo_elemento> que puede contener cada fila del arreglo, • n es la cantidad de elementos de <tipo_elemento> que puede contener cada columna del arreglo. Cabe aclarar que <tipo_elemento> puede ser cualquier estructura de dato (simple o compuesta) ⇒ Ejemplo: Tipos MAT_ENT = arreglo(3,5) de enteros En este caso hemos declarado un tipo denominado MAT_ENT que define un arreglo bidimensional de 3 filas por 5 columnas de elementos de tipo entero. • DECLARACIÓN DE VARIABLES DE UN TIPO MATRIZ Variables <identificador_de_variable>:<tipo_matriz> donde <identificador_de_variable> es el nombre que se desea asignar a la variable y <tipo_matriz> es el identificador del tipo definido previamente. ⇒ Ejemplo: Tipos MAT_REAL = arreglo(4, 12) de reales MAT_ENTERO = arreglo(5, 12) de enteros Variables MATRIZ_TEMPERATURAS: MAT_REAL El acceso a una componente determinada de la matriz se realiza indicando el nombre de la variable acompañado de dos subíndices encerrados entre paréntesis, que indicarán la fila y la columna que determinan la posición del dato dentro de la matriz. Indices 1 2 3 4 1 2 3 4 5 6 7 8 9 10 11 12 29.5 32.4 31.8 33.7 28.0 29.2 26.6 28.8 27.9 26.9 25.7 26.3 21.6 23.5 22.8 20.1 11.5 13.4 15.2 14.9 14.1 13.8 14.2 14.1 11.8 10.9 13.1 11.2 5.7 6.3 6.2 6.1 14.4 12.3 13.8 12.8 18.6 19.7 14.6 13.3 23.1 22.4 23.8 22.3 34.6 32.5 31.4 32.1 Ene Feb Mar Abr May Jun Jul Ago Set Oct Nov Dic APUNTES TEÓRICOS - 39 - 1994 1995 1996 1997 ALGORITMICA Y PROGRAMACIÓN Elementos de Programación En nuestro ejemplo, cada posición de la Matriz MATRIZ_TEMPERATURAS almacena la temperatura promedio del mes y año cuyos números se corresponden con los índices. Si queremos hacer referencia a la temperatura de Junio del año 1995, usamos la notación: MATRIZ_TEMPERATURAS(2,6) Si queremos asignar una nueva temperatura al mes de Octubre de 1996, que se almacena en la posición (3,10) de la matriz, expresamos: MATRIZ_TEMPERATURAS(3,10) ← 20.4 • OPERACIONES SOBRE MATRICES ⌦ Lectura: lee cada una de las componentes de la matriz individualmente. Ejemplo: Procedimiento LEO_MATRIZ ( M,N:entero; ref MAT:MAT_REAL ) Variables i, j:entero Comienza para i ← 1 hasta M hacer para j ← 1 hasta N hacer leer MAT(i, j) Termina ⌦ Impresión: imprime cada una de las componentes del vector en forma individual. Procedimiento IMP_MATRIZ (M,N:entero; MAT:MAT_REAL) Variables i, j:entero Comienza para i ← 1 hasta M hacer para j ← 1 hasta N hacer escribir MAT(i, j) Termina ⌦ Impresión detallada: imprime literalmente cada una de las componentes del vector (cadena identificatoria y contenido, por fila) Procedimiento IMP2_MATRIZ (M,N:entero; MAT:MAT_REAL) Variables i, j:entero Comienza para i ← 1 hasta M hacer comienza para j ← 1 hasta N hacer escribir ’matriz(‘, i, ‘,’,j,’)=‘, MAT(i, j) APUNTES TEÓRICOS - 40 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación escribirlínea termina Termina Supongamos que queremos imprimir una matriz de 5 x 4; con este procedimiento saldría impreso de la siguiente manera: matriz(1,1)= 2.3 matriz(2,1)=-2.43 matriz(3,1)= 12.8 matriz(4,1)= 31.3 matriz(5,1)= 11.8 ⌦ matriz(1,2)= 4.8 matriz(2,2)= 5.7 matriz(3,2)= -2.7 matriz(4,2)= 4.8 matriz(5,2)= - 5.4 matriz(1,3)= 2.53 matriz(2,3)= 4.3 matriz(3,3)= -2.8 matriz(4,3)= 46.7 matriz(5,3)= 12.9 matriz(1,4)= 5.4 matriz(2,4)= 7.38 matriz(3,4)= 12.9 matriz(4,4)= 32.8 matriz(5,4)= 12.6 Procesamiento de una matriz: veamos algunos ejemplos de procesamiento de matrices. Ejemplo 1: Procedimiento SUMA_FILAS (M,N:entero; MAT:MAT_REAL; ref VEC_SUMA:VEC_REAL) { Este procedimiento suma los elementos de cada fila de la matriz y almacena los resultados en VEC_SUMA, que es un vector de M componentes } Variables i, j, Sum: entero Comienza para i ← 1 hasta M hacer Comienza Sum ← 0 para j ← 1 hasta N hacer Sum ← Sum+ MAT(i, j) VEC_SUMA (i) ← Sum Termina Termina Ejemplo 2: Procedimiento MAX_MIN (M,N:entero; MAT:MAT_REAL; ref MAX, MIN:real) { Este procedimiento obtiene los valores máximo y mínimo de una matriz, almacenándolos en MAX y MIN, respectivamente } Variables i, j : entero Comienza MAX ← MAT(1,1) MIN ← MAT(1,1) para i ← 1 hasta M hacer para j ← 1 hasta N hacer si MAT(i, j) < MIN entonces MIN ← MAT(i, j) sino si MAT(i, j) > MAX entonces MAX ← MAT(i, j) Termina Ejemplo 3: APUNTES TEÓRICOS - 41 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Procedimiento GENERA_MATRIZ (M, N:entero; REF MAT: MAT_ENTERO) { El siguiente procedimiento almacena en cada fila de la matriz nro_legajo, cod_asignatura y el promedio de las notas leidas} Variables i, nro_legajo, cod_asignatura: entero nota_1er_cuatrim, nota_2do_cuatrim: entero Comienza para i ← 1 hasta M hacer Comienza leer nro_legajo, nota_1er_cuatrim, nota_2do_cuatrim MAT(i,1) ← nro_legajo MAT(i,2) ← cod_asignatura MAT(i,3) ← [(nota_1er_cuatrim + nota_2do_cuatrim) / 2] Termina Termina Importante: es necesario distinguir entre lectura y generación de matrices. Cuando se lee una matriz, los valores que corresponden a cada componente de la misma han sido ingresados directamente como valores matriciales; en caso contrario, utilizamos la matriz como soporte de la información para procesarla y ésta es generada así. • ORDENAMIENTO SOBRE MATRICES Ordenar una matriz significa reubicar sus componentes de tal forma que se cumpla alguna relación de orden (menor < , menor ó igual ≤, mayor >, mayor ó igual ≥ ) entre sus componentes. El ordenamiento de los elementos de una matriz se realiza teniendo en cuenta una columna J en particular; para ello se debe tener en cuenta que la comparación será de los elementos de la columna J en las diferentes filas. Si debe realizarse una permuta, ésta debe efectuarse por completo en las filas correspondientes. Procedimiento para ordenar una matriz por columnas: Como en el caso de los vectores, consideraremos en todos los casos una ordenación ascendente, pero es muy sencillo adaptar los métodos para una ordenación descendente. Supongamos que COL es la columna según la cual ordenaremos la matriz. El procedimiento Burbuja a aplicar es el siguiente: Procedimiento ORDEN_MAT1 (M, N, COL: entero, ref A: MAT_ENTERO) Variables: i, j, Tope: entero Aux: entero Cambio: Lógico Comienza Tope ← N repetir cambio ← falso Para i ← 1 hasta Tope - 1 Hacer Si A( i, COL) > A( i+1, COL) Entonces Comienza Cambio ← Verdadero Para J ←1 hasta M Hacer Comienza APUNTES TEÓRICOS - 42 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Aux ← A( i, j) A(i, j) ← A(i+1, j) A(i+1, j) ← Aux Termina Termina Tope ← Tope-1 hasta Tope = 1 ∨ no cambio Termina Observaciones: Tener en cuenta que si la matriz posee elementos repetidos, se debe utilizar una segunda columna de ordenamiento.Si es previsible dicha situación, debemos conocer otra columna COL2. Utilizamos para ello el siguiente algoritmo: Procedimiento ORDEN_MAT2 (M, N, COL, COL2: entero, ref A: MAT_ENTERO) Variables: i, j, Tope: entero Aux: entero Cambio: Lógico Comienza Tope ← N Cambio ← Verdadero repetir Cambio ← Falso Para i ← 1 hasta Tope - 1 Hacer Si A(i,COL) ≥ A(i+1,COL) ∨ A (i,COL2) > A(i+1,COL2)) Entonces Comienza Cambio ← Verdadero Para J ←1 hasta M Hacer Comienza Aux ← A( i, j) A(i, j) ← A(i+1, j) A(i+1, j) ← Aux Termina Termina Tope ← Tope-1 hasta tope = 1 v no cambio Termina • BUSQUEDA SOBRE MATRICES Para realizar una búsqueda en una matriz, también consideramos una columna determinada. Podemos utilizar tanto la búsqueda secuencial como la binaria, teniendo en cuenta que para esta última, la matriz debe estar ordenada por la columna de búsqueda. Veremos a continuación un ejemplo de búsqueda binaria en una matriz, considerando una columna COL. Procedimiento BuscoEnMat (MAT:MAT_ENTERO; N,M,COL,Buscado:entero; ref NFil:entero) { NFil contendrá en nro. de fila de la matriz en la que se encontró el elemento buscado dentro de la columna COL; si es 0 significa que el elemento no se encontró} Variables PI, PF, Medio: entero Encontrado: lógico Comienza APUNTES TEÓRICOS - 43 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación NFil ← 0 Encontrado ← Falso PI ← 1 PF ← M mientras PI ≤ PF ^ no encontrado hacer comienza Medio ← [(PI + PF) / 2] si MAT(Medio, Col) = Buscado entonces comienza NFil ← Medio encontrado ← verdadero termina sino si MAT(Medio, Col) > Buscado entonces PF ← Medio - 1 sino PI ← Medio + 1 termina termina Aplicación de cadenas y arreglos en seguridad de la Información: Encriptado En el anexo de Seguridad de la Información, hemos visto el concepto de la misma, como así también, cómo la Criptología pretende resolver los problemas de seguridad en la comunicación dedatos. En nuestra materia, simplemente veremos un método sencillo de encriptar un vector, y cómo desencriptarlo: En primer lugar, haremos una matriz de correspondencia entre pares de caracteres: A B C D E F G H I J K L M N O P Q R S C w J e M V A b O a c f Z E d B g k I T U V W X Y Z a b c d e f g h i j k l x L j p T h F i K N l D m S n G o Y W m n o p q r s t u v w x y z . , ; U q ; H v y R . z r P s , t u Q X ≠ 1 2 3 4 5 6 7 8 9 0 * / & # @ + < > ^ % Si quisiéramos encriptar el siguiente mensaje: Nuestra cita informática virtual la haremos en el Jardín Japonés, a las 7 p.m., bajo la madreselva en flor. Aplicando nuestra tabla de transformación quedará: APUNTES TEÓRICOS - 44 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación EzDR.yi≠NG.i≠Gqm;yUi.GNi≠rGy.ziW≠Wi≠niyDU;R≠Dq≠DW≠aiyl Gq≠aiH;qDRQ≠i≠WiR≠<≠HuUuQ≠Kio;≠Wi≠UiIyDRDWri≠Dq≠mW;yu. El que quiera traducirlo, deberá usar esa tabla en el sentido contrario. Dejamos para la clase práctica el desarrollo del algoritmo. REGISTROS Es oportuno aclarar que hasta ahora todas las operaciones realizadas sobre un conjunto de datos, imponían la condición necesaria de homogeneidad de la estructura utilizada para contener a dichos datos. ¿Qué sucede si, dadas las características del problema, necesitamos de una estructura de datos cuyo contenido sea no homogéneo ? Es así que aparece el tipo de dato registro, el cual tiene la característica de permitir identificar unívocamente un conjunto de datos que pueden ser de tipos diferentes (carácter, entero, real, etc.) Un registro se compone de campos, en los que se almacena la información no homogénea, cada campo se asocia a un identificador - identificador de campo -, y cada registro tiene su identificador identificador de registro-. Se puede manipular el registro completo para una asignación, o lectura/grabación en un archivo, pero en general vamos a necesitar operar con los campos de un registro. En este caso, el acceso a cada campo tiene el siguiente formato: <identificador_de_registro > “.” <identificador de campo> Sea la siguiente declaración de una variable persona Variable persona: registro nombre:cadena(20) edad:entero ocupación:cadena(25) salario:real fin registro La descripción de este registro será: Registro Persona Identificador del campo Tipo del campo Nombre Edad Ocupación Salario cadena(20) entero cadena(25) real Si quiero asignarle un valor al nombre, pondré: persona.nombre ← ‘Juan Ignacio Perez’ Si quiero leer su salario, pondré leer persona.salario Los siguientes ejemplos ilustran cómo definir los tipos y cómo manipular la información de los campos: Ejemplo1: Tipos TipoRegistro = registro Campo1: TipoDato1 Campo2: TipoDato2 FinRegistro Variables VariableRegistro : TipoRegistro variable1: TipoDato1 APUNTES TEÓRICOS - 45 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación variable2: TipoDato2 Comienza ..... ..... Leer(variable1) Leer(variable2) { si queremos asignar los datos a los campos del registro hacemos } VariableRegistro . Campo1 ← variable1 VariableRegistro . Campo2 ← variable2 ...... Termina No podríamos realizar las siguientes operaciones: • Leer(VariableRegistro) { no se puede leer un registro completo} • VariableRegistro . Campo1 ← variable2 { los tipos de datos no son iguales} El tipo de los campos puede ser estructurado, por lo que su acceso depende de la estructura a la que pertenece. Veamos los siguientes ejemplos: Tipos TipoRegistroA = registro CampoA1 TipoDato1 CampoA2: TipoDato2 FinRegistro TipoRegistro = registro Campo1: TipoRegistroA Campo2: entero FinRegistro Variables VariableRegistro : TipoRegistro variable1: TipoDato1 variable2: TipoDato2 Comienza ........ { para escribir el campo A1 de la variable VariableRegistro deberemos hacer} Escribir (VariableRegistro . Campo1 . CampoA1) ........ Termina Es necesario destacar que la elección de uso de cualquier estructura está directamente relacionada con el problema que estamos modelando y la información que queremos representar. Podemos agrupar registros por medio de un arreglo, el cual puede ser de cualquier tipo simple de datos (entero, real, caracter, etc. ) o tipos compuestos (registros. arreglos) Teniendo en cuenta la declaración de tipo anterior y nuevas variables veremos como manipular un arreglo de registros. Tipos TipoRegistro = registro Campo1: TipoDato1 Campo2: TipoDato2 FinRegistro Variables VariableRegistro : TipoRegistro ArregloRegistro: arreglo (30) de TipoRegistro APUNTES TEÓRICOS - 46 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Comienza ...... i ← 1 { quiero acceder a la posición 1 del arreglo } VariableRegistro ← ArregloRegistro ( i ) { accedo a la información de un registro} { si ahora quiero mostrar el primer campo de la 5 posición del arreglo de registros} Escribir (ArregloRegistro(5).Campo1) ...... Termina Supongamos que queremos almacenar información del personal de la Facultad. Primero debemos definir qué estructura utilizaremos para contener la información. Una elección posible podría ser: Tipos RegistroPersona = Registro Nombre : cadena (20) Edad : entero Ocupacion : cadena (25) Salario :real FinRegistro Variables Yo : RegistroPersona Facultad : Arreglo (30) de RegistroPersona { permite mantener información de 30 personas} ARCHIVOS Hasta aquí hemos manipulado datos (información) en variables de tipos de datos simples y tipos estructurados. Estos tipos de variables se almacenan en memoria RAM, y por la volatilidad de la misma, no podemos mantener información permanentemente. Introduciendo un nuevo tipo, el tipo archivo, podemos solucionar el problema de almacenamiento de información. Una variable de tipo archivo se caracteriza por contener una secuencia de elementos de un tipo base, que pueden ser registros o cualquier otro tipo simple. Así, cada elemento integrante de la secuencia posee todas las propiedades y características de éstos. Es conveniente destacar ahora los aspectos de manipulación lógica y física. El manejo lógico es el que realizamos nosotros mediante programas que mantienen la información del archivo. El aspecto físico es independiente de lo que nosotros realicemos en nuestros programas, ya que todos los sistemas operativos donde se ejecutarán nuestros programas cuentan con una parte (el sistema de archivos) que se encarga de operaciones transparentes para nosotros (tales como obtener espacio en disco o cinta para el archivo, almacenar bit a bit, etc.). El acceso a la información de un archivo puede hacerse en forma secuencial ó directa. Nosotros sólo utilizaremos el acceso secuencial, ya que lógicamente un archivo es una secuencia de registros y no es recomendable violar esta propiedad. Tal vez no esté clara esta recomendación sobre la forma de acceso, pero se puede comprobar cuando se intenta modificar o detectar un error en un algoritmo. Las características lógicas de un archivo que debemos destacar son: 1. Existe una posición actual del archivo. Ésto significa que cualquier operación que se realice a un registro del archivo se materializará sobre el registro que es apuntado por esta posición actual. 2. El archivo posee una marca de fin-de-archivo, que nos permite identificar si hemos llegado al final. Antes de enumerar las operaciones y los métodos que se aplican sobre archivos declaremos un tipo archivo, un tipo registro, y las variables que necesitaremos para la descripción de los ejemplos: Tipos APUNTES TEÓRICOS - 47 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación RegistroPersona = Registro Nombre : cadena (20) Edad : entero Estado_Civil: carácter Salario :real FinRegistro ArchivoPersona = archivo de RegistroPersona Variables Profesor : RegistroPersona Facultad : ArchivoPersona { permite mantener información del personal de la Facultad} Operaciones sobre archivos ⇒ ABRIR: Esta operación debe ser usada previamente a cualquier otra, para preparar la utilización del archivo. Para Lectura: Esta operación se utiliza cuando el archivo ya está creado y se desea acceder a la información que se encuentra en él. Para Escritura: Esta operación se utiliza cuando el archivo no existe y se necesita crearlo para grabar información en él. Es necesario aclarar el tipo de apertura del archivo. Ejemplo Abrir (Facultad ) {Para lectura} {se abre un archivo existente} Abrir (Facultad) {Para escritura} { se abre un archivo que no existe} ⇒ CERRAR: Se utiliza esta operación siempre que se termina de procesar la información de un archivo que ha sido abierto ya sea para lectura o para escritura. Ejemplo Cerrar (Facultad) {se cierra el archivo que se abrió previamente} CUALQUIER ACCESO QUE SE PRETENDA REALIZAR SOBRE UN ARCHIVO CERRADO SERÁ NO VÁLIDO ⇒ LEER: Se utiliza para leer el registro del archivo que se encuentra bajo el indicador de posición actual descrito anteriormente. Esta lectura colocará el contenido de un registro del archivo en una variable tipo registro que se deberá declarar para tal fin. Es importante aclarar que con cada realización de la operación Leer, el indicador de posición actual se irá modificando hasta avanzar hacia el fin-de-archivo. Ejemplo Leer(Facultad, Profesor) { coloca en la variable Profesor información de un registro del archivo Facultad} ⇒ GRABAR: Se utiliza para agregar un registro en el archivo, colocando la información la variable registro en un registro del archivo. Aclaramos que con cada operación Grabar que se realiza, se irá modificando la marca de fin-de-archivo. Ejemplo Grabar(Facultad, Profesor) { agrega información de la variable profesor en el archivo Facul- tad } ⇒ FIN: Es necesario utilizar esta operación para detectar el fin del archivo para saber si debemos continuar procesando información de un archivo. Es operación devuelve un valor booleano, esto es verdadero o falso. Ejemplo APUNTES TEÓRICOS - 48 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Fin(Facultad) { esta operación devolverá verdadero o falso, dependiendo de si el indicador de posición actual esta sobre la marca de fin-de-archivo del archivo Facultad} Recursos para manipular archivos Previo a describir los recursos para el uso de archivos debemos declarar algunas variables del tipo estructurado que hemos visto con anterioridad. Estas (que se encuentran en memoria de acceso directo obviamente) servirán para ordenar, realizar búsquedas sobre un archivo, etc. El tipo estructurado que emplearemos es el arreglo unidimensional (un vector), donde cada elemento de éste será un registro que contendrá la información de cada registro lógico del archivo que estemos procesando. Esta “duplicación de información” es necesaria para evitar realizar múltiples operaciones Abrir y Cerrar sobre un archivo. También se hace para que el acceso a la información que se encuentra en el archivo sea mas rápida, y nos permita realizar acceso directo a la misma, algo que ya dijimos que no es recomendable en un archivo. Tipos RegistroPersona = Registro Nombre : cadena (20) Edad : entero Estado_Civil : cadena (25) Salario :real FinRegistro ArchivoPersona = archivo de RegistroPersona { información en dispositivo de almacenamiento secundario} VectorPersona = arreglo (100) de RegistroPersona { información en memoria de acceso directo} Variables Profesor : RegistroPersona Facultad : ArchivoPersona { permite mantener información del personal de la Facultad} InfoFacultad : VectorPersona Bajar un archivo: la información de un archivo -existente en almacenamiento secundario (disco, cinta, etc.)- se almacena en una variable del tipo estructurado. Procedimiento BajarArchivo ( ref Facu : ArchivoPersona, ref InfoFacu : VectorPersona, ref CantPersonas : entero ) Variables Regi:RegistroPersona I:entero Comienza I 0 { inicialmente suponemos que no existe información en el archivo} Abrir (Facu) {Para lectura} Mientras no Fin(Facu) Hacer Comienza I I+1 Leer (Facu, Regi) InfoFacu (I) Regi { coloco en la posición I-esima del vector la información del registro leído} Termina CantPersonas I { tenemos i-elementos en el vector de registros} Cerrar (Facu) Termina APUNTES TEÓRICOS - 49 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Subir un archivo: se graba la información desde memoria central en un archivo que se encuentra en almacenamiento secundario. Procedimiento SubirArchivo( ref Facu : ArchivoPersona, InfoFacu : VectorPersona, CantPersonas : entero ) Variables Regi:RegistroPersona I:entero Comienza Abrir (Facu) {Para escritura} Para I 1 hasta CantPersonas Hacer { coloco los i-elementos del vector en el archivo} comienza Regi ← InfoFacu (I ) Grabar (Facu, Regi ) { grabo el i-esimo elemento del vector en el archivo. Esta operación también modifica la marca fin-de-archivo } termina Cerrar ( Facu ) Termina Considerando las anteriores aclaraciones y recomendaciones, procederemos a describir cuales son los distintos procesos que se realizan sobre los archivos. ⌦ Apareo de archivos (mezclarlos respetando el orden). Consiste en intercalar información de dos o más archivos, donde cada uno debe estar ordenado previamente en el mismo orden y bajo la misma clave. Generalmente existe un archivo denominado Maestro y otro denominado Detalle, donde Detalle es la actualización a la información que se encuentra en el Maestro. ⌦ ABM de archivos (Altas, Bajas y Modificaciones de información contenida en un archivo). Los tipos de archivos que estamos estudiando son una fuente de información, y como tal, necesitamos mantenerla actualizada. La actualización implica agregar, borrar o modificar la información que se encuentra en un registro. ⌦ Ordenamiento de un archivo, Búsqueda. Para ordenar un archivo lo “bajamos” a memoria, a un vector de registros, lo ordenamos como se ordena un vector de registros, y luego lo “subimos” a disco. Las búsquedas se pueden realizar sobre el dispositivo, o más rápidamente en la memoria. Cortes de Control Desde los primeros algoritmos que hemos escrito, podemos observar que en alguna de sus partes aparece una selección dicotómica que bifurca el proceso. Esa selección produce un corte en la secuencia, a partir de una condición que controla por cuál de las opciones debe seguir. Este corte de control puede hacerse mediante una marca (bandera, flag, señal), o comparando variables de control. Por ejemplo, en la página 9 de este apunte, en el algoritmo que determina la mínima presión, se realiza un corte de control en el condicional que testea el valor de marca. Veamos un ejemplo más complejo en el que se utiliza más de un corte de control. La empresa Argentina_Potencia cuenta con sucursales en diversas localidades del país, y dentro de ellas, cuenta con secciones. Cada empleado tiene su número de legajo. La información por cada transacción realizada contiene: Sucursal Sección Legajo Importe El programa debe imprimir el total de cada empleado, de cada sección y de cada sucursal, y finalizada la información, el total de la empresa. La información está ordenada por Sucursal, Sección y Legajo. Programa Totales variables APUNTES TEÓRICOS - 50 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Sucursal, Sección, Legajo : cadena(3) Importe: real Suc_Ant, Sec_Ant, Leag_Ant : cadena(3) Tot_Empre, Tot_Suc, Tot_Sec, Tot_Empleado: real Comienza Tot_Empre 0 Tot_Suc 0 Tot_Sec 0 leer (Sucursal, Sección, Legajo, Importe) Suc_Ant Sucursal Sec_Ant Sección Leag_Ant Legajo Tot_Empleado Importe mensaje(Rta); mientras Rta=’S’ hacer comienza leer (Sucursal, Sección, Legajo, Importe) si Suc_Ant = Sucursal entonces { la sucursal es la misma y testeo la sección } si Sec_Ant = Sección entonces { la sección es la misma y testeo el legajo } si Leg_Ant = Legajo entonces {el empleado es el mismo y acumulo su importe } Tot_Empleado Tot_Empleado +Importe sino { cambió el empleado. Acumulo en la sección e imprimo el empleado } comienza Tot_Sec Tot_Sec + Tot_Empleado escribir (Leg_Ant, Tot_Empleado) Leag_Ant Legajo { defino legajo anterior } Tot_Empleado Importe termina sino {cambió la sección } comienza Tot_Sec Tot_Sec + Tot_Empleado { sumo a la sección anterior } Tot_Suc Tot_Suc + Tot_Sec { sumo a la sucursal } escribirlinea (Leg_Ant, Tot_Empleado) {imprimo al empleado} escribirlinea ( ‘total seccion ‘, Sec_Ant, ‘= ‘, Tot_Sec) { imprimo a la sección anterior } Leg_Ant Legajo Sec_Ant Sección {defino legajo y sección anterior } Tot_Empleado Importe Tot_Sec 0 termina sino {cambió la sucursal } comienza Tot_Sec Tot_Sec + Tot_Empleado { sumo a la sección anterior } Tot_Suc Tot_Suc + Tot_Sec {sumo a la sucursal } Tot_Empre Tot_Empre + Tot_Suc {sumo a la empresa } escribirlinea (Leg_Ant, Tot_Empleado) {imprimo al empleado } escribirlinea ( ‘total seccion ‘, Sec_Ant, ‘= ‘, Tot_Sec) { imprimo a la sección anterior } escribirlinea ( ‘total sucursal ‘, Suc_Ant, ‘= ‘, Tot_Suc) {imprimo a la sucursal anterior } Leag_Ant Sec_Ant Suc_Ant Legajo Sección Sucursal {defino legajo , sección y sucursal anterior } APUNTES TEÓRICOS - 51 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación Tot_Empleado Importe Tot_Sec 0 Tot_Suc 0 termina termina { termina el mientras Rta = ‘S’} { el operador indicó que no tiene más información, por lo que se debe imprimir todo lo correspondiente al último empleado, sección, sucursal y empresa } Tot_Sec Tot_Sec + Tot_Empleado {sumo a la sección anterior } Tot_Suc Tot_Suc + Tot_Sec {sumo a la sucursal } Tot_Empre Tot_Empre + Tot_Suc {sumo a la empresa } escribirlinea (Leg_Ant, Tot_Empleado) escribirlinea ( ‘total seccion ‘, Sec_Ant, ‘= ‘, Tot_Sec) escribirlinea ( ‘total sucursal ‘, Suc_Ant, ‘= ‘, Tot_Suc) escribirlinea ( ‘total empresa‘, Tot_Empre ) termina {Fin del Programa } Las tres selecciones dicotómicas sombreadas son cortes de control. Todas y cada una determinan el estado del dato, lo que permite producir resultados y transformar las variables de control. Así es como podemos imprimir los datos de cada empleado, de cada sección dentro de una sucursal, y de cada sucursal dentro de la empresa. Aplicación de cortes de control en Apareo de Archivos El siguiente programa genera el archivo de una distribuidora, a partir de dos archivos de sendas sucursales. Programa UNIFICACIÖN tipos regi_dato: registro clave: entero; cantidad: entero; resto: algún tipo fin registro archi_datos: archivo de regi_dato; variables Distrib, Sucursal1, Sucursal2 : archi_datos Procedimiento Apareo ( ref Distrib, Sucursal1, Sucursal2 : archi_datos); var regiSuc1, regiSuc2, regiDist: regi_dato; comienza abrir (Sucursal1) { para lectura} abrir (Sucursal2) { para lectura} abrir (Distrib) { para escritura} si no fin(Sucursal1) ∧ no fin(Sucursal2) entonces {leo el primer registro de cada archivo} comienza leer(Sucursal1, regiSuc1) leer(Sucursal2, regiSuc2) termina mientras no fin(Sucursal1) ∧ no fin(Sucursal2) hacer comienza {este mientras lee y procesa info de los dos archivos mientras ambos tengan información} si regiSuc1.clave = regiSuc2.clave entonces comienza {se compone el registro resultante de la suma lógica de ambos} regiDist.clave regiSuc1.clave regiDist. cantidad regiSuc1.cantidad + regiSuc2.cantidad regiDist. resto regiSuc1.resto ⊕ regiSuc2.resto {suma lógica} grabar (Distrib, regiDist) APUNTES TEÓRICOS - 52 - ALGORITMICA Y PROGRAMACIÓN Elementos de Programación leer(Sucursal1, regiSuc1) leer(Sucursal2, regiSuc2) termina sino si regiSuc1.clave < regiSuc2.clave entonces comienza { genero el registro resultante con la info del regiSuc1} regiDist.clave regiSuc1.clave regiDist. cantidad regiSuc1.cantidad regiDist. resto regiSuc1.resto grabar (Distrib, regiDist) leer(Sucursal1, regiSuc1) termina sino comienza { genero el registro resultante con la info del regiSuc2} regiDist.clave regiSuc2.clave regiDist. cantidad regiSuc2.cantidad regiDist. resto regiSuc2.resto grabar (Distrib, regiDist) leer(Sucursal2, regiSuc2) termina termina { por lo menos uno de los dos archivos se terminó} mientras no fin(Sucursal1) hacer comienza { no quedan datos de Sucursal2, y genero el registro resultante con la info del regiSuc1} regiDist.clave regiSuc1.clave regiDist. cantidad regiSuc1.cantidad regiDist. resto regiSuc1.resto grabar (Distrib, regiDist) leer(Sucursal1, regiSuc1) termina mientras no fin(Sucursal2) hacer comienza { no quedan datos de Sucursal1, y genero el registro resultante con la info del regiSuc2} regiDist.clave regiSuc2.clave regiDist. cantidad regiSuc2.cantidad regiDist. resto regiSuc2.resto grabar (Distrib, regiDist) leer(Sucursal2, regiSuc2) termina cerrar (Sucursal1) cerrar (Sucursal2) cerrar (Distrib) termina {fin procedimiento} Comienza {programa principal} {al comienzo del programa hay una serie de enunciados, los que preceden a la acción del apareo de archivos} {precondición: Sucursal1 y Sucursal2 EXISTEN} apareo(Sucursal1, Sucursal2, Distrib) { después del apareo, siguen otros enunciados que utilizarán el archivo Distrib} termina {programa principal} APUNTES TEÓRICOS - 53 -