Hola Mundo 06
-
Upload
eduardo-s-pina -
Category
Documents
-
view
222 -
download
0
Transcript of Hola Mundo 06
-
7/24/2019 Hola Mundo 06
1/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html
.java.c.pas
7 D E A G O S T O D E 2 0 0 7
Captulo 6
.
Tipos de Datos definidos por el Programador
Los lenguajes de programacin brindan la posibilidad al programador de definir sus propios
tipos de datos.
En Pascal tenemos la seccin type donde podemos definir nuevos tipos. Un ejemplo de esto es
el siguiente programa en el que se definen los tipos de datos: Enteroy Cadena, y luegosedefinen dos var iables (ey s) de esos tipos y se las usa.
testType.pas
1:
2:type
3: Entero =integer;
4: Cadena =string[20];
5:
6: var
7: // defino una variable de tipo Entero
8: e:Entero;
9:
10: // defino una variable de tipo Cadena
11: s:Cadena;
12:
13:begin
14: e:=10;
15: s:='Prueba';
16:
17: writeln(e,' ',s);
18: end.
19:
En este captulo nos interesa definir tipos de datos compuestos, es decir: tipos de datos que
agrupen dos o ms datos simples.
Registros
Llamamos registro o estructura a un tipo de datos definido por el programador que agrupa dos
o ms datos relacionados entre s, a los que llamaremos campos.
Veamos un programa que define un registro RAlumnoque contiene 3 campos: legajo, nombre
y fecNac.
testRecord.pas
1:
2:type
3:
4: // definimos un nuevo tipo de datos
5: // un "registro"
6: RAlumno =record
Publicaciones del Autor
>> Click para Ms Informacin
-
7/24/2019 Hola Mundo 06
2/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 2
7: legajo:integer;
8: nombre:string[20];
9: fecNac:longint;// aaaammdd
10: end;
11:
12: var alumno:RAlumno;
13:
14:begin
15: // leemos el legajo
16: write('Ingrese Legajo: ');
17: readln(alumno.legajo);
18:
19: // leemos el nombre
20: write('Ingrese Nombre: '); 21: readln(alumno.nombre);
22:
23: // leemos la fecha
24: write('Ingrese Fecha (aaaammdd): ');
25: readln(alumno.fecNac);
26:
27: // imprimimos los datos
28: writeln('Legajo: ',alumno.legajo);
29: writeln('Nombre: ',alumno.nombre);
30: writeln('Fecha: ',alumno.fecNac);
31: end.
32:
Por convensin utilizaremos el prefijo Rpara indicar que el tipo de datos corresponde a un
registro. Por ejemplo: REmpleado, RAlumno, etc.
Analicemos nuevamente el registro RAlumno:
type RAlumno = record
... legajo: integer;
...nombe: string[20];
... fecNac: longint;// aaaammdd
end;
El campo fecNac a su vez podra ser un registro con tres campos: dia, mesy anio. Entonces la
seccin type quedara as:
1:
2:type
3: // definimos un registro RFecha
4: RFecha =record
5: dia:integer;
6: mes:integer;
7: anio:integer;// no usamos la "enie"
8: end;
9:
10: RAlumno =record
11: legajo:integer;
12: nombre:string[20];
13: fecNac: RFecha;// este campo es tipo RFecha
14: end;
15:
Entonces para asignar la fecha de nacimiento de un alumno (fecNac) ser:
1:
2: var alumno: RAlumno;
3:begin
4: alumno.fecNac.dia:=2;
5: alumno.fecNac.mes:=10;
6: alumno.fecNac.anio:=1970;
7: end.
8:
Archivos
Acerca del Autor
Ing. Pablo A. Sznajdleder
Agradecimientos
No al blog de Java
Super Baterista
Sitios Relacionados
PascAlgo (por Lic. Hugo Cuello)Algoritmia.net
Java Algorithm Framework
http://www.jaframework.com/http://www.algoritmia.net/http://pascalgo.blogspot.com/https://www.youtube.com/watch?v=UNSzfuZgNHAhttp://holamundopascal.blogspot.com/2009/04/agradecimientos.htmlhttp://www.pablosz.com/cv -
7/24/2019 Hola Mundo 06
3/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 3
Llamamos archivo a todo conjunto de datos almacenado en un dispositivo de alacenamiento
secundario (no en memoria principal).
La informacin contenida en un archivo puede ser homogenea o no. Es decir: un archivo puede
contener un conjunto de valores integer, un conjunto de valores string, un conjunto de
registros de alumnos (RAlumno), etc. Pero tamben podra contener una combinacin
arbitraria de diferentes tipos de datos: por ejemplo un integercon un valor n, luego n
registros de tipo RAlumno, Luego un longint conteniedo otro valor y as.
En este captulo estudiaremos archivos homogneos, principalmente archivos de registros.
Grabar un Archivo
Veamos el cdigo de un programa que lee valores numricos por teclado y los graba en un
archivo llamado SALIDA.dat.
grabarArchivo.pas
1:
2:type
3: FInteger =fileofinteger;
4:
5: var
6: arch: FInteger;// variable de archivo
7: v:integer;
8:begin
9: // relacionamos la variable de archivo con
10: // el archivo fisico en disco: SALIDA.dat
11: assign(arch,'SALIDA.dat');
12:
13: // si el archivo no existe entonces lo crea
14: // si el archivo existe entonces lo vacia
15: rewrite(arch);
16:
17: // leemos un valor por teclado (tipo integer)
18: read(v);
19:
20: // finalizamos la carga de datos con cero
21: while( v 0)dobegin
22:
23: // escribimos en el archivo el valor leido
24: write(arch,v);
25:
26: // leemos el siguiente valor (por teclado)
27: read(v);
28: end;
29:
30: // cierra el archivo
31: close(arch);
32: end.
33:
Anlisis
Analizando el cdigo anterior podremos ver los puntos fundamentales para poder manejar
archivos dentro de un programa.
Comenzamos definiendo un tipo de datos propio para el archivo. El tipo FInteger. Por
convensin utilizaremos el prefijo Fpara identificar los tipos de datos que se refieren aarchivos.
Recordemos que el archivo contendr valores numricos ingresados por teclado. As que un
archivo de integer estar bien (siempre que no se ingresen valores con decimales o valores
mayores que 32767). Tambin definimos una variable del tipo FInteger. La variable arch.
1:
2:type
3: FInteger =fileofinteger;
4:
5: var
6: arch: FInteger;// variable de archivo
7: v:integer;
8:
-
7/24/2019 Hola Mundo 06
4/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 4
Teniendo definido el tipo del archivo y una variable de ese tipo para manejarlo tenemos que
relacionar la variable de archivo (arch) con un archivo fsico en el disco. En el ejemplo el
archivo fsico ser SALIDA.dat. Con la funcin assign establecemos esta relacin y luego con
la funcin rewrite creamos el archivo. Es decir: si no exista lo crea y si exista lo deja vacio
(con 0 bytes).
1:
2:begin
3: // relacionamos la variable de archivo con
4: // el archivo fisico en disco: SALIDA.dat
5: assign(arch,'SALIDA.dat');
6:
7: // si el archivo no existe entonces lo crea
8: // si el archivo existe entonces lo vacia
9: rewrite(arch);
10:
El prximo paso es leer valores por teclado (finalizando con cero) y grabarlos en el archivo.
Para esto utilizamos la funcin write. Esta funcin recibe como parmetro la variable de
archivo (arch) y el valor que queremos grabar (v). Obviamente el valor tiene que ser del
mismo tipo del archivo. Como este archivo es de integer entonces lo que vayamos a grabar en
l tiene que ser de tipo integer tambin.
1:
2: // leemos un valor por teclado (tipo integer)
3: read(v);
4:
5: // finalizamos la carga de datos con cero
6: while( v 0)dobegin
7:
8: // escribimos en el archivo el valor leido
9: write(arch,v);
10:
11: // leemos el siguiente valor (por teclado)
12: read(v);
13: end;
14:
Por ltimo es necesario cerrar el archivo. El archivo se abre y se cierra. Para cerrarlo
utilizamos la funcin close.
1:
2: // cierra el archivo
3: close(arch);
4: end.
5:
Leer un Archivo
Veamos ahora el cdigo de un programa que lee el archivo SALIDA.dat (generado en el
problema anterior) y muestra por pantalla su contenido.
leerArchivo.pas
1:
2:type
3: FInteger =fileofinteger;
4:
5: var
6: arch: FInteger;
7: v:integer;
8:begin
9: // relaciona la variable de archivo
10: // con el archivo fisico SALIDA.dat
11: assign(arch,'SALIDA.dat');
12:
13: // abre el archivo
14: reset(arch);
15:
-
7/24/2019 Hola Mundo 06
5/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 5
16: // mientras no llegue el fin de archivo (eof)
17: while(NOT eof(arch))dobegin
18:
19: // lee el archivo y asigna el valor leido
20: // a la variable v (que es del mismo tipo
21: // del archivo: integer)
22: read(arch,v);
23:
24: // muestro el valor leido
25: writeln(v);
26: end;
27:
28: // cierra el archivo
29: close(arch); 30: end.
31:
Anlisis
Analizando el cdigo anterior vemos lo siguiente. Para abrir el archivo (luego del assign)
utilizamos la funcion reset. Esta funcin abre para lectura/escritura el archivo pero no borra
su contenido.
1:
2:type
3: FInteger =fileofinteger;
4:
5: var
6: arch: FInteger; 7: v:integer;
8:begin
9: // relaciona la variable de archivo
10: // con el archivo fisico SALIDA.dat
11: assign(arch,'SALIDA.dat');
12:
13: // abre el archivo
14: reset(arch);
15:
A continuacin iteramos mientras no llegue el fin del archivo. Para esto utilizamos la funcin
eof("end of fi le") que retorna true al momento de leer el ltimo registro. Dentro de while
leemos con la funcin read. Esta funcin recibe la variable de archivo (arch) y una variable
del mismo tipo del archivo en la cual va a asignar el valor leido (v).
15:
16: // mientras no llegue el fin de archivo (eof)
17: while(NOT eof(arch))dobegin
18:
19: // lee el archivo y asigna el valor leido
20: // a la variable v (que es del mismo tipo
21: // del archivo: integer)
22: read(arch,v);
23:
24: // muestro el valor leido
25: writeln(v);
26: end;
27:
28: // cierra el archivo
29: close(arch);
30: end.31:
Veamos los diagramas para los programas grabarArchivo (izquierda) y leerArchivo (derecha).
-
7/24/2019 Hola Mundo 06
6/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 6
El Registro Actual y el Fin de Archivo
Cada vez que leemos desde un archivo, la funcin read leer (retornar) el prximo registro.
Esto es posible porque internamente se maneja un puntero que apunta al siguiente registro
que se debe leer.
Cuando hacemos reset el puntero se posiciona en el primer registro. Cuando hacemos read la
funcin retorna el registro apuntado y avanza el puntero al siguiente registro.
Cuando el puntero llega a final del archivo (uno despues del ltimo) la funcin eof retorna
true.
Supongamos que tenemos el archivo NOMBRES.dat(de strings), el siguiente grfico muestra
como se va desplazando el puntero hasta llegar al end of file. En azul se destaca el valor
retornado por la funcin read.
Siguiendo el grfico paso a paso vemos que al hacer resetel puntero apunta al primer
registro. Luego, el primer read retorna 'Analia' y el puntero queda en el segundo registro. El
prximo read retorna 'Pablo' y el puntero queda en el tercer registro. El prximo read retorna
'Silvia' y el puntero pasa al fin de archivo (es decir: la funcin eof da true en ese mismo
momento).
Tenemos que tener mucho cuidado al momento de "barrer" un archivo (leerlo integramente
desde el primer registro hasta el ltimo) porque la funcin eof da true al momento de leer el
ltimo registro, no luego de leerlo.
http://bp3.blogger.com/_X1IHMrfIpE8/RrMubGgqxOI/AAAAAAAABEk/yYp3YdHiUk8/s1600-h/punteroArchivoOK.jpghttp://bp3.blogger.com/_X1IHMrfIpE8/SGK-NkIxPzI/AAAAAAAACcA/mOeB1JSM9NM/s1600-h/pepe.jpg -
7/24/2019 Hola Mundo 06
7/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 7
Veamos como barrer el archivo NOMBRES.datsin perder ningn registro.
En el siguiente grfico el programa de la izquierdaest mal, no muestra el ltimo registro. El
programa de la derecha es correcto, procesa todos los registros del archivo.
El cdigo Pascal ser:
Incorrecto:
1:
2: // :
3: read(arch,nom);// leo antes de entrar
4: while(NOT eof(arch))dobegin
5: writeln(nom);
6: read(arch,nom);// leo antes de cerrar
7: end;
8: // :
9:
Leer afuera del while y volver a leer antes de cerrarlo hace que el ltimo registro no se
procese. Esto es porque al leer el ltimo registro la funcin eof retorna true y entonces el
while no vuelve a iterar.
Correcto:
11:
12: // :
13: while(NOT eof(arch))dobegin
14: read(arch,nom);// leo ni bien entra
15: writeln(nom);
16: end;
17: // :
18:
19:
Leer una nica vez adentro, al inicio del while, soluciona el problema y permite procesar
todos los registros.
http://bp1.blogger.com/_X1IHMrfIpE8/SGKXKa4AS_I/AAAAAAAACb4/igBk90R-ivs/s1600-h/barrer.jpg -
7/24/2019 Hola Mundo 06
8/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 8
El problema del eofpuede resultar un poco molesto. En realidad, lo intuitivo (al menos para
mi) es que eof de true luego de leerse el ltimo registro, no al mismo momento de leerlo.
Para solucionar esto y poder leer antes de entrar y antes de f inalizar el while podemos
programar una funcin (muy simple) que retorne true si lleg el eof y false si no lleg (y en
este caso que lea el registro).
El siguiente programa recorre y muestra un archivo de enteros utilizando la funcin
leerArchivo.
leerArchivoConFuncion.pas
1:
2:type
3: FInteger =fileofinteger;
4:
5: // funcion leerArchivo:
6: // si es eof retorna true, si no entonces
7: // lee el archivo y retorna false
8:function leerArchivo(var a:FInteger
9: ;var buff:integer):boolean;
10:begin
11: if( eof(a))thenbegin
12: leerArchivo:=true;
13: endelsebegin
14: read(a,buff);
15: leerArchivo:=false;
16: end;
17: end;
18:
19: // programa principal
20: var
21: arch: FInteger;
22: v:integer;
23: fin:boolean;
24:begin
25: assign(arch,'SALIDA.dat');
26: reset(arch);
27:
28: // leemos afuera del while utilizando
29: // la funcion leerArchivo
30: fin:=leerArchivo(arch,v);
31:
32: while(NOT fin )dobegin
33: writeln(v);
34:
35: // volvemos a leer antes de cerrar
36: // el while utilizando la funcion
37: fin:=leerArchivo(arch,v);
38: end;
39:
40: close(arch);
41: end.
42:
http://bp0.blogger.com/_X1IHMrfIpE8/RpTt8jEMXzI/AAAAAAAAAlI/jlpLPSTJ5C0/s1600-h/leerArchivoCFuncionLeer.jpg -
7/24/2019 Hola Mundo 06
9/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 9
Acceso Directo a Registros
Como ya vimos, al abrir el archivo se maneja un puntero interno que apunta al primer
registro. Luego, si leemos ese registro el puntero avanza al prximo registro y as hasta llegar
al fin de archivo (eof).
Se puede identificar a los registros por la posicin que ocupan dentro del archivo y luego
posicionar el puntero para acceder y leer directamente el registro ubicado en dicha posicin.
Para esto disponemos de las siguientes funciones:
fileSize(arch) retorna la cantidad de registros que tiene el archivo
seek(arch,n) posiciona el puntero en el registro nmero n
El siguiente programa utiliza la funcionalidad de acceso directo para leer arbitrar iamente los
registros del archivo PERSONAS.dat. El usuario ingresa el nmero de registro que quiere ver y
el programa lo muestra. As hasta que se ingrese un nmero de registro negativo.
testAccesoDirecto.pas
1:
2:type
3: RPersona =record
4: nombre:string[20];
5: edad:integer;
6: end;
7: FPersona =fileof RPersona;
8:
9: // programa principal
10: var
11: arch: FPersona;
12: reg: RPersona;
13: cantReg,pos:integer;
14:begin
15: // abro el archivo para leerlo
16: assign(arch,'PERSONAS.dat');
17: reset(arch);
18:
19: // obtengo la cantidad de registros que
20: // tiene el archivo
21: cantReg:=filesize(arch);
22: writeln('El archivo tiene: '
23: , cantReg,' registros.');
24:
25: // el usuario ingresa el nro. de registro
26: // que quiere leer
27: write('Ingrese Nro. Registro (0,'
28: , cantReg1,'): ');
29: readln(pos);
30:
31: while( pos >=0)dobegin
32:
33: // posiciono el puntero
34: seek(arch,pos);
35:
36: // leo el registro apuntado por el puntero
37: read(arch,reg);
38:
39: // muestro la informacion
40: writeln( reg.nombre,' , ', reg.edad );
41:
42: // vuelvo a pedir al usuario que
43: // ingrese el proximo nro. de registro
44: write('Ingrese Nro. Registro (0,'
45: , cantReg1,'): ');
46: readln(pos);
47: end;
48:
49: close(arch);
50: end.
51:
Notemos que la posicin de los registros se cuenta a partir de 0 (cero). Por este motivo la
-
7/24/2019 Hola Mundo 06
10/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 10
funcin seek puede posicionarse entre los registros 0y n1(siendo nla cantidad de registros
del archivo).
Es decir: si filesize(arch) = nentonces seek(arch,0)posiciona el puntero en el primer
registro, seek(arch, 1) posiciona el puntero en el segundo registro y.. . seek(arch,n1)
posiciona el puntero en el ltimo registro.
Veamos el diagrama:
Ordenamiento de Archivos
Lamentablemente no hay forma de ordenar los registros de un archivo sin que esto implique
reescribir nuevamente el archivo. Es decir: ordenar un archivo implica escribirlo de nuevo.
Por esto (sobre todo para archivos grandes) el proceso de ordenamiento suele ser costoso (en
trminos de procesamiento). Debemos ser prudentes al momento de considerarlo como una
opcin vlida.
Ordenar Archivos va Arrays
Esta opcin solo es vlida para archivos pequeos y (dado que la longitud del array debe ser
definida con anticipacin) con una cantidad de registros acotada.
La idea es: definir un array de registros del mismo tipo que los registros del archivo, "subir" el
archivo al array, ordenar el array y "bajar" el array al archivo, reescribindolo.
El trmino "subir" describe la accin de cargar (en este caso) en el array los registros leidos
del archivo. El trmino "bajar" indica la accin de grabar los registros del array en el archivo.
Supongamos que el archivo PERSONAS.dattiene a lo sumo 100 registros, entonces el
siguiente programa nos permite ordenarlo ascendentemente por el campo nombre.
Comencemos por analizar la seccin typeen la que definiremos el tipo de registro, el tipo del
archivo y un tipo ARPersonacomo un array de registros RPersona, de 100 posiciones.
http://bp0.blogger.com/_X1IHMrfIpE8/SGLQbr6KqSI/AAAAAAAACcQ/jyxhfbfXvZI/s1600-h/accDir.jpg -
7/24/2019 Hola Mundo 06
11/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 1
1:
2:type
3: RPersona =record
4: nombre:string[20];
5: edad:integer;
6: end;
7: FPersona =fileof RPersona;
8:
9: // un array de 100 registros RPersona
10: ARPersona =array[1..100]of RPersona;
11:
Con la seccin type definida, veamos el diagrama del algoritmo que resuelve el problema y
luego continuaremos con el resto del cdigo.
Para resolver el problema abrimos el archivo, lo subimos al array con la funcin subirArchivo,
ordenamos el array con el procedimiento ordenar, vaciamos el archivo con rewrite y bajamos
al archivo el contenido del array (con el procedimiento bajarArchivo).
Notemos que la funcin subirArchivo retorna un entero (len) que indica la cantidad de
elementos tiles que se insertaron en el array.
Que el array sea de 100 elementos no significa que los 100 elementos estn siendo utilizados.
Lo definimos de 100 porque ese es el nmero mximo de registros que puede tener el archivo
(segn el enunciado). Pero si el archivo tiene 20 registros entonces len (el valor de retorno de
la funcin) ser 20.
Ahora si, continuemos con el cdigo del programa.
function subirArchivo
13:
14: function subirArchivo(var a:FPersona
15: ;var arr: ARPersona):integer;
16: var reg:RPersona; i:integer;
17: begin
18: i:=0;
19: while(NOT eof(a))dobegin
http://bp1.blogger.com/_X1IHMrfIpE8/RrM0pmgqxRI/AAAAAAAABE8/yyOwI5BDhkw/s1600-h/ordenaPersonas.jpg -
7/24/2019 Hola Mundo 06
12/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 12
20: read(a,reg);
21: i:=i+1;
22: arr[i]:=reg;
23: end;
24:
25: subirArchivo:=i;
26: end;
27:
La funcin recorre el archivo (lo recibe abierto), asigna al array en la posicin iel registro
leido (reg) e incrementa el valor de i. Es decir que al finalizar el while, en itendremos la
cantidad de registros que se insertaron en el array. Por eso el valor de retorno ser i.
procedure ordenar
28:
29: procedure ordenar(var arr:ARPersona; len:integer);
30: var ordenado:boolean; i:integer; aux: RPersona;
31: begin
32: ordenado:=false;
33: while(NOT ordenado )dobegin
34: ordenado:=true;
35: for i:=1to len1dobegin
36: if(arr[i+1].nombre
-
7/24/2019 Hola Mundo 06
13/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 13
75: rewrite(arch);
76:
77: // grabo en el archivo los registros del array
78: bajarArchivo(arch,arr,len);
79:
80: close(arch);
81: end.
82:
Bsqueda Binaria sobre Archivos
Si el archivo se encuentra ordenado por el campo por el cual queremos buscar, entonces
podemos aplicar el algoritmo de la bsqueda binaria exactamente de la misma manera que lo
utilizamos para realizar bsquedas sobre arrays.
Supongamos que tenemos el archivo EMPLEADOS.datordenado por el campo legajo con el
siguiente formato de registro:
REmpleado = record
..legajo: integer;
..nombre: string[20];
end;
Entonces podemos analizar la funcin buscarBinArch que realiza una bsqueda binaria sobre
este archivo y retorna (en un valor entero) la posicin del registro que contiene el valor
(legajo) que estamos buscando (si existe) o un valor negativo si no existe lo que buscamos.
1:
2:function buscarBinArch(var arch: FEmpleado
3: ; v:integer
4: ;var reg: REmpleado):integer;
5: var i,j,k:integer; encontrado:boolean;
6:begin
7:
8: encontrado:=false;
9:
10: // i comeinza en cero (primer posicion)
11: i:=0;
12:
13: // j apunta al ultimo registro (recordemos que
14: // se numeran desde cero) 15: j:=filesize(arch)1;
16:
17: while((i
-
7/24/2019 Hola Mundo 06
14/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 14
1 jse iniciali za con la posicin del ltimo registro del archivo (menos 1 porque los registros
se numeran desde cero) y
2 Luego de calcular el valor de khacemos un acceso directo al archivo para leer el registro
ubicado en esa posicin.
Notemos que el parmetro reglo recibimos por referencia por lo tanto cuando leemos en el
archivo y utili zamos esta variable para que la funcin readguarde all lo que ley, los datos
leidos quedarn en la variable an despues de finalizar la funcin buscarBinArch.
Ahora veamos un programa principal que le pide al usuario que ingrese legajos y (si existen)muestra los datos completos del registro encontrado.
1:
2: // programa principal
3: var pos,leg:integer; arch: FEmpleado; reg: REmpleado;
4:begin
5: assign(arch,'EMPLEADOS.dat');
6: reset(arch);
7:
8: write('Legajo: ');
9: readln(leg);
10:
11: while( leg >0)dobegin
12:
13: // busqueda binaria sobre el archivo
14: pos:=buscarBinArch(arch,leg,reg);
15: if( pos >=0)thenbegin
16: writeln('Encontrado (',pos,'): '
17: , reg.legajo,' , '
18: , reg.nombre);
19: endelsebegin
20: writeln('Legajo no encontrado');
21: end;
22:
23: write('Legajo: ');
24: readln(leg);
25: end;
26:
27: close(arch);
28: end.
29:
Notemos que la funcin buscarBinArch retorna un entero positivo indicando en que posicin
fu encontrado el registro cuyo campo legajoes el que estamos buscando. Si la funcin
retorna un valor negativo significa que no se encontr ningn registro con ese legajo.
Si el registro se encontr entonces la misma funcin ya deja cargados los datos del registro en
la variable reg.
-
7/24/2019 Hola Mundo 06
15/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 15
Indexar Archivos
Como dijimos anteriormente, no siempre es una buena idea ordenar el archivo. Y si el archivo
no est ordenado entonces no se puede realizar una bsqueda binaria sobre l. Tenemos un
problema.
La solucin consiste en crear un ndice ordenado por el campo por el cual queremos realizar la
bsqueda y luego acceder a los registros del archivo de manera directa, previa bsqueda sobre
el ndice.
El ndice se puede implementar en un array (si la cantidad de registros del archivo est
acotada) o en una lista enlazada.
Implementando el Indice sobre un Array
Veremos como implementar el ndice para el archivo EMPLEADOS.dat sobre un array
(arrIndice).
Supongamos que el archivo EMPLEADOS.dat tiene a lo sumo 100 registros. Entonces
definiremos un registro RIndicey un array (arrIndice) de 100 elementos tipo RIndice:
type
..//definimos el registro para el indice
..RIndice = record
....legajo: integer;
....posArch: integer;
..end;
..//definimos tipo para el array
..ARIndice = array [1..100] of RIndice;
var
..arrIndice: ARIndice; // definimos el array
La idea es recorrer el archivo e ir insertando registros en el array ordenados por el campo
legajo (que es el campo clave para la bsqueda), guardando en el campo posArch la posicin
que ocupa dentro del archivo el registro que tiene ese legajo.
http://bp2.blogger.com/_X1IHMrfIpE8/RrM4Z2gqxTI/AAAAAAAABFM/kHWFoMfQeCs/s1600-h/buscarBinArchCMain.jpg -
7/24/2019 Hola Mundo 06
16/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 16
En el ejemplo vemos que el array qued ordenado por legajo. As podremos realizar una
bsqueda binaria sobre el array para buscar (por ejemplo) el legajo nmero 271. Cuando lo
encontremos veremos que el campo posArch dir 1. Entonces si accedemos al archivo, al
registro nmero 1 habremos encontrado el registro que estbamos buscando.
Analicemos entonces la funcin indexaEmpleados que lee el archivo y genera el array ndice
sobre el que luego se podr realizar la bsqueda binaria por la clave legajo.
Primero veamos la seccin typedonde definimos los tipos REmpleado (registros del archivo),
FEmpleado (tipo del archivo), RIndice (registros del array) ARIndice (tipo que define un
array de 100 RIndice).
1:
2:type
3: REmpleado =record
4: legajo:integer;
5: nombre:string[20];
6: end;
7:
8: FEmpleado =fileof REmpleado;
9:
10: RIndice =record
11: legajo:integer;
12: posArch:integer;// posicion en el archivo
13: end;
14:
15: ARIndice =array[1..100]of RIndice;16:
Veamos ahora la funcin indexarEmpleados. Esta funcin recibe el archivo arch(ya abierto)
y el array arr(vacio, sin elementos). Retorna la cantidad de elementos tiles que se
insertaron en el array (len).
El objetivo de la funcin es recorrer el archivo arch y por cada registro del archivo ir
insertando (ordenado por legajo) registros (de tipo ARIndice) en el array arr.
51:
52: function indexarEmpleados(var arch:FEmpleado
53: ;var arr:ARIndice):integer;
54: var len:integer;reg:REmpleado;regArr:RIndice;
55: begin56: len:=0;
57: while(NOT eof(arch))dobegin
58: read(arch,reg);
59: regArr.legajo:=reg.legajo;
60: regArr.posArch:=len;
61:
62: insertarOrdenado(arr,len,regArr);
63: end;
64:
65: indexarEmpleados:=len;
66: end;
67:
Como vemos, el algoritmo que resuelve la funcin es muy simple: recorre el archivo, por cada
http://bp2.blogger.com/_X1IHMrfIpE8/Rpa-pWadlRI/AAAAAAAAAnA/-czTl_yxb94/s1600-h/indexDemo.jpg -
7/24/2019 Hola Mundo 06
17/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 17
registro del archivo asigna el legajo y la posicin en el archivo del registro leido (que coincide
con len) en un registro de tipo RIndice. Luego, utilizando la funcin insertarOrdenado
inserta ese registro en el array.
Cabe aclarar que en este caso la funcin insertarOrdenado fue modificada. El array que
recibe es de tipo ARIndice y el valor que recibe para insertar es de tipo RIndice. Y en todas
las condiciones lgicas pregunta por arr[i].legajoo valor.legajoya que legajo es el campo
clave.
Veamos el cdigo del procedimiento insertar y de la funcin insertarOrdenado adaptados
para este problema.
17:
18: procedure insertar(var arr: ARIndice
19: ;var len:integer
20: ; valor: RIndice; pos:integer);
21: var i:integer;
22: begin
23: for i:=len+1downto pos+1dobegin
24: arr[i]:= arr[i1];
25: end;
26:
27: arr[pos]:=valor;
28: len:=len+1;
29: end;
30:
31: function insertarOrdenado(var arr: ARIndice32: ;var len:integer
33: ; valor: RIndice):integer;
34: var i:integer;
35: begin
36: i:=1;
37: while((i
-
7/24/2019 Hola Mundo 06
18/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 18
48: insertarOrdenado:=i;
49: end;
50: end;
51:
Ahora podemos ver el programa principal. Pide al usuario que ingrese un legajo, lo busca en el
ndice y (si existe) accede directamente al archivo para leer y mostrar los datos del empleado.
El cdigo del programa principal es:
97:
98: // programa principal
99: var
100: arch:FEmpleado ;
101: arrIndice:ARIndice;
102: reg:REmpleado;
103: len,leg,posArr,posArch:integer;
104:
105: begin
106: assign(arch,'EMPLEADOS.dat');
107: reset(arch);
108:
109: len:=indexarEmpleados(arch,arrIndice);
110:
111: write('Ingrese Legajo: ');
112: readln(leg);113:
114: while( leg>0)dobegin
115:
116: posArr:=buscarBinIndex(arrIndice,len,leg);
117:
118: if( posArr>0)thenbegin
119: posArch:=arrIndice[posArr].posArch;
120: seek(arch,posArch);
121: read(arch,reg);
122: writeln('Legajo: ',reg.legajo
123: ,' Nombre: ',reg.nombre);
124: endelsebegin
125: writeln('Legajo no encontrado');
126: end;
127:
128: write('Ingrese Legajo: ');
http://bp2.blogger.com/_X1IHMrfIpE8/RrM8R2gqxVI/AAAAAAAABFc/tAhn1SlLz-Y/s1600-h/indexarEmpleadosPpal.jpg -
7/24/2019 Hola Mundo 06
19/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 19
129: readln(leg);
130: end;
131: close(arch);
132: end.
133:
Inplementando el Ind ice sobre una Lista Enlazada
Esta tcnica la estudiaremos en el captulo de Estructuras Dinmicas, luego de analizar los
temas de punteros y l istas.
Apareo de Archivos
Se considera "apareo de archivos" a los problemas que intercalan datos de dos o ms archivos
que se encuentran ordenados por la misma clave, recorrindolos simultaneamente.
Analicemos los datos de los siguientes conjuntos:
Los dos conjuntos estn ordenadosen forma ascendente. Leemos el primer valor de A(lo
llamaremos a) y luego el primer valor de B(lo llamaremos b).
Si a(1)< b(2)podemos determinar que el valor aest en el conjunto Apero no en el conjuntob, ya que como estn ordenados el siguiente valor de Bser an ms grande. Luego leemos el
siguiente valor de Aa(3)y lo comparamos con b(2).
Si a(3)> b(2)entonces podemos determinar que el valor de b(2)est en el conjunto Bpero no
en el conjunto A. Ahora leemos Bb(3).
Si a(3) = b(3)entonces el valor se encuentra en ambos conjuntos. En este caso leemos Ay By
as sucesivamente hasta que finalice alguno de los dos conjuntos.
Si un conjunto (A) termina antes que el otro (B) podemos asegurar que todos los elementos
sobrantes (de B) no estarn contenidos en el otro conjunto (A).
Luego de este anlisis podemos plantear un enunciado que le de sentido a lo anterior.
Problema 6.1
Se tienen los archivos PRESTA_2006.dat y PRESTA_2007.dat, con la informacin
correspondiente a las prestaciones que realizaron los diferentes mdicos de una clnica. Ambos
archivos estn ordenados por id_medicoy t ienen los siguientes campos:
id_medico (5 dgitos)
cantidad (4 dgitos)
Existe la posibilidad de que durante el ao 2007 se hayan incorporado mdicos que no
trabajaron durante 2006. Tambin pueden haber mdicos que trabajaron durante 2006 pero no
durante 2007.
Se Pide
http://bp2.blogger.com/_X1IHMrfIpE8/Rrde92gqxsI/AAAAAAAABIU/BPagDNWlUxs/s1600-h/apareoAB.jpg -
7/24/2019 Hola Mundo 06
20/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 20
1. Un listado de los mdicos que se incorporaron durante 2007 (no sern ms de 100).
2. Un listado de los mdicos que solo trabajaron durante 2006 (no sern ms de 100).
3. Un listado indicando los mdicos que incrementaron la cantidad de prestaciones de un
ao al otro.
Anlisis
La idea del apareo de archivos es recorrer simultaneamente ambos archivos comparando su
campo clave (por el cual estn ordenados). Si encontramos un registro en PRESTA_2006 que no
est en PRESTA_2007 corresponder a un mdico que no trabaj en 2007. Si encontramos un
registro en PRESTA_2007 que no est en PRESTA_2006 entonces ese mdico se incorpor en
2007. Si encontramos un mismoid_medicoen ambos archivos entonces ese mdico trabaj en
2006 y 2007.
Veamos el siguiente ejemplo (los datos de la i zquierda corresponden a PRESTA_2006. Los de la
derecha corresponden a PRESTA_2007):
Leemos ambos archivos y comparamos su id_medico. S i coinciden entonces ese id_medico
corresponde a un mdico que trabaj en los aos 2006 y 2007. Leemos nuevamente en los dos
archivos:
Ahora id_medicoen PRESTA_2006 es mayor que id_medicoen PRESTA_2007. Evidentemente
el mdico conid_medico=2 se incorpor en 2007. En este caso leemos solamente
PRESTA_2007.
http://bp3.blogger.com/_X1IHMrfIpE8/Rrbi2WgqxiI/AAAAAAAABHE/OesecDkL51o/s1600-h/apareo2.jpghttp://bp3.blogger.com/_X1IHMrfIpE8/Rrbi2WgqxhI/AAAAAAAABG8/Daa7XS4xXzY/s1600-h/apareo1.jpg -
7/24/2019 Hola Mundo 06
21/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 2
Ahora en los dos archivos tenemos registros con el mismo id_medico(3). Este mdico
tambin trabaj los dos aos. Volvemos a leer ambos archivos.
En este caso id_medicoen PRESTA_2006 es menor que id_medicoen PRESTA_2007. Esto
significa que el mdico con id_medico=4no trabaj en 2007. En este caso solo leemos
PRESTA_2006 y as hasta el fin de datos de alguno de los dos archivos.
Si llega el f in de datos de PRESTA_2006 significa que todos los registros que quedan por leer en
PRESTA_2007 corresponden a mdicos que se incorporaron ese ao. Pero si llega primero el eof
de PRESTA_2007 entonces todos los registros que quedan sin leer en PRESTA_2006
corresponden a mdicos que dejaron de trabajar.
La estrategia de solucin ser la siguiente: tendremos dos arrays (arr06y arr07) de 100
elementos cada uno. En arr06iremos guardando los mdicos que solo trabajaron en 2006
(punto 2 del enunciado). En arr07iremos guardando los mdicos que se incorporaron a
trabajar en 2007 (punto 1 del enunciado). Los mdicos que trabajaron los dos aos e
incrementaron la cantidad de prestaciones (punto 3 del enunciado) los listaremos a medida que
los encontremos.
Veamos la seccin typepara definir los tipos de datos.
1:
2:type 3: // registro de los archivos
4: RPresta =record
5: id_medico:longint;
6: cantidad:integer;
7: end;
8:
9: // tipo para los archivos
10: FPresta =fileof RPresta;
11:
12: // tipo para los arrays de medicos
13: AMed =array[1..100]oflongint;
14:
http://bp0.blogger.com/_X1IHMrfIpE8/Rrbi2mgqxkI/AAAAAAAABHU/mR1EpmM9naI/s1600-h/apareo4.jpghttp://bp3.blogger.com/_X1IHMrfIpE8/Rrbi2WgqxjI/AAAAAAAABHM/NDab1WK5y5c/s1600-h/apareo3.jpg -
7/24/2019 Hola Mundo 06
22/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 22
En el programa principal resolvemos el apareo de archivos. Leemos PRESTA_2006 y
PRESTA_2007 e i teramos mientras no llegue el fin de archivo de alguno de los dos.
Comparamos reg06.id_medicocon reg07.id_medico:
Si reg06.id_medico = reg07.id_medicoentonces tenemos que comparar las
prestaciones que realiz ese mdico durante 2006 y 2007. Si las de 2007 fueron ms
entonces lo imprimimos para resolver el punto 3 del eununciado. Luego volvemos a
leer los dos archivos.
Sireg06.id_medico > reg07.id_medico entonces el mdico apuntado enPRESTA_2007 es nuevo, se incorpor ese ao. Almacenamos su id_medicoen el array
arr07.
Si reg06.id_medico no es mayor que reg07.id_medicoentonces el mdico apuntado
en PRESTA_2006 no trabaj durante 2007. Almacenamos su id_medico en el array
arr06.
Por ltimo, preguntamos cual de los dos archivos termin. S i termino PRESTA_2006 tenemos
que recorrer PRESTA_2007 hasta el f inal agregando todos los registros que quedaron en arr07
ya que todos fueron mdicos que se incorporaron ese ao. Si el que termin primero fue
PRESTA_2007 entonces recorremos hasta el f inal PRESTA_2006 agregando todos los registros
que quedarn en arr06porque todos corresponden a mdicos que dejaron de trabajar.
http://bp3.blogger.com/_X1IHMrfIpE8/RrcEfGgqxrI/AAAAAAAABIM/duLVhrMGoxc/s1600-h/Problema6.1apareoA_02.jpghttp://bp0.blogger.com/_X1IHMrfIpE8/RrcEIWgqxpI/AAAAAAAABH8/LByMVS2qsSs/s1600-h/Problema6.1apareoA_01.jpg -
7/24/2019 Hola Mundo 06
23/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
http://holamundopascal.blogspot.mx/2007/08/capitulo-6.html 23
Algoritmos y Estructuras de Datos UTN UBA.
Publicado por PabloSZ
3 comentarios:
Annimo dijo...
Excelente tu trabajo en toda la pgina. Estoy cursando Algoritmos en la UTN y me
recomendaron tu pgina, la verdad me aclaraste muchas dudas con el tema de
archivos.
Hay algunos errores en los diagramas, lo cual lo veo muy til (apropsito o no) porque
me obliga a pensar y analizar si estn bien, y no nicamente a leer de corrido cada
ejercicio.
Un abrazo y segu con la pgina!
03 junio, 2008 23:28
Sebastian dijo...
Pablo veo en la parte de Indexacin de Archivosque usas un array para almacenar
DOS campos:
1 legajo2 posArch
Luego usas ese Array para todo el ejemplo.
No tendras que usar una matriz de 2x100?
Creo que ahi tenes un error porque por mas que declares al array con un registro de
dos variables no las podes meter. O si?
Me agarro la duda...
Gracias
12 septiembre, 2008 18:33
http://holamundopascal.blogspot.com/2007/08/capitulo-6.html?showComment=1221255180000#c6522738527129368195http://holamundopascal.blogspot.com/2007/08/capitulo-6.html?showComment=1212546480000#c1423164073194355531http://bp0.blogger.com/_X1IHMrfIpE8/Rrb3GmgqxnI/AAAAAAAABHs/UwLfx8QG-1o/s1600-h/Problema6.1apareoB.jpg -
7/24/2019 Hola Mundo 06
24/24
15/10/2015 HolaMundo.pascal (online): Captulo 6
Entrada ms reciente Entrada antigua
Publicar un comentario en la entrada
Pgina principal
Suscribirse a: Enviar comentarios (Atom)
Todos los Derechos Reservados Propiedad Intelectual Nro. 591212
Annimo dijo...
ola tengo una consulta...puede ser que solo pueda subir 2 campos de un registro..o sea
no el registro entero al array....a ver si me explico por ejmplo tengo
descripcion,monto,fecha,nombre en un registro de archivo..y yo solo kiero subir
descripcion y monto al array se usa la el mismo procedimiento de "subir archivo"?
25 septiembre, 2008 12:05
http://holamundopascal.blogspot.com/2007/08/capitulo-6.html?showComment=1222355100000#c7806919964914257965http://holamundopascal.blogspot.com/feeds/4224815089116588815/comments/defaulthttp://holamundopascal.blogspot.mx/https://www.blogger.com/comment.g?blogID=994832637513226408&postID=4224815089116588815&isPopup=truehttp://holamundopascal.blogspot.mx/2007/08/capitulo-7.htmlhttp://holamundopascal.blogspot.mx/2007/08/capitulo-5.html