1.Definicion de arreglos 2.Caracteristicas de arreglos3.
decalracion de arreglos
4.representacion de un arreglo en la memoria 5.inicializacion 6.recorrido de un arreglo
7.busqueda de un arreglo 8.operaciones con arreglos 9.arreglos unidimensionales
10.arreglos multidimensionales 11.funciones y procedimientos definidos por el usuario
en turbo pascal 12.recursividad 13.archivos secuenciales indexados 14.archivos directos
o de dispersion 15.archivos aleatorios. El trabajo debe llevar ejemplos explicados!
1 DEFINICION DE ARREGLO
Array en inglés. Una forma de estructurar elementos. Se emplea especialmente en
programación y en su forma más básica es una lista de la forma array(elemento,
elemento, ...).
Los arrays pueden ser vectores (unidimensionales), matrices (bidimensionales) o
multidimensionales.
Definición
Un arreglo es un conjunto de elementos del mismo tipo agrupados en una sola
variable. También se les conoce con el nombre de arreglos. Cada posición de
almacenamiento en un arreglo es llamada un elemento del arreglo.
Para ingresar a un elemento en particular, utilizamos un índice. Existen arreglos
unidimensionales, bidimensionales y tridimensionales.
Su uso más común es en la implementación de cadenas de caracteres. Recuerda
que en C no existen variables de tipo cadena por lo cual se utiliza un arreglo de
caracteres.
Físicamente, un arreglo es un conjunto de localidades de memoria contiguas
donde la dirección más baja corresponde al primer elemento y la dirección más
alta al último.
En un arreglo de n elementos, éstos ocuparan desde la casilla 0 hasta la n-1. Por
si mismo, el nombre del arreglo apunta a la dirección del primer elemento del
arreglo.
CARACTERISTICAS DE LOS ARREGLOS:
Un Arreglo se caracteriza por:
1.- Almacenar los elementos del arreglo en posiciones de memoria continua.
2.- Tener un único nombre de variable que representa a todos los
elementos(Notas), y estos a su vez se diferencian por un índice o subíndice.
Notas[0], …, Notas[n-1] {Lenguaje C}
Notas[1]..Notas[n] {Pascal}
3.- Acceso directo o aleatorio a los elementos individuales del arreglo.
DECALRACION DE ARREGLOS:
Declaración de un arreglo
Los tipos arreglo se declaran en la sección type del programa:
nombre = array [tipo_indice] of tipo_base;
tipo_indice debe ser un tipo ordinal, generalmente es un subrango de enteros.
tipo_base es cualquier tipo de Pascal.
REPRESENTACION DE UN ARREGLO EN LA MEMORIA:
Representación de un arreglo en la memoria
Un arreglo ocupa tantas celdas de memoria como el cardinal de su tipo índice:
const
MaxArreglo = 9;
type
RangoArreglo = 1..MaxArreglo;
Arreglo1 = array [RangoArreglo] of integer;
var
a : Arreglo1; (* ocupa 9 celdas *)
La variable a ocupa 9 celdas:
*------*------*------*------*-----*-----*-----*-----*-----*
| 23 | 34 | 0 | -12 | 6 | 9 | 11 | -2 | 34 |
*------*------*------*------*-----*-----*-----*-----*-----*
1 2 3 4 5 6 7 8 9
REPRESENTACION EN MEMORIA
Los arreglos se representan en memoria de la forma siguiente:
x : array[1..5] of integer
Para establecer el rango del arreglo (número total de elementos) que componen el arreglo se utiliza la
siguiente formula:
RANGO = Ls - (Li+1)
donde:
ls = Límite superior del arreglo
li = Límite inferior del arreglo
Para calcular la dirección de memoria de un elemento dentro de un arreglo se usa la siguiente formula:
A[i] = base(A) + [(i-li) * w]
donde :
A = Identificador único del arreglo
i = Indice del elemento
li = Límite inferior
w = Número de bytes tipo componente
Si el arreglo en el cual estamos trabajando tiene un índice numerativo utilizaremos las siguientes fórmulas:
RANGO = ord (ls) - (ord (li)+1)
A[i] = base (A) + [ord (i) - ord (li) * w]
INICIALIZACION DE ARREGLOS:
Inicialización
Para inicializar un arreglo es necesario asignar cada celda por separado:
(* todo en cero *)
for i:= 1 to 10 do
a[i]:= 0;
(* 2,4,6,...,20 *)
for i:= 1 to 10 do
a[i]:= 2 * i;
(* desde la entrada *)
for i:= 1 to 10 do
ReadLn(a[i]);
RECORRIDO DE UN ARREGLO:
Recorridas de arreglos
La estructura de control for es la adecuada para recorrer completamente un arreglo
(* hallar la suma de todos los elementos *)
suma:= 0;
for i:= 1 to M do
suma:= suma + a[i];
(* hallar el maximo *)
max:= a[1];
for i:= 2 to M do
if a[i] > max then
max:= a[i];
(* desplegar un arreglo *)
for i:= 1 to M do
WriteLn(a[i]);
(* desplegar separados por comas *)
write(a[1]);
for i:= 2 to M do
write(',',a[i]);
Búsqueda en un arreglo
Buscar un elemento que sea igual a A.
i:= 1;
repeat
exito:= (a[i] = A);
i:= i+1;
until (i > M) or exito;
if exito then
WriteLn('exito')
else
WriteLn('fracaso')
Búsqueda (2)
Usando while
i:= 1;
exito:= false;
while (i<=M) and not exito do
begin
exito:= (a[i] = A);
i:= i+1;
end;
if exito then
WriteLn('exito')
else
WriteLn('fracaso')
Búsqueda (3)
No es correcto utilizar for. (aunque "anda")
(* INCORRECTO! *)
exito:= false;
for i:= 1 to M do
if (a[i] = A) then
exito:= true;
if exito then
WriteLn('exito')
else
WriteLn('fracaso')
Búsqueda
¿Por qué usar la bandera exito?
exito:= false;
while (i<=M) and not exito do
begin
exito:= (a[i] = A);
i:= i+1;
end;
¿Se podría escribir directo la condición
(i<=M) and (a[i] <> A) ?
Respuesta: En principio no.
Búsqueda secuencial o lineal
La búsqueda secuencial en un arreglo consiste en buscar un valor en el
arreglo recorriendo los elementos adyacentes, comenzando desde una
posición inicial. El proceso finaliza cuando se encuentre una posición en el
cual su valor es el buscado o bien cuando se haya alcanzado al último
elemento y no apareció el valor buscado. Por lo tanto habrá dos situaciones
de salida, una es cuando se encontró el valor y la otra cuando se alcanzó al
último elemento en el arreglo sin haberse encontrado el valor. De esto se
desprende que si el valor estuviera en la primera posición, un solo acceso al
arreglo sería suficiente y en el peor de los casos tendremos que acceder
hasta la última posición, así, si un arreglo tuviera n componentes, la
cantidad de accesos promedia sería de n / 2.
A continuación se presenta el siguiente módulo en el cual se buscará el
valor de una clave en un arreglo, retornando el módulo la posición
encontrada si el valor clave se encontró en el arreglo, caso contrario un
valor cero si no se encontró.
El método de búsqueda secuencial sirve tanto si el arreglo está
desordenado como si se encontrara ordenado. No obstante en los casos en
que el arreglo estuviera ordenado debería optimizarse el algoritmo para los
casos en que habiendo llegado a una posición en el arreglo y siendo que su
contenido es mayor al valor buscado, bajo esta situación se debería
abandonar la búsqueda, ya que si no se lo encontró hasta esa posición,
tampoco se lo encontrará más adelante, por ser todos esos valores
mayores al buscado, sabiendo que el arreglo se encontraba ordenado en
forma ascendente.
A continuación se presenta el módulo de búsqueda secuencial optimizado.
El módulo BusLinOpt mejora el rendimiento de la búsqueda con respecto al
módulo BusLin, ya que en el segundo caso si se encontró un valor mayor al
buscado se abandona la búsqueda de los siguientes elementos restantes.
Búsqueda binaria
Pero, ¿será este el mejor método de búsqueda cuando el arreglo se
encuentre ordenado, por el valor de la clave a buscar?. La respuesta
es ¡NO!. Una mejor manera de buscar un valor en un arreglo ordenado será
aquel que obtiene un punto medio entre sus extremos y es comparado por
el valor a buscar, si es, entonces se encontró y se abandona la búsqueda,
en cambio si no lo es, caben dos posibilidades, que haya que seguir
buscando en una primera mitad o bien en la segunda mitad, en ambos
casos el arreglo queda reducido para continuar la búsqueda en la mitad. El
método que realiza estas acciones se conoce como método de búsqueda
binario o dicotómica. Este método ya fue presentado en el tema de buscar
un elemento en un archivo ordenado. Por lo tanto, diremos que conservará
básicamente la estructura lógica vista, la única diferencia notable está en
que no hace falta bajar el dato ya que se encuentra en la propia memoria
interna. A continuación se presenta el módulo de búsqueda binaria o
dicotómica en arreglos.
El método comienza conociendo las posiciones extremas del arreglo, pri y
ult, se obtiene el punto medio med y se compara si el valor de esta posición
es el valor clave a buscar, si es entonces se abandona el proceso, sino
caben 2 alternativas, es menor, entonces se modifica el extremo inferior pri
por el de la posición med + 1 caso contrario se modifica el extremo superior
ult por el de la posición med – 1, luego de lo cual se obtiene una nueva
posición med. Si después de reiteradas búsquedas no aparece el valor el
algoritmo finaliza cuando el valor extremo inferior pri se vuelva mayor al
valor del extremo superior ult.
Como vemos por cada comparación realizada se reduce a la mitad el
conjunto de valores a consultar, por lo tanto, el análisis será de:
n / 2, n / 4, n / 8; es decir, n / 2 1, n / 22, n / 23
El proceso finalizará cuando el tamaño se haga MENOR 1. Por lo tanto, si k
es el número mayor de comparaciones n / 2k MENOR 1 establecerá la
finalización.
Si tomamos un conjunto de 50000 elementos, la cantidad máxima de
comparaciones estará en el orden de log2 n = log2 50000 ~16. Por lo tanto,
con k = 16 se abandonará la búsqueda si aún no se encontró el valor de la
clave en el arreglo.
Ejemplo:
Se tiene el siguiente arreglo Arr con los siguientes elementos:
y se requiere buscar el valor 35, los pasos a realizar establecerán los
siguientes valores para los extremos y los puntos medios:
pri <-- 1, ult <-- 15, med <-- 8, como el valor de la pos. 8 es 56 y no es
igual a 35 la comparación siguiente 56 MENOR 35 es falsa se cambia el
extremo superior ult <-- med – 1 y med <-- 4, como el valor de la pos. 4 es
32 y no es igual a 35 la comparación siguiente 32 MENOR 35 es verdadera
se cambia el extremo inferior pri <-- med + 1 y med <-- 6, notamos que 43
MENOR 35 es falso se modifica ult <-- med – 1 y med <-- 5, por último
vemos que el valor de la pos. 5 35 es igual al valor a buscar que es 35, por
lo tanto hemos encontrado el valor clave. Tambien notamos que los
extremos en este último caso se hicieron iguales y justamente en esa
posición se encontraba el valor a buscar, este sería la última comparación a
realizar si el valor no se hubiera encontrado, debido a que en el próximo
paso el extremo inferior se volvería mayor al extremo superior, indicando
que no debemos seguir procesando la búsqueda.
OPERACIONES CON ARREGLO:
5 Operaciones Con Arreglos
Las operaciones en arreglos pueden clasificarse de la siguiente forma:
Lectura
Escritura
Asignación
Actualización
Ordenación
Búsqueda
a) LECTURA
Este proceso consiste en leer un dato de un arreglo y asignar un valor a cada uno de sus componentes.
La lectura se realiza de la siguiente manera:
para i desde 1 hasta N haz
x<--arreglo[i]
b) ESCRITURA
Consiste en asignarle un valor a cada elemento del arreglo.
La escritura se realiza de la siguiente manera:
para i desde 1 hasta N haz
arreglo[i]<--x
c) ASIGNACION
No es posible asignar directamente un valor a todo el arreglo, por lo que se realiza de la manera siguiente:
para i desde 1 hasta N haz
arreglo[i]<--algún_valor
d) ACTUALIZACION
Dentro de esta operación se encuentran las operaciones de eliminar, insertar y modificar datos. Para realizar
este tipo de operaciones se debe tomar en cuenta si el arreglo está o no ordenado.
Para arreglos ordenados los algoritmos de inserción, borrado y modificación son los siguientes:
1.- Insertar.
Si i< mensaje(arreglo contrario caso En arreglo[i]<--valor i<--i+1 entonces>
2.- Borrar.
Si N>=1 entonces
inicio
i<--1
encontrado<--falso
mientras i<=n y encontrado=falso
inicio
si arreglo[i]=valor_a_borrar entonces
inicio
encontrado<--verdadero
N<--N-1
para k desde i hasta N haz
arreglo[k]<--arreglo[k-1]
fin
en caso contrario
i<--i+1
fin
fin
Si encontrado=falso entonces
mensaje (valor no encontrado)
3.- Modificar.
Si N>=1 entonces
inicio
i<--1
encontrado<--falso
mientras i<=N y encontrado=false haz
inicio
Si arreglo[i]=valor entonces
arreglo[i]<--valor_nuevo
encontrado<--verdadero
En caso contrario
i<--i+1
fin
fin
ARREGLOS UNIDIMENSIONALES:
Un array de una dimensión (unidimensional), también llamado vector o fila, es un tipo de
datos estructurado compuesto de un número determinado de elementos, de tamaño fijo y
elementos homogéneos (del mismo tipo). La característica de tamaño fijo se refiere a que
el tamaño del array debe ser conocido en tiempo de compilación.
Por ejemplo, si deseamos conservar las puntuaciones de los 50 estudiantes de un
examen de informática, se necesita reservar cincuenta posiciones de memoria, dar un
nombre al arreglo y a cada uno de los 50 estudiantes asignarles una posición o índice del
arreglo.
OTRO UNIDIMENSIONAL
VECTORES (arreglos unidimensional)
Son aquéllos de una sola dimensión, por lo que también son llamados arreglos
Unidimensionales.
Ejemplo :
Un vector de una dimensión llamado CALIF, que consta de n elementos.
calif(1)
calif(2)
…
calif(n-2)
calif(n-1)
calif(n)
El subíndice o índice de un elemento (1, 2 …n) designa su posición en la ordenación del
vector. Otras posibles notaciones del vector son:
a1, a2,…,an En matemáticas y algunos lenguajes(BASIC)
A(1), A(2),…A(n)
A[1], A[2],…A[n] En programación (Pascal)
Los vectores se almacenan en memoria central de la computadora en un orden adyacente.
Así, un vector de 50 elementos denominado NUMEROS se representa gráficamente por 50
posiciones de memoria sucesivas.
Memoria
NUMEROS(1) Dirección x
NUMEROS(2) Dirección x+1
NUMEROS(3) Dirección x+2
NUMEROS(50) Dirección x+49
Cada elemento de un vector se puede procesar como si fuese una variable simple al ocupar
una posición de memoria. Así :
NUMEROS(25) 75 (almacena el valor 75 en la posición 25a del vector NUMEROS y la
instrucción de salida: Escribir NUMEROS(25).
NOMBRES: arreglo [1..10] de carácter
Significa que NOMBRES es un arreglo (array) unidimensional de 10 elementos (1 a 10) de
tipo carácter.
ASIGNACIÓN
NOMBRES(8) ‘Ana’
Asigna el valor ‘Ana’ al elemento 8 del vector NOMBRES.
ARREGLOS MULTIDIMENSIONALES:
Arreglos Multidimensionales
Este también es un tipo de dato estructurado, que está compuesto por n dimensiones. Para hacer referencia
a cada componente del arreglo es necesario utilizar n índices, uno para cada dimensión
Para determinar el número de elementos en este tipo de arreglos se usan las siguientes fórmulas:
RANGO (Ri) = lsi - (lii + 1)
No. TOTAL DE ELEMENTOS = R1 * R2* R3 * ...* Rn
donde:
i = 1 ... n
n = No. total de dimensiones
Para determinar la dirección de memoria se usa la siguiente formula:
LOC A[i1,i2,i3,...,in] = base(A) + [(i1-li1)*R3*R4*Rn + (i2-li2)*R3*R2*... (in - lin)*Rn]*w
ARREGLOS MULTIDIMENSIONALES
Los arreglos multimensionales se declaran de igual modo que los arreglos de una
dimensión.
La posición de cada uno de los elementos está determinada por dos subíndices,
que determinan la fila y la columna.
Los arreglos multimensionales (tablas) se crean con declaraciones type y var
cuando un programa se codifica en Pascal.
Se debe indicar:
1) Nombre del arreglo.
2) Tipo del arreglo.
3) El rango permitido.
Type
Identificador = array [indice1,indice2] of tipo elemento;
Var
Identificador1:identificador;
Ejemplo:
Type
Calificaciones = array [1..5,1..6] of integer;
Var
Calif: calificaciones;
FUNCIONES Y PROCEDIMIENTOS DEFINIDOS POR EL USUARIO
EN TURBO PASCAL
Funciones en Turbo Pascal:
Una función es un subprograma que recibe como argumentos o parámetros datos de un
tipo numérico o no numérico (char, string, bolean u otros) y devuelve un resultado. Esta
característica le diferencia de un procedimiento.
El pseudocódigo es el siguiente:
Nombre_función (argumento1,argumento2,...);
Los argumentos es lo que se conoce en Pascal como parámetros. Para poder calcular el
valor o resultado de la función, todo lo que se necesita conocer es el valor o valores de los
parámetros respectivos.
4.3.1 Funciones aritméticas o matemáticas
4.3.2 Funciones definidas por el usuario
Además de las funciones predefinidas citadas anteriormente, es posible que el usuario
pueda declarar sus propias funciones de igual modo que declara sus procedimientos.
Una función es un subprograma que devuelve un único resultado al programa o
subprograma que le llamó. La sintaxis es muy similar a la de un procedimiento.
Function nombre (parámetros): tipo
(declaración de variables locales)
begin
<cuerpo de la función>
nombre de la función := valor de la función
end;
Comparación entre funciones y procedimientos
En vez de la palabra procedure se debe utilizar la palabra function
Al igual que en los procedimientos, el nombre de una función es un identificador. Sin
embargo, el nombre de la función se refiere a la posición de memoria que contiene el
valor devuelto por la función.
La lista de los parámetros formales son los identificadores utilizados para recibir valores
del programa.
El tipo de datos del resultado coincide con el tipo expresado en la cabecera de la función.
En el cuerpo de la función tiene que existir una sentencia de asignación como la siguiente:
Nombre_función := valor_función
La función sólo devuelve un valor, el procedimiento puede devolver cero, uno o varios
valores.
El tipo de dato del resultado de la función debe estar indicado en la cabecera y puede ser
tipo char, integer, real o bolean.
Ejemplo:
Program Cubo;
Uses
Wincrt;
Var
Num,valor : integer;
Function El_cubo (Numero: integer):integer;
Begin
valor := Num*Num*Num;
End;
Begin
Write ('Digite un número entero: ');
Readln (Num);
El_cubo(Num);
Write ('El cubo de ',Num,' es ',valor);
End.
OTRAS FUNCIONES EN PASCAL:
FUNCIONES: una función es un subprograma que recibe como
argumentos o parámetros datos de tipo numérico o no numérico (char,
string, boolean u otros) y devuelve un resultado.
Las funciones pueden ser predefinidas o definidas por el usuario.
Ejemplo de algunas de las funciones predefinidas:
FUNCIO EFECTO TIPO DE TIPO DE
PARÁMETRO RESULTADO
N
Abs(x) Calcula valor absoluto Entero o real Entero o real
de x
* Calcula arcotangente Entero o real Real
Arctan(x) de x
* Cos(x) Calcula coseno de x Entero o Real
real
Exp(x) Calcula exponencial de x ( ex ) Entero o Real
real
Frac(x) Devuelve parte decimal de x Real Real
Int(x) Devuelve parte entera de x Real Real
Ln(x) Calcula logaritmo natural de x Entero o Real
real
Pi Devuelve el valor de Pi (3.1415…) Real Real
Round( Redondea el valor de x al entero Entero o Entero
x) positivo más próximo. real
Roun(-x) = Round(x)
* Sin(x) Calcula seno de x Entero o Real
real
Sqr(x) Calcula cuadrado de x Entero o Entero o
real real
Sqrt(x) Calcula raiz cuadrada de x (x>=0) Entero o Real
real
Trunc(x Suprime la parte decimal de x Real Entero
)
Log10(x Logaritmo base 10 Entero o Real
) real
NOTA1: las funciones marcadas con un * significa que el argumento es
siempre en radianes.
NOTA2: la expresión XY se escribe en Turbo Pascal de la siguiente
manera:
Exp(Y*Ln(x))
Ejemplos de funciones predefinidas:
Trunc(5.2) = 5 Trunc(5.99) = 5 Trunc(-3.14) = -3 Round(4.44) = 4
Round(18.5) = 19 Round(-7.15) = -7 Round(0.7) = 1 Abs(-63) = 63
Abs(3.97) = 3.97 Frac(28.437) = 0.437 Int(45.438) = 45.0
Exp(4.5) = e4.5 = 2.7982824.5
Otras funciones que utilizaremos en el curso son las siguientes:
Función UPCASE: cambia las letras minúsculas a letras
MAYÚSCULAS. Si las letras ya están en MAYÚSCULAS las deja igual.
forma: UPCASE (s); donde s es una expresión tipo char
Ejemplo: UPCASE(‘a’) ‘A’
UPCASE(‘A’) ‘A’
Función RANDOM: devuelve un número pseudoaleatoreo.
donde n debe ser una expresión entera de
valor mayor que 0, de ser 0 o negativo se
produce un error.
n es opcional
forma: RANDOM (n)
Si no existe n la función devuelve un número pseudoaleatorio en el
rango:
0<= número < 1
Si n existe la función devuelve un número entero pesudoaleatorio en
el rango:
0<= número < n
Función KEYPRESSED: es una función de valor lógico que devuelve
true (verdadero) si se ha pulsado una tecla en el teclado.
Forma: KEYPRESSED
PROCEDIMIENTOS EN PASCAL:
Los procedimientos son módulos que deben ser invocados para que su
código pueda ser ejecutado, ya que, si no se lo invocan están como en
un estado de hibernación. La comunicación entre la llamada y el módulo
se logra por medio de los parámetros. En el punto de la llamada se
denominan parámetros actuales, mientras que en la cabecera del
módulo se denominan parámetros formales. Un procedimiento está
estructurado en las siguientes partes:
Una cabecera que incluye:
La palabra reservada procedure
El identificador de procedimiento
Una lista de parámetros, que podrán ser pasados por valor o por
referencia; en este último caso deberá estar precedido con la palabra
reservada var.
Un área de definiciones y declaraciones de objetos locales.
Un cuerpo encerradas entre las palabras reservadas begin y end.
procedure IdProc(lista de parámetros);
var {Locales}
begin
sentencia; ...
end;
lista de parámetros es: Identificador, ... : tipo o var Identificador, ... : tipo
Si el parámetro no está precedido por la palabra reservada var, entonces
el parámetro es pasado por valor, esto es, con el valor pasado se hace
una copia en otra región de memoria y cualquier cambio que se hiciere,
en realidad no afectará al parámetro actual, por estar trabajando con la
copia, y no con el valor original. Este tipo de pasaje de parámetros es
utilizado cuando el valor se conoce antes de invocar al módulo y
deseamos pasar el valor al módulo para que realice algún proceso. Los
parámetros pasados por valor son parámetros de entrada y sirve para
inicializar al parámetro formal. El objeto que ocupa la misma posición, el
parámetro actual, puede ser una expresión, es decir, puede ser una
constante, una variable o una expresión propiamente dicha, p.e.:
Si el parámetro está precedido por la palabra reservada var, entonces el
parámetro es pasado por referencia, esto es, se pasa la dirección del
objeto, por lo tanto, este objeto, del parámetro actual, solo debe ser una
variable. El parámetro formal recibe la dirección, y al momento en que
se le asigne un valor dentro del módulo al parámetro formal, en realidad
se lo está asignando al parámetro actual, a través del parámetro formal.
Imaginemos que este parámetro formal es una catapulta que envía lo
que recibe a un único punto, al punto al que apunta, es decir en donde
está ubicada la variable –el parámetro actual-, cuya dirección es la que
recibió el parámetro formal. Este tipo de pasaje de parámetros es
utilizado cuando conocemos el valor dentro del módulo y queremos
dárselo al bloque que lo llamó a través de su parámetro actual o bien
conociendo previamente su valor, dentro del módulo invocado quizás
sufra alguna modificación y queremos informarlo al bloque que invocó al
módulo, por medio de su parámetro actual. Este tipo de parámetros
pasados por referencia son parámetros de salida o bien de entrada-
salida.
Las funciones son módulos que deben ser invocados para que su código
pueda ser ejecutado, ya que, si no se invocan están como en un estado
de hibernación. La comunicación entre la llamada y el módulo se logra
por medio de los parámetros. En el punto de la llamada se denominan
parámetros actuales, mientras que en la cabecera del módulo se
denominan parámetros formales.
Una función está estructurada en las siguientes partes:
Una cabecera que incluye:
La palabra reservada function
El identificador de la función.
Una lista de parámetros, que podrán ser pasados por valor, es lo más
habitual o por referencia; en este último caso deberá estar precedido
con la palabra reservada var.
El tipo de dato simple que retornará la función.
Un área de definiciones y declaraciones de objetos locales.
Un cuerpo encerradas entre las palabras reservadas begin y end, el
cual deberá tener al menos una sentencia de asignación y que asigne al
nombre de la función el resultado de una expresión que deberá coincidir
con el tipo en que fue definida en su cabecera.
function IdFunc(lista de parámetros) : tipo;
var {Locales}
begin
sentencia; ...
IdFunc <-- expresión end;
lista de parámetros es: Identificador, ... : tipo o var Identificador, ... : tipo
Si el parámetro no está precedido por la palabra reservada var,
entonces el parámetro es pasado por valor, esto es, con el valor pasado
se hace una copia en otra región de memoria y cualquier cambio que se
hiciere, en realidad no afectará al parámetro actual, por estar trabajando
con la copia, y no con el valor original. Este tipo de pasaje de parámetros
es utilizado cuando el valor se conoce antes de invocar al módulo y
deseamos pasar el valor al módulo para que realice algún proceso. Los
parámetros pasados por valor son parámetros de entrada y sirve para
inicializar al parámetro formal. El objeto que ocupa la misma posición, el
parámetro actual, puede ser una expresión, es decir, puede ser una
constante, una variable o una expresión propiamente dicha.
Si el parámetro está precedido por la palabra reservada var, entonces el
parámetro es pasado por referencia, esto es, se pasa la dirección del
objeto, por lo tanto, este objeto, del parámetro actual, solo debe ser una
variable. El parámetro formal recibe la dirección, y al momento en que
se le asigne un valor dentro del módulo al parámetro formal, en realidad
se lo está asignando al parámetro actual, a través del parámetro formal.
Imaginemos que este parámetro formal es una catapulta que envía lo
que recibe a un único punto, al punto al que apunta, es decir en donde
está ubicada la variable –el parámetro actual-, cuya dirección es la que
recibió el parámetro formal. Este tipo de pasaje de parámetros es
utilizado cuando conocemos el valor dentro del módulo y queremos
dárselo al bloque que lo llamó a través de su parámetro actual o bien
conociendo previamente su valor, dentro del módulo invocado quizás
sufra alguna modificación y queremos informarlo al bloque que invocó al
módulo, por medio de su parámetro actual. Este tipo de parámetros
pasados por referencia son parámetros de salida o bien de entrada-
salida.
PROCEDIMIENTOS EN PASCAL:
Subprogramas: Funciones y Procedimientos
Procedimientos
4.1.1 Concepto
Un procedimiento es un programa que realiza una tarea específica. Puede recibir cero
o más valores del programa que llama y devolver cero o más valores al programa que
realizó la llamada. Un procedimiento está compuesto de un grupo de sentencias a las
que se asigna un nombre (identificador) y constituye una unidad de programa. La tarea
asignada al procedimiento se ejecuta siempre que Pascal encuentra el nombre del
procedimiento.
Los procedimientos es obligatorio declararlos y deben ser declarados antes de que
puedan ser referenciados en el cuerpo del programa. En Pascal reciben el nombre de
PROCEDURE.
4.1.2 Declaración de un procedimiento
Al igual que los identificadores, los procedimientos deben declararse dentro del cuerpo
del programa. La declaración de un procedimiento NO indica a la computadora que
ejecute las instrucciones dadas, sino que indica a la computadora cuáles son estas
instrucciones y dónde están localizadas cuando sea necesario.
El formato del procedimiento es el siguiente:
Procedure nombreproc;
Declaraciones locales
Begin
Cuerpo del procedimiento
End;
A las variables que se encuentran dentro de un procedimiento se les llaman Variables
Locales y a las que se ubican en el cuerpo principal, fuera de los procedimientos, se
les llama Variables Globales.
En resumen, un procedimiento, al igual que un programa, consta de tres partes:
Una cabecera del procedimiento que proporciona el nombre del mismo y, en caso de
existir, una lista de parámetros formales.
Una sección de declaración que puede contener constantes, variables e incluso otros
procedimientos.
Una sección ejecutable: el cuerpo del procedimiento.
Ejemplo:
Program Recuadro;
Var I : Integer;
Procedure Estrellas;
(* Este procedimiento visualiza 15 asteriscos *)
Begin
For I := 1 to 15 do
Write (`*´)
End;
Begin
Estrellas; (* Llamado del procedure *);
Write (`Mensajes´);
Estrellas; (* Nuevo llamado del procedure *);
End.
4.1.3 Ventajas de utilizar procedimientos
La organización de un programa en procedimientos lo hace más fácil de escribir y
depurar. Los procedimientos no deben exceder de 25 líneas.
Las ventajas de utilizar procedimientos son:
Facilita el diseño descendente.
Los procedimientos se pueden ejecutar más de una vez en un programa y/o en
diferentes programas, ahorrando tiempo de programación.
El uso de procedimientos facilita la división de las tareas entre un equipo de
programadores y se pueden comprobar individualmente.
RECURSIVIDAD DE ARREGLOS EN PASCAL
Recursividad
Definición
Un procedimiento o función se dice recursivo si durante su ejecución se invoca
directa o indirectamente a sí mismo. Esta invocación depende al menos de una
condición que actúa como condición de corte que provoca la finalización de la
recursión.
Un algoritmo recursivo consta de:
1- Al menos un caso trivial o base, es decir, que no vuelva a invocarse y que se
ejecuta cuando se cumple cierta condición, y
2- el caso general que es el que vuelve a invocar al algoritmo con un caso más
pequeño del mismo.
Los lenguajes como Pascal, que soportan recursividad, dan al programador una
herramienta poderosa para resolver ciertos tipos de problemas reduciendo la
complejidad u ocultando los detalles del problema.
La recursión es un medio particularmente poderoso en las definiciones matemáticas.
Para apreciar mejor cómo es una llamada recursiva, estudiemos la descripción
matemática de factorial de un número entero no negativo:
1, si n = 0
n! =
n * ( n - 1 ) * ( n - 2 ) * .. * 1 = n * ( n - 1 )! si n > 0
Esta definición es recursiva ya que expresamos la función factorial en términos de sí
misma.
Ejemplo: 4! = 4 * 3!
Por supuesto, no podemos hacer la multiplicación aún, puesto que no sabemos el
valor de 3!
3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 0!
0! = 1
Podemos ahora completar los cálculos
1! = 1 * 1 = 1
2! = 2 * 1 = 2
3! = 3 * 2 = 6
4! = 4 * 6 = 24
Diseño de Algoritmos Recursivos
Para que una función o procedimiento recursivo funcione se debe cumplir que:
Existe una salida no recursiva del procedimiento o función y funciona
correctamente en ese caso.
Cada llamada al procedimiento o función se refiere a un caso más pequeño del
mismo.
Funciona correctamente todo el procedimiento o función.
Para poder construir cualquier rutina recursiva teniendo en cuenta lo anterior,
podemos usar el siguiente método:
Primero, obtener una definición exacta del problema.
A continuación, determinar el tamaño del problema completo a resolver. Así se
determinarán los valores de los parámetros en la llamada inicial al procedimiento
o función.
Tercero, resolver el caso base en el que problema puede expresarse no
recursivamente. Esto asegurará que se cumple el punto 1 del test anterior.
Por último, resolver correctamente el caso general, en términos de un caso más
pequeño del mismo problema (una llamada recursiva). Esto asegurará cumplir
con los puntos 2 y 3 del test.
Cuando el problema tiene una definición formal, posiblemente matemática, como el
ejemplo del cálculo del factorial, el algoritmo deriva directamente y es fácilmente
implementable en otros casos debemos encontrar la solución más conveniente.
Ejemplo
Cálculo del factorial para enteros no negativos
1, si n = 0
n! =
n*(n-1)! si n > 0
Diagrama de Llaves:
(*Pre: n >= 0*)
n=0 Factorial 1 (*Caso
base*)
Factorial(n)
n=0 Factorial n * Factorial (n-1) (*Caso Gral*)
(*Pos: Factorial = n!*)
Código Pascal:
function factorial(n: integer):integer;
begin
if n=0 then factorial = 1 (* caso base *)
else factorial = n * factorial(n-1) (* caso general *)
end;
ARCHIVOS SECUENCIALES INDEXADOS:
Archivos Secuenciales
La forma mas común de estructura de archivo es el archivo
secuencial. En este tipo de archivo, un formato fijo es usado para los
registros. Todos los registros tienen el mismo tamaño, constan del
mismo numero de campos de tamaño fijo en un orden particular.
Como se conocen la longitud y la posición de cada campo, solamente
los valores de los campos se necesitan almacenarse; el nombre del
campo y longitud de cada campo son atributos de la estructura de
archivos.
Un campo particular, generalmente el primero de cada registro se
conoce como el campo clave. El campo clave identifica unívocamente
al registro. así, los valores de la clave para registros diferentes son
siempre diferentes.
Los archivos secuenciales son típicamente utilizados en aplicaciones
de proceso de lotes Y son óptimos para dichas aplicaciones si se
procesan todos los registros. La organización secuencias de archivos
es la única que es fácil de usar tanto en disco como en cinta.
Para las aplicaciones interactivas que incluyen peticione s o
actualizaciones de registros individuales, los archivos secuenciales
ofrecen un rendimiento pobre.
Normalmente un archivo secuencial se almacena en bloques, en un
orden secuencial simple de los registros. La organización física del
archivo en una cinta o disco se corresponde exactamente con la
ubicación lógica del archivo. En este caso, el procedimiento para
ubicar los nuevos registros en un archivo de pila separado, llamado
archivo de registro (log file) o archivo de transacciones.
Periódicamente, se realiza una actualización por lotes
que mezcla el archivo de registro con el archivo maestro para
producir un nuevo archivo en secuencia correcta de claves.
2.3) Archivos Secuenciales indexados
Un método popular para superar las desventajas de los archivos
secuenciales es el del archivo secuencias indexado. El archivo
secuencial indexado mantiene las caracteristicas básicas de los
archivos secuenciales: los registros están organizados en una
secuencia basada en un campo. Dos características se añaden: un
índice del archivo para soportar los accesos aleatorios y un archivo
de desbordamiento ( overflow ). El indice provee una capacidad de
búsqueda para llegar rapidamente a las proximidades de un registro
deseado. El archivo de desbordamiento (overflow) es similar al
archivo de registro usado en un archivo secuencial, pero esta
intregrado de forma que los registros del archivo de desbordamiento
se ubican en la dirección de un puntero desde si registro precedente.
En la estructura secuencial indexada mas simple, se usa un solo nivel
de indexacion. El indice, en este caso, es un archivo secuencial
simple. Cada registro del archivo indice tiene dos campos: un campo
clave, que es el mismo que el campo clave del archivo principal y un
puntero al archivo principal. Para encontrar un campo especifico se
busca en el indice hasta encontrar el valor mayor de la clave que es
igual o precede al valor deseado de la clave. La busqueda continua
en el archivo principal a partir de la posición indicada por el puntero.
OTRO Archivos Secuenciales indexados
Un archivo secuencial indexado maneja tanto el acceso secuencial por valor de
llave, como el acceso directo a un registro en particular, dado su valor de llave.
Este tipo de organización de archivo se logra mediante la construcción de un índice
sobre un archivo de datos secuencial que reside en dispositivos de almacenamiento
de acceso directo.
Una buena implementación es a través del enfoque de árboles B+. Otro método
utiliza áreas primarias de datos y de sobrecarga y depende mas de las
características físicas de almacenamiento. Estos dos métodos difieren
principalmente , debido a su manera de tratar la condición de sobrecarga. Cuando
un bloque de datos o de índices, en un árbol B+ se desborda, éste es particionado.
Cuando una pista de datos se desborda con el segundo método, los registros son
colocados en un área de sobrecarga separada y encadenados juntos, para
mantener un orden de secuencia lógica de llaves.
Los compiladores que manejan archivos secuenciales indexados tienen una
interface con facilidades de manejo de datos extensivas que liberan al
programador de los detalles de implementación y mantenimiento de archivos
secuenciales indexados.
Los archivos secuenciales indexados son utilizados extensamente cuando existe la
necesidad de accesar registros tanto secuencial como directamente. Si sólo se
necesita de acceso secuencial, la organización secuencial de archivos generalmente
es más económica. Si sólo es necesario el acceso directo, entonces la organización
relativa de archivos requiere menos sobrecarga puesto que el acceso por orden de
secuencia lógica de llave no necesita ser manejado.
2.4) Archivos Indexados
Los archivos secuenciales indexados retienen la limitación del
archivo secuencial: la eficacia en el procesamiento se limita al
basado en un único campo del archivo. Cuando es necesario buscar
un registro basándose en algún otro atributo distinto del campo
clave ambas formas de archivo secuencial no son adecuadas. En
algunas aplicaciones esta flexibilidad es deseable.
Para alcanzar esta flexibilidad, se necesita una estructura que utilice
múltiples índices, uno para cada tipo de campo que pueda ser objeto
de la búsqueda.
Se suelen utilizar dos tipos de índices. Uno indice exhaustivo
contiene una entrada par cada registro del archivo principal. Otro
índice parcial contendrá entradas a los registros donde este el campo
de interés. Con registros de longitud variable, algunos registros no
contendran todos los campos.
Los archivos indexados son muy utilizados en aplicaciones donde es
critica la oportunidad de la informacion y donde los datos son rara
vez procesados de forma exhaustiva.
2.5) Archivos Directos o de Dispersión
Los archivos directos explotan la capacidad de los discos para
acceder directamente a cualquier bloque de dirección conocida.
Como en los archivos secuenciales y secuenciales indexados, se
requiere un campo clave en cada registro. Sin embargo, aquí no hay
concepto de ordenamiento secuencial.
OTRO ARCHIVO DIRECTOS O DE DISPERSION:
ARCHIVOS DIRECTOS O DE DISPERSIÓN =
+++ CONCEPTO +++
Los archivos directos explotan la CAPACIDAD de los discos para acceder
DIRECTAMENTE a cualquier bloque de dirección conocida. Como en los archivos
secuenciales y secuenciales indexados, se requiere un CAMPO CLAVE en cada
registro. Sin embargo, aquí NO hay concepto de ORDENAMIENTO SECUENCIAL. Los
archivos directos son muy usados donde se necesita un ACCESO muy RÁPIDO,
donde se usan registros de LONGITUD FIJA y donde siempre se ACCEDE a los
registrosg DE UNA VEZ.
La organización directa es aquella que permite un POSICIONAMIENTO sobre
registros específicos al LOCALIZAR una LLAVE. Lo anterior permite AGILIZAR la
localización de un dato en un archivo determinado al no requerirse el
procesamiento de los registros contiguos previos.
Un archivo se accesa directamente cuando el programa que lo utiliza especifica
directamente la posición dentro del archivo que se accesará. Por ejemplo el
programa puede leer la línea número 200, luego la línea 50000 y más tarde la línea
1. Es importante notar que para el sistema operativo todos los archivos pueden ser
accesados directamente. Para que un archivo se pueda accesar cómodamente en
forma directa, es necesario que sus líneas tengan un número fijo de caracteres. Por
esta razón, los archivos de acceso directo que usaremos en los ejemplos, tendrán la
extensión ".raf".
ARCHIVOS DISPERSOS.
También llamados (Hashed Files) representan un sistema de
almacenamiento de archivos que solo ofrece acceso directo, y
permiten calcular la posición de un registro en el almacenamiento
masivo.
Rudimentos de los archivos dispersos.
El usuario debe dividir el área de almacenamiento asignando al
archivo en varias secciones llamadas cubetas para poder ingresar los
datos.
La distribución de la información en las cubetas es problemática
debido a que la estructura de los archivos es dispersa.
Dentro de los archivos se presentan colisiones de información debido
al agrupamiento de los registros ingresados.
Cuestiones de programación.
Casi ninguno de los lenguajes de programación por procedimientos
en la actualidad ofrece implantaciones directas de archivos
dispersos; esto es debido a las cuestiones dependientes de la
aplicación implicadas en el diseño de estos archivos.
Capítulo 34:
Archivos tipificados o aleatorios
Son archivos que pueden contener datos tipo integer, real o record. Para declarar un
archivo se procede de la siguiente manera:
Type
Nombrearchivo = file oftipo de datos
Ejemplo:
Type
Nombres = file of string[60];
Var
Nom: Nombres;
8.3.1 Creación de un archivo tipificado
Para crear un archivo se utilizan las sentencias Assign la cual crea el archivo y Rewrite
para abrir el archivo.
La sintaxis es la siguiente:
Assign (f,nombre);
f: Nombre interno del archivo dentro del programa.
nombre: Nombre externo con el que se conoce al archivo por el sistema operativo.
La operación Assign establece una correspondencia entre la variable tipo archivo con
un archivo externo situado en disco.
8.3.1 Apertura de un archivo
Luego de haber sido asignado, el archivo debe ser abierto. Esta operación se realiza
por medio de uno de los dos procedimientos predefinidos: rewrite y reset.
8.3.1.1 Reset
Abre un nuevo archivo existente para una operación de lectura. Si se intenta llamar a
Reset y el archivo especificado no existe, se producirá un error de E/S
(entrada/salida).
Sintaxis:
Reset (NombreArch);
8.3.1.2 Rewrite
Crea y abre un nuevo archivo. Si el archivo ya existe, Rewrite borra su contenido; en
caso contrario, el archivo queda abierto para una operación de escritura.
Sintaxis:
Rewrite (f);
Existen algunos aspectos importantes que se deben tomar en cuenta al utilizar la
sentencia Rewrite:
- Si al abrir el archivo de texto, con assign y reset, ya existe en el disco, la
sentencia Rewrite lo rescribirá, en otras palabras, "se perderT el archivo contiguo.
- Por el contrario, las sentencias assign y rewrite suponen la existencia del
archivo llamado en el disco. Si este archivo no existe, las sentencias anteriores
producirán errores de ejecución.
El siguiente programa define un tipo registro (cliente) y a continuación rellena (pone
valores en los campos) en la variable correspondiente. Otra variable del mismo tipo se
asigna a la primera variable y los campos de la segunda variable se imprimen uno a
uno.
Program Visualiza_Registros;
Type
Datos = record
Nombre : String [80];
Direccion : String [80];
Edad : Integer;
Saldo : Real
End;
Var
Aux, Cliente : Datos;
Begin
Write (`Digite el nombre del cliente: `);
Readln (Cliente.Nombre);
Cliente.Dirección := `Calle El Último Grito´;
Write (`Digite la edad del cliente: `);
Readln (Cliente.Edad);
Cliente.Saldo := 245320;
Aux := Cliente; (* Transfiere los datos al registro Aux *)
(* Visualización de los campos de Aux *)
Writeln (`Nombre: `, Aux.Nombre);
Writeln (`Dirección: `, Aux.Direccion);
Writeln (`Edad: `, Aux.Edad:1);
Writeln (`Saldo: `, Aux.Saldo:1:1);
End.
Este método de lectura/escritura campo a campo es engorroso. Pascal proporciona la
sentencia with que facilitará el proceso de lectura/escritura de los registros.
8.3.2 - 8.3.3 Manipulación de archivos tipificados y funciones
8.3.2.1 Escritura de un archivo
Una vez que se ha abierto el archivo para escritura, las sentencias write y writeln
sirven para escribir datos en el nuevo archivo.
Sintaxis:
Write (f,v1,v2,...);
f es una variable tipo archivo.
v1,v2,... son variables del tipo de datos.
Ejemplos:
1. Write (demo,´Esto es una prueba de escritura´);
Writeln (demo,´y esta es la siguiente prueba´);
2. Var NombreArch : string[60];
archtex : text;
...
...
Write (`Nombre de archivo´);
Readln (NombreArch);
Assign (Archtex,NombreArch);
Reset (Archtex);
8.3.2.2 Lectura de un archivo
La lectura de un archivo se efectúa mediante las sentencias read o readln.
Sintaxis:
Read (f,v1,v2,...);
f es una variable tipo archivo.
v1,v2,... son variables del tipo de datos.
Ejemplo:
Var
Horas : Real;
Archivo : Text;
Mensaje : string [30];
Begin
Assign (Archivo,´Demo´);
Reset (Archivo);
...
...
Readln (Archivo,Mensaje,Horas);
End.
8.3.2.3 Cierre de un archivo
Para cerrar un archivo se utiliza la siguiente sintaxis:
Close (Nombrearchivo);