Apunte del curso ALGORITMOS y PROGRAMACIÓN (FI-UBA, Prof. Ing. F. J. LAGE, J. T. P. Ing. Z. CATALDI; A.T.P. Srta. A Pauluzzi, Sr. C Corradino, Sr. F Gómez SUBRANGO ENUMERADOS CONJUNTOS SUBRANGO: Un tipo subrango se define a partir de un tipo ordinal, especificando dos valores constantes de ese tipo, que a partir de aquí serán el límite inferior y superior del conjunto de datos de esa clase. Un tipo subrango es un por ser un subconjunto de un tipo ordinal es también ordinal, y sus valores se ordenan de la misma forma que están ordenados en el tipo patrón del cual derivan. Ejemplos 1 ..10 este tipo subrango consta de los elementos 1,2,3,4,5,6,7,8,9,10 ’F’ .. ’I’ este subrango consta de los caracteres ’F’, ’G’, ’H’, ’l’ ’a’ .. ’z’ este subrango consta de los caracteres ’a’ hasta ’z’ ’0’ .. ’9’ este subrango consta de los caracteres ’0’ a ’9’ Para operar con el tipo subrango, se pueden hacer de dos maneras distintas. a) Creando un tipo y luego asignándolo a una variable b) Definiéndolo directamente en la declaración de variables type var IntervaloEnteros = -100..100; Grande : integer; var Reducido : -100..100; Grande : integer; Reducido : IntervaloEnteros; El tipo subrango es esencialmente utilizado para dos fines: 1. Mejorar la legibilidad y la comprensión 2. Aumentar la fiabilidad de los programas, ya que Pascal detecta si un valor recibe un valor fuera del intervalo declarado. El tipo subrango puede ser leído de teclado como cualquier otra tipo de variable (Read o ReadLn), y presentado a través de pantalla por medio de los procedimientos correspondientes (Write, WriteLn). Compatibilidad de tipos: Los tipos subrangos y los tipos de donde proceden, son compatibles, en el sentido de que cualquier tipo de subrango pertenece al patrón. En el ejemplo anterior es legítima la sentencia: Grande := Reducido; También es legítimo el código de programa ReadLn (Grande); Página 1 de 11 Reducido := Grande; Sin embargo, si al leer con Readln (Grande) se toma para Grande un valor de 500 (fuera del rango IntervaloEnteros), la sentencia de aplicación Reducido := Grande produce un mensaje de error. Como ya se ha dicho un uso importante de los tipos subrangos es detectar ciertos errores de programación o carga de datos. Si se espera que una variable tome valores siempre en un cierto rango, entonces se debe declarar esa variable que adopte el tipo subrango. De este modo, si la variable de tipo subrango toman un valor fuera del rango especificado, se producirá un mensaje de error. 10.3.4. La directiva del compilador R Turbo Pascal no siempre produce un mensaje de error cuando el valor de un tipo subrango está fuera de su rango definido. Sin embargo, puede tener la posibilidad de visualizar dichos mensajes de error, insertando la siguiente línea en el archivo que contenga su programa: ($R+) Esta línea se denomina directiva del compilador. Su valor por defecto (desactivada) es $R-, que no realiza la verificación de los índices del subrango, pero que por el contrario aumenta la velocidad de ejecución. Durante la fase de depuración y puesta a punto de un programa es aconsejable utilizar la directiva $R+, insertándola al principio del programa. ENUMERADOS: Pascal permite otro tipo de dato ordinal denominado tipo enumerado. Estos tipos de datos son definidos por el usuario. Un tipo enumerado se compone de un conjunto de valores referenciados por identificadores. Estos valores constituyen una lista de identifica- dores de constantes que el programador debe indicar en la parte del programa reservada a las declaraciones. Eligiendo adecuadamente nombres significativos para los identificadores se pueden hacer programas más fáciles de leer. Ejemplos type Vehiculos = (avion, barco, tren, automovil, moto, colectivo); Frutas = (frutillas, manzana, pera, naranja, duraznos); Estos tipos pueden ser asignados a variables. Así, por ejemplo, se puede declarar Var Transporte : Vehiculos; Postre : Frutas; Características § Un tipo de dato enumerado es un tipo ordinal cuyo orden se indica por la disposición de los valores en la definición. § El número de orden de cada elemento comienza en 0 para el primer elemento. type Arcoiris = (Verde, Amarillo, Rojo, Azul, Verde); Página 2 de 11 Verde es el elemento número 0. Amarillo es el elemento número 1. Miércoles es el elemento tercero (3). § Las variables de tipo enumerado sólo pueden tomar valores de estos tipos. type Dia (lunes, martes, miercoles, jueves, viernes, sabado, domingo); var Semana : dia; Las sentencias siguientes son válidas: Semana := miercoles; while Semana = jueves do § Los únicos operadores que pueden acompañar a los enumerados son los operadores de relación y de asignación. lunes < martes verdadera jueves < viernes verdadera La expresión Colegio < martes produce un error de sintaxis, ya que los valores mostrados se asocian con dos tipos diferentes. El operador de asignación puede definir el valor de una variable cuyo tipo es un tipo enumerado. Dado que están ordenados los valores de un tipo enumerado, pueden ser comparados con la ayuda de operadores relacionales. Mediante las sentencias selectivas y repetitivas es posible dar gran flexibilidad a su lenguaje. Ejemplo a) Ejemplo b) if hoy < sabado then While hoy <> domingo do Write (’Dia laborable’) Ejemplo c) Else For hoy := lunes to viernes do Write (’Fin de semana’); § Los procedimientos de entrada/salida no pueden leer o escribir datos de tipo enumerado. Write (jueves); producirá un error ReadLn (jueves); producirá un error Si se desea obtener una salida se debe utilizar una sentencia Case Case hoy of lunes martes miercoles jueves : Write ("Lunes"); : Write ("Martes"); : Write ("Miércoles"); : Write ("Jueves"); Página 3 de 11 viernes sabado : Write ("Viernes"); : Write ("Sábado") else Write ("Domingo") end; § Un valor no puede figurar en dos tipos enumerados diferentes. § Los tipo enumerado no pueden leerse o escribirse en los archivos de texto. Subrangos de tipo enumerados Se pueden declarar subrangos de tipo enumerado Por ejemplo type mes = (enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre); primavera verano otonio invierno = octubre .. diciembre; = enero.. marzo; = abril .. junio; = julio .. septiembre; var mensual : mes; vendimia : otonio; vendimia := abril; vendimia := julio; sentencia válida sentencia no válida Funciones Ordinales Los tipos de datos ordinales como ya nos hemos referido, cada valor tiene un único predecesor (excepto el primero) y un único sucesor (excepto el último). Basándose en esta propiedad Pascal incorpora tres funciones predefinidas. Ord, Pred y Succ. Ord Determina la posición relativa de un elemento en la serie, las series no numéricas comienzan por la posición 0 (cero). Página 4 de 11 Por ejemplo: type mes = (enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre); var {* definición de las variables *} A : Integer; begin {* Comienzo del programa *} ...... A := ord(junio); Writeln ('El ordinal de Junio es: ',A); {* Salida del resultado *} A debe ser de tipo ordinal (byte o integer), el resultado de esta carrera es 5. Pred y Succ Pred devuelve el predecesor del argumento y Succ devuelve el sucesor del argumento. Pred (marzo) ⇒ febrero Succ (marzo) ⇒ abril Pred (enero) ⇒ indefinido Succ (diciembre) ⇒ indefinido Aunque no se vea a simple vista su utilidad estas funciones pueden ser aplicadas para ejemplos como el siguiente. While mensual <= diciembre do begin A := Ord (mensual); mensual := Succ(mensual); end; CONJUNTOS Es otro tipo de datos estructurado con el que se puede operar en Pascal. es el conjunto (set). Una variable de tipo set se denomina conjunto. El concepto es idéntico al matemático, y con este tipo de datos se puede realizar las mismas operaciones que las vistas en matemática (unión, intersección, etc.). En Pascal el conjunto de elementos se representan entre corchetes y separados por comas El máximo número de elementos de un conjunto es 256. Como en el álgebra existe el conjunto vacío, es aquel que no contiene ningún elemento. Declaraciones de tipos de datos conjuntos Para declarar o definir variables tipo conjunto, se deberá definir en función de un tipo base que deberá ser ordinal. Página 5 de 11 Ejemplos type mes = (enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre); meses = set of mes; digitos = set of byte; (no acepta otro tipo de enteros) caracteres = set of char; var Periodo, Cuatrimestre, Trimestre : meses; Posicion: digitos; El conjunto como cualquier otra variable parte de una condición de vacío. Los elementos pueden ser colocados en los conjuntos utilizando una sentencia de asignación. Periodo := [ ]; Posicion := [3, 5, 6, 8] Cuatrimestre := [abril..julio]; En el primer caso se le asignó será un conjunto vacío, en el segundo de los casos estará compuesto por esos cuatro elementos (3, 5, 6, 8), y en el último de los casos serán los meses (abril, mayo, junio, julio). Dos tipos de conjuntos son compatibles, si tienen los tipos base compatibles. En este caso sus variables representativas se pueden utilizar en sentencias de asignación. Periodo := Trimestre := [ ]; Una variable de tipo conjunto se suele inicializar al conjunto vacío o al conjunto universal. Include A partir de la versión 7 de Pascal. Una de las formas para agregar un elemento a un conjunto es a través del procedimiento include. Exclude También es una modificación de la versión 7. Exclude es un procedimiento para eliminar un elemento a un conjunto. Ejemplos Posicion :=[3, 5, 6, 8]; A := 15; include(Posicion, 22); include(Posicion, A); exclude (Posicion, 22); exclude (Posicion, A); En ambos casos se da como parámetros el conjunto (Posicion) y el elemento a agregar o quitar. El mismo puede darse como valor o como una variable, de esta última forma la variable debe ser de igual tipo que el tipo base del conjunto. Página 6 de 11 La relación In Determina si un elemento pertenece o no a un conjunto. El resultado de evaluar la expresión relacional puede ser true o false. El tipo de datos de elemento y la lista de elementos deben ser compatibles. Ejemplo if A in Posicion then if 15 in Posicion then La variable A y los elementos de Posicion deben ser compatibles. OPERACIONES CON CONJUNTOS En Pascal es posible realizar tres operaciones binarias sobre ellos que son: unión, intersección y diferencia. Unión (+) Las tres operaciones cumplen estrictamente las reglas del álgebra de conjuntos. Por lo tanto la unión de dos conjuntos da como resultante otro conjunto que tiene por elementos a los elementos comunes y no comunes de ambos conjuntos. La unión de conjunto se representa por el símbolo de la suma. Alfa := [3, 5, 8, 14]; Beta := [2, 5, 9, 14, 22]; Capa := Alfa + Beta; ⇒ Capa = [2, 3, 5, 8, 9, 14, 22] La unión es el segundo método para ingresar un elemento a un conjunto Ejemplo ReadLn(A); Posicion := Posicion + [A] Diferencia (-) La diferencia entre dos conjuntos da otro conjunto que tiene por elementos, todos los elementos del primer conjunto que no pertenecen al segundo. Se representa por el símbolo de la diferencia. Capa := Alfa - Beta; ⇒ Capa = [3, 8] Capa := Beta - Alfa; ⇒ Capa = [2, 9, 22] La diferencia es el segundo método para sacar un elemento a un conjunto Ejemplo ReadLn(A); Posicion := Posicion - [A] Intersección (*) La intersección entre dos conjuntos da otro conjunto que tiene por elementos, todos los elementos comunes a ambos conjuntos. Se representa por el símbolo del producto. Página 7 de 11 Capa := Alfa * Beta; ⇒ Capa = [5, 14] COMPARACIÓN DE CONJUNTOS Los conjuntos se pueden comparar entre sí mediante el uso de los operadores relacionales (=, <> , < =, > =). Los operandos deben ser del mismo tipo base. El resultado de la comparación es un valor lógico: true o false. Igualdad de Conjuntos Dos conjuntos son iguales, cuando sus tipos de base son equivalentes, y además todo elemento del primer conjunto pertenece al segundo y todo elemento del segundo conjunto pertenece al primero. Sub y Superconjunto Un conjunto Alfa es subconjunto (esta incluido) de otro Beta, si todo elemento de Alfa pertenece a Beta, pero no todo elemento de Beta pertenece a Alfa. En dicho caso Beta será un superconjunto de Alfa LOS CONJUNTOS COMO PARÁMETROS Los conjuntos se pueden utilizar como parámetros de funciones y procedimientos. En el caso de una función, se debe recordar que la misma devuelve un único valor, por lo tanto su tipo deberá ser un dato simple y no puede ser un conjunto. Ejemplo Realizar un programa que determine los números primos de entre 1 y N elegido por el usuario (menor que 65536). Utilizando la Criba de Eratóstenes. La idea de la criba es la siguiente: Dado una serie ordenada de valores, por ejemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 se prueba cuales son múltiplos de dos y se los elimina de la serie 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 se busca el siguiente de la serie (3) y se elimina los múltiplos de él 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 y así sucesivamente. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 El último valor con que se prueba es con R el cual es la parte entera de la raíz cuadrada del mayor de los valores de la serie. Página 8 de 11 program Criba_de_Eratostenes; {* Ejemplo de conjuntos *} {* Desarrollo del Ing. Fernando J. LAGE *} {* Septiembre 1998*} uses wincrt,windos; {* declaraciones de librerias, para correr bajo Windows *} {* crt,dos;*} {* declaraciones de librerias, para correr bajo DOS *} const Enter = #13; Ln = #13#10; {* Indica un salto de renglón *} type Valores = set of byte; {* Tipo conjunto *} var {* definición de las variables *} Criba : Valores; N, S: Byte; h : char; procedure ingresos; begin {* Comienzo del procedimiento de ingreso de valores *} repeat Write ('Ingrese un valor mayor que 0 y menor o igual 255 '); Readln (N); until (N>0) and (N<255) end; {* Fin del procedimiento ingreso*} function Extremo(A:Byte):Integer; {función que devuelve la parte entera de la raíz cuadrada } var Raiz : Real; begin {* Comienzo de la función Extremo *} Raiz := Sqrt(A); Extremo := Trunc(Raiz); end; {* Fin de la función Extremo *} Página 9 de 11 procedure Llenado(var Alfa : Valores; {* tipo conjunto *} Beta : Byte); var i : Byte; begin {* Comienzo del procedimiento de llenado de valores *} WriteLn (Ln,Ln,'Elementos del conjunto original : '); For i := 1 to Beta do begin Write (i,' '); Alfa := Alfa + [i] {* Agrega un elemento al conjunto *} end end; {* Fin del procedimiento Llenado *} function Multiplo(A,B:Byte):Boolean; {* Función que devuelve si un número es múltiplo o no *} var Mul : Byte; begin {* Comienzo de la función Extremo *} Mul := ((B div A)*A); Multiplo := Mul=B end; {* Fin de la función Extremo *} procedure Primos(var Alfa : Valores; {* tipo conjunto *} Beta, Gama: Byte); var i,j : Byte; begin {* Comienzo del procedimiento de búsqueda de valores no primos*} WriteLn (Ln, Ln, 'Elementos del conjunto original : '); For i := 2 to Gama do If i in Alfa Then For j := i+1 to Beta do If j in Alfa then If Multiplo(i,J) then Alfa := Alfa - [j]; end; {* Fin del procedimiento Primos *} Página 10 de 11 procedure salidas (Beta :Valores); {* tipo conjunto *} var i : byte; begin {* Comienzo del procedimiento de egreso de valores *} Writeln (' ',LN); {* Se deja renglones en blanco *} For i := 1 to N do if i in Beta then begin Write (' ',i); {* Salida del resultado *} exclude (Beta,i) end; Writeln (' son primos'); {* Salida del resultado *} Writeln (' ', Ln, Ln, Ln, Ln); {* Deja cinco renglones en blanco *} writeln ('Presione un tecla para terminar'); {* Salida de mensaje *} read(h); ClrScr; end; {* Fin del procedimiento salidas*} begin {* Comienzo del programa *} {* Se limpia la pantalla *} ClrScr; {* Declaro al conjuto vacio *} Criba := []; {* Ingreso del extremo superior *} Ingresos; {* Llenado del conjunto *} Llenado(Criba, N); {* Cálculo de el extremo de búsqueda *} S := Extremo(N); {* Obtención de los números primos *} Primos(Criba,N,S); {* Salida de resultados *} Salidas(Criba); end. {* Fin del programa *} Página 11 de 11