Hola Mundo 06

download Hola Mundo 06

of 24

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