Paradigmas de Programación - UTN

Anuncio
UTN.- Paradigmas de Programación. 2009
Paradigmas de Programación
Programación Procedural. TAD’s.
Repaso de las principales características de la programación procedural.
Características de los lenguajes imperativos:
Son los lenguajes orientados a “sentencias”. La unidad de trabajo es la
sentencia. Los efectos de las sentencias individuales se combinan en un
programa para obtener los resultados deseados. Todos estos lenguajes se
basan fundamentalmente en la arquitectura tradicional de la computadora. Esto
se puede ver en tres características principales:
• variables: La componente principal de la arquitectura es la memoria, que
consta de un gran número de celdas. Es el lugar donde se almacenan los
datos. Los valores se almacenan en las celdas y se puede acceder a ellas
dando un nombre a dichas celdas. Esto está representado por el concepto
de variable.
• operación de asignación: Estrechamente ligado a la arquitectura de la
memoria se encuentra la idea de que el valor calculado debe ser
“almacenado”, es decir, asignado a una celda. Esta es la razón de la
importancia de la sentencia de asignación.
• repetición: un programa en un lenguaje imperativo, normalmente realiza su
tarea ejecutando repetidamente una secuencia de pasos elementales. Esto
es una consecuencia de la arquitectura, en la cual las instrucciones se
almacenan en memoria y la única manera de llevar a cabo algo complicado
es repitiendo una secuencia de instrucciones.
El papel de la abstracción
Como cualquier modelo, un programa es una abstracción de la realidad.
recordamos que, la abstracción es el proceso de identificación de las
propiedades importantes del problema que se está modelando, ignorando los
detalles irrelevantes.
La abstracción es el concepto clave en la teoría de la programación. En
concreto, tiene una doble relación con los lenguajes de programación. Por un
lado, los lenguajes son las herramientas con las que los diseñadores pueden
implementar los modelos abstractos (“los programas”). Por el otro, ellos mismos
son abstracciones del procesador sobre el cual se implementa el modelo. Sin
embargo, los primeros lenguajes no reconocían el papel crucial que la
abstracción juega en la programación. Por ejemplo, a comienzos de la década
del ‘50, el único mecanismo de abstracción proporcionado por los lenguajes
(ensambladores) sobre los lenguajes de máquina era la denominación
simbólica: se utilizaban mnemotécnicos o términos relativamente
autoexplicativos para denominar códigos de operación y posiciones de
memoria.
TADs - Página 1
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
Los subprogramas fueron también introducidos en los lenguajes de tipo
ensamblador como un mecanismo para denominar una actividad descrita por un
grupo de acciones y considerarla como una única acción. Los subprogramas
son mecanismos útiles para la construcción de abstracciones. Un subprograma
es la implementación de una abstracción mientras que la llamada a un
subprograma representa el uso de la abstracción. Cuando el programador
implementa un subprograma se encuentra en el cómo trabaja dicho
subprograma. Cuando se invoque este subprograma, ya no nos interesa el
“cómo” sino el “qué” hace. Esto se conoce como abstracción procedural.
También es posible definir abstracciones de datos. Las abstracciones
de datos modelan los datos manipulados por el programa.
Abstracciones de datos. Cómo aparecen en los lenguajes.
Los lenguajes a nivel de la máquina veían a los datos almacenados como
cadenas de bits que podían ser manipulados por las instrucciones de la
máquina. El repertorio de instrucciones incluía operaciones de desplazamientos,
lógicas, aritméticas en pto. flotante, etc.
Fortran, Cobol y Algol 60 dieron su primer paso hacia la introducción a la
abstracción de datos. En estos lenguajes, la información almacenada en
determinadas posiciones de memoria no se ve como una secuencia de bits
anónimos, sino como un valor entero, real, lógico, etc. Cada lenguaje tenia un
propósito fijo y de acuerdo a esto proveía los tipos adecuados. Como resultado,
ninguno de estos lenguajes resulto apropiado para TODAS las aplicaciones, ya
que el programador estaba limitado por la rigidez del conjunto fijo de
abstracciones proporcionado por el lenguaje.
El objetivo perseguido por los lenguajes de la siguiente generación
(Simula 67, Algol 68, Pascal) era incorporar mecanismos flexibles y fáciles de
usar por medio de los cuales el programador pueda definir
nuevas
abstracciones.
Algol 68 y Pascal permiten al programador usar tipos de datos
incorporados y constructores de nuevos tipos (matrices, registros).
Ejemplo: En Pascal:
type
estudiante=record
nombre:string[30];
legajo:integer;
end;
curso=array[1..60] of estudiante;
var
grupo_A:curso;
El tipo estudiante es una estructura de datos que consta de dos
componentes utilizado para guardar una identificación de un estudiante. El tipo
curso se define como una colección (arreglo) de estudiantes.
TADs - Página 2
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
Si quiero manipular los estudiantes de un curso, podría definir
procedimientos tales como:
• Insertar(grupo_A, unEstud);
• Eliminar(grupo_A, unEstud);
• Imprimir(grupo_A);
• etc.
Estos procedimientos están fuertemente relacionados con el tipo curso.
En concreto, son las operaciones que manipulan los objetos del tipo curso. Sin
embargo, esta relación lógica no queda evidente en el programa:
Ejemplo:
program demo;
type
............ // se mezclan con otros tipos
var
............ // se mezclan con otras variables
Proc,....
............ // se mezclan con otros procedimientos
begin
............
end.
Hay semejanzas entre los tipos definidos por el usuario de Pascal y los
tipos predefinidos. Por ejemplo, consideremos el tipo predefinido “integer” y el
tipo definido por el usuario “curso”. Los dos tipos son abstracciones construidas
sobre una representación interna: una cadena de bits para los integer y un
arreglo de registros para curso. Los dos tipos tienen asociados un conjunto de
operaciones: operaciones aritméticas y de comparación para los integer e
Insertar(..), Eliminar(..), Imprimir(..), etc. para curso.
Sin embargo, los tipos predefinidos y los tipos definidos por el usuario
difieren uno del otro en un aspecto muy importante. Los tipos predefinidos
ocultan al programador la representación interna: ésta no puede ser
manipulada directamente. Por ejemplo, el programador no puede acceder a un
bit en particular de la cadena de bits que representan al integer (si no dispone
de operaciones provistas para tal fin, obviamente). Por otra parte, los
procedimientos Insertar(..), Eliminar(..), Imprimir(..), etc., no son los únicos
medios para manipular un objeto de tipo curso. El programador puede operar
directamente sobre cada registro que compone el arreglo, sin estar obligado a
utilizar exclusivamente las operaciones definidas para el nuevo tipo.
Ejemplo:
grupo_A[15].legajo:=12345;
En otras palabras, desde el punto de vista del lenguaje, no hay distinción
entre dos niveles de abstracción: el nivel en el que se pueden utilizar cursos
como objetos nuevos y el nivel en el que se puede considerar la representación
de los cursos en términos de las abstracciones de mas bajo nivel.
TADs - Página 3
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
Esta confusión entre niveles de abstracción puede conducir a la
producción de programas difíciles de leer y lo que es más importante, reduce la
modificabilidad de los mismos. Por ejemplo, si cambiamos la representación
interna de los cursos a listas encadenadas necesitaríamos cambiar todos los
accesos directo a la representación interna (como la sentencia anterior) a los
largo de todo el programa.
En conclusión, si queremos definir nuevos tipos de datos en un
programa, seria deseable que el lenguaje me permitiera asociar una
representación con las operaciones para manipularla en una unidad adecuada
del lenguaje (“separada” del programa) y ocultar la representación interna del
nuevo tipo a las unidades que la usa.
Los tipos definidos por el usuario que satisfacen estas dos propiedades
se denominan “tipos abstractos de datos” (TAD). La primer propiedad hace
que la versión final del programa refleje las abstracciones descubiertas durante
la fase de diseño. La segunda propiedad enfatiza la distinción entre los niveles
de abstracción y favorece la modificabilidad de los programas.
Pascal, en su definición original, no proveía ningún mecanismo para la
construcción de TAD’s. Turbo Pascal tiene herramientas para cubrir la primer
propiedad (encapsular la definición del tipo con las operaciones para
manipularlo en una “unit”) pero no para ocultar la estructura interna del tipo.
Más adelante vamos a ver otro lenguaje (ADA) que provee mecanismos
que cubren las dos propiedades.
Ahora vamos a ver cómo se diseña utilizando TAD’s, cómo se identifica
un TAD en un problema. Antes vamos a recordar algunos principios de la
abstracción procedural o la técnica de diseño por refinamientos sucesivos..
REPASO:
Abstracción de procedimientos (refinamientos sucesivos)
Es el principio subyacente de la programación utilizando el diseño topdown (refinamientos sucesivos). Las ventajas de este estilo de programación ya
las vimos en el semestre pasado (en la materia Sintaxis y ..), pero vamos a
recordarlos:
“es un método que hace que la complejidad de un programa grande sea
manejable, controlando sistemáticamente la interacción entre sus
componentes”.
Esto es, un programa modular es más fácil de escribir, ya que enfocamos
nuestra atención en una tarea (procedimiento o función) a la vez.
La idea es que sabe “qué” es lo que hace un módulo y no “cómo” lo hace.
O sea, desde afuera NO PUEDO (no interesa) ver detalles de implementación de
ese módulo. Es como si estaría rodeado de “paredes” (walls) que impiden que
otros módulos sepan (vean) cómo fue implementado. Para poder utilizar los
módulos debemos especificar la forma en que se interactúa con ellos, es decir
debemos establecer un “contrato” en el cual se especifica cómo se lo debe
TADs - Página 4
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
invocar (con qué parámetros, de qué tipo, etc.) y qué se obtendrá como
resultado luego de ejecutar el módulo.
Todo esto no es nuevo. Es lo que vimos anteriormente sobre
refinamientos sucesivos, solo que ahora “formalizamos” un poquito más el
concepto.
Programa
que usa una
tarea
Implementa
request
retorno de la op. ción de la
tarea
La abstracción procedural particiona un programa en algoritmos
independientes, los cuales ejecutan tareas más pequeñas. Se piensa en
términos de qué es lo que un algoritmo hace, independientemente de cómo lo
hace.
En la abstracción de datos se piensa qué puedo hacer con una colección
de datos independientemente de cómo lo voy a hacer.
La abstracción de datos es una herramienta que nos permite desarrollar
las estructuras de datos en una forma relativamente independiente del resto de
la solución. Los otros módulos de la solución conocerán qué operaciones
pueden hacer con los datos pero no cómo están almacenados ni cómo se
ejecutarán las operaciones.
Ya vimos qué era un TAD: una colección de datos, más el conjunto de
operaciones para manipularlos. La definición de las operaciones debe ser
rigurosa, para especificar completamente el efecto que tiene sobre los
datos, pero no se especificará si los datos se almacenarán en posiciones
consecutivas de memoria, o en posiciones disjuntas, ni nada. Cuando se
implementa el TAD se elige una representación particular, una estructura de
datos (recordemos que son construcciones que provee el lenguaje para guardar
datos, por ejemplo, un array en Pascal).
Un TAD no es lo mismo que una estructura de datos. Por ejemplo, la
estructura de datos “curso” definida anteriormente no es un TAD.
Cuando un programa debe ejecutar operaciones sobre sus datos que no
están soportadas directamente por el lenguaje, se debe construir la estructura
de datos. Primero debería diseñar el TAD y entonces cuidadosamente
especificar las operaciones (el “contrato”). Entonces (y sólo entonces), debería
implementar las operaciones con una estructura de datos. Si se implementan las
operaciones apropiadamente, el resto del programa será capaz de ejecutar las
operaciones según fueron especificadas.
TADs - Página 5
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
En resumen, se usa el mismo concepto que para la abstracción
procedural: hay “paredes” (“walls”) entre un programa y sus estructuras de
datos. El “contrato” define qué operaciones puedo realizar con la estructura de
datos y qué resultados obtengo luego de ejecutar esas operaciones.
Programa
que usa la
estructura
de datos
request
return
Implementa
ción de la
estructura
de datos
Ejemplo: TAD lista ordenada
Consideremos una lista cualquiera (la lista del super, por ejemplo).
harina
arroz
gaseosas
huevos
yerba
azúcar
.......
El orden está dado por el orden en el cual se me fueron ocurriendo las
cosas (no necesariamente es un orden alfabético, sólo que un ítem tiene un
anterior y un siguiente)
Ahora pensemos, qué cosas podría hacer con la lista?
• contar los ítems para saber cuántas cosas tengo que comprar
(la longitud de la lista);
• agregar un elemento en la pos. i de la lista;
• eliminar el elemento de la posición i;
• ver el ítem que está en la posición i.
Cómo especificamos estas operaciones?
Procedure Crear(L)
{ Crea una lista ordenada L vacía}
Function Longitud(L) : integer
TADs - Página 6
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
{ Retorna el numero de ítems que están en la lista ordenada L}
Procedure Insertar(L, i, nuevo-item)
{ Inserta el nuevo-item en la posición i de la lista. El valor de i debe estar en el rango de 1 a
Longitud(L)+1. Si i<=Longitud(L), los ítems son desplazados como sigue: el ítem de la posición i
pasa a la posición i+1, el de la posición i+1 a la i+2, etc. y el de la posición Longitud(L), pasa a
la posición Longitud(L)+1. }
Procedure Eliminar(L,i)
{ Elimina el ítem de la posición i de la lista ordenada L. El valor de i debe estar en el rango de 1
a Longitud(L). Si i<Longitud(L), los ítems son desplazados como sigue: el ítem de la posición
i+1 pasa a la posición i, el de la posición i+2 a la i+1, etc. y el de la posición Longitud(L), pasa a
la posición Longitud(L)-1. }
Function Recuperar(L, i) : <tipo correspondiente a los ítems>
{ Retorna el ítem que se encuentra en la posición i de la lista ordenada L. El valor de i debe
estar en el rango de 1 a Longitud(L). La lista no cambia luego de esta operación (esta
operación no altera la lista)}
Las especificaciones de estas 5 operaciones son los términos del
“contrato” para el TAD lista ordenada. Notemos que estas especificaciones no
mencionan cómo se almacena la lista ordenada ni cómo se implementan las
operaciones. La definición del TAD únicamente dice lo que se puede hacer con
una lista ordenada.
Ejemplo:
Si queremos hacer una pequeña aplicación que intercambie dos
elementos de la lista que se encuentran en las posiciones i y j respectivamente:
Procedure Cambiar(L, i, j)
mo.
mo.
{ cambia el i y el j elemento de la lista ordenada L}
mo.
primero:= Recuperar(L, i);
{Copia el i ítem}
segundo:= Recuperar(L, j);
{Copia el j mo. ítem}
Eliminar(L.i);
Insertar(L, i, segundo);
{ Reemplaza el i
mo.
ítem con el j
mo.
Eliminar(L.j);
Insertar(L, j, primero);
{ Reemplaza el j
mo.
ítem con el i
mo.
}
}
Notar que esta aplicación NO necesita saber cómo está implementada la lista.
TADs - Página 7
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
Diseñando un TAD
El diseño de un TAD surge naturalmente durante el proceso de la
resolución del problema. Cuando Pascal (o el lenguaje que se va a utilizar) no
provee los tipos convenientes y un tipo definido por el usuario no es suficiente,
ya que no se puede definir las operaciones y las restricciones, entonces se
piensa en un TAD.
Ejemplo: Supongamos que queremos imprimir todas las fechas que sean
feriados del almanaque de un determinado año. Una posible solución sería:
tomar la fecha correspondiente al primer día del año
while la fecha no corresponda con el último dia del año
do begin
if la fecha corresponde a un día feriado
then Imprimirla
tomar la siguiente fecha
end;
En este problema aparace un tipo no provisto por Pascal: el tipo fecha.
Una fecha contiene dia, mes y año. ¿Qué operaciones serían necesarias?
• determinar la fecha correspondiente al 1er. día del año.
• determinar si una fecha corresponde al último día del año.
• determinar si una fecha es o no feriado.
• dado una fecha, determinar la fecha siguiente.
¿Cómo las especificamos?
Function PrimerDia(): fecha
{Retorna la fecha correspondiente al primer dia del año}
Function EsUltimoDia(unaFecha): boolean
{Retorna verdadero si unaFecha corresponde al último día del año}
Function EsFeriado(unaFecha): boolean
{Retorna verdadero si unaFecha corresponde a un día feriado}
Function SiguienteFecha(unaFecha): fecha
{Retorna la fecha del dia siguiente al la fcha dada}
¿Cómo quedaría la solución a nuestro problema en función del TAD fecha?
dia:= PrimerDia();
while not EsUltimoDia(dia)
do begin
if EsFeriado(dia)
then Imprimir(dia) (***)
dia:= SiguienteFecha(dia)
end;
TADs - Página 8
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
(***) En realidad, en este punto, nos damos cuenta que no podemos imprimir un
dato tipo fecha (porque no conocemos nada de él). Por lo tanto, necesitamos
definir más operaciones al TAD que no devuelvan el dia, mes y año de una
fecha dada y luego imprimir estos valores.
Function Dia(unaFecha): integer
{ Retorna el día de la fecha dada. El día estará en el rango de 1 a 31}
Function Mes(unaFecha): integer
{ Retorna el mes de la fecha dada. El mes estará en el rango de 1 a 12}
Function Anio(unaFecha): integer
{ Retorna el año de la fecha dada. El año estará en el rango de 0 a 2500}
Anteriormente diseñamos el TAD en función del problema/aplicación a
resolver. También podemos disñar el TAD y luego utilizarlo en alguna aplicación
(hacer el proceso inverso)
Ejemplo: Vamos a diseñar el TAD “Agenda”. ¿Qué operaciones necesitamos
proveer para manejar una agenda?
Las más obvias:
• agendar una actividad en un dia y hora determinado
• desagendar una acctividad previamente agendado en un dia y hora
determinado
Podemos pensar en otras dos operaciones que complementan las
anteriores.
• ver si hay una actividad agendad en un horario y dia determinado
• ver qué actividad está agendada en un horario y dia determinado
Estas dos operaciones podríamos combinarlas y especificarlas como una sola
operación.
Especificaciones:
Function CrearAgenda(): agenda
{ Retorna una agenda vacía}
Procedure Agendar(unaAgenda, fecha, hora, actividad)
{ Agrega en la agenda la actividad en el dia y hora dado asumiendo que ese horario está libre}
Procedure Desagendar(unaAgenda, fecha, hora)
{ Borra la actividad agendada en la fecha y hora dada}
Procedure VerActividad(unaAgenda, fecha, hora, hayActividad, unaActividad)
{determina si existe o una actividad agendada en la fecha y hora dada. Si hay, setea hayAct en
true y retorna la actividad agendad en unaActividad. Si no hay nada agendado setea hayAct en
false}
Aplicación:
TADs - Página 9
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
Supongamos que queremos cambiar el día y hora de una actividad
particular (esto que lo hagan ellos - a lo sumo en la práctica)
Leer(diaAnt, horaAnt, diaNuevo, horaNueva,);
VerActividad(agenda, diaAnt, horaAnt, hayAct, acti);
if hayAct { verifico que verdaderamente estaba algo agendado}
then begin
VerActividad(agenda, diaNuevo, horaNueva, hayAct, acti);
if hayAct { si ya tengo algo agendado en ese horario}
then write(“Ud. ya tiene agendada otra actividad en el nuevo horario”)
else { el horario está libre}
begin
Agendar(agenda, diaNuevo, horaNueva, acti);
Desagendar(agenda, diaAnt, horaAnt);
end;
end;
else
write(“Ud. no tiene agendada ninguna actividad en ese horario”);
Al diseñar TAD’s nos podemos encontrar con otros TAD’s. por ejemplo,
en el TAD anterior (agenda) hacemos referencia a fechas, y éstas podrían ser
datos abstractos.
Esto es, se puede utilizar un TAD para implementar otro TAD.
Otro Ejemplo: queremos armar una base de datos de recetas (un recetario). Las
operaciones para manipularlo sería:
Procedure Crear(recetario)
{Crea un recetario vacío}
Procedure Insertar(recetario, receta)
{Agrega la receta al recetario. Se asume que la receta NO está en el recetario}
Procedure Eliminar(recetario, receta)
{Elimina la receta del recetario. Asume que la receta está en el recetario}
Function Recuperar(recetario, nombreReceta): Receta
{Retorna la receta del recetario cuyo nombre coincide con nombreReceta}
Function Esta(recetario, nombreReceta):Boolean
{ Retorna true si la receta cuyo nombre es nombreReceta está en el recetario y false en caso
contrario}
En este caso, podríamos pensar en definir otro TAD: Receta que
contengan la información de una receta, con operaciones como:
Function Nombre(receta): string[50]
{Retorna el nombre de la receta}
Esta función sería utilizada por las operaciones Recuperar y Esta para
obtener el nombre de las recetas y compararlos con el nombreReceta recibido
como parámetro en el momento de implementar el TAD recetario.
TADs - Página 10
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
Implementación de TAD’s
Tenemos que ver cómo guardar los datos y cómo realizar las operaciones
especificadas anteriormente.
TAD Lista Ordenada.
Tenemos dos opciones para almacenar los datos:
• utilizar arreglos
• utilizar punteros (listas encadenadas)
Recordamos la especificación del TAD:
Procedure Crear(L)
{ Crea una lista ordenada L vacía}
Function Longitud(L) : integer
{ Retorna el numero de ítems que están en la lista ordenada L}
Procedure Insertar(L, i, nuevo-item)
{ Inserta el nuevo-item en la posición i de la lista. El valor de i debe estar en el rango de 1 a
Longitud(L)+1. Si i<=Longitud(L), los ítems son desplazados como sigue: el ítem de la posición i
pasa a la posición i+1, el de la posición i+1 a la i+2, etc. y el de la posición Longitud(L), pasa a
la posición Longitud(L)+1. }
Procedure Eliminar(L,i)
{ Elimina el ítem de la posición i de la lista ordenada L. El valor de i debe estar en el rango de 1
a Longitud(L). Si i<Longitud(L), los ítems son desplazados como sigue: el ítem de la posición
i+1 pasa a la posición i, el de la posición i+2 a la i+1, etc. y el de la posición Longitud(L), pasa a
la posición Longitud(L)-1. }
Function Recuperar(L, i) : <tipo correspondiente a los ítems>
{ Retorna el ítem que se encuentra en la posición i de la lista ordenada L. El valor de i debe
estar en el rango de 1 a Longitud(L). La lista no cambia luego de esta operación (esta
operación no altera la lista)}
Implementación basada en arreglos.
................. .
Longitud
Items
Podría definir la lista como un registro con dos campos:la longitud de la
lista y los ítems en sí.
const
type
maxlen=100;
itemType=<tipo de los items de la lista>
listaOrdenada=record
long:integer;
TADs - Página 11
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
items:array[1..maxlen] of itemType;
end;
var
L:listaOrdenada;
algunas de las operaciones quedarían:
Procedure Crear (var L: listaOrdenada)
{ Crea una lista ordenada L vacía}
begin
L.Long:=0;
end;
Function Longitud(L:listaOrdenada): integer;
{ Retorna el numero de ítems que están en la lista ordenada L}
begin
Longitud:=L.long;
end;
Procedure Insertar(var L: listaOrdenada; i:integer; nuevoItem:itemType)
{ Inserta el nuevo-item en la posición i de la lista. El valor de i debe estar en el rango de 1 a
Longitud(L)+1. Si i<=Longitud(L), los ítems son desplazados como sigue: el ítem de la posición i
pasa a la posición i+1, el de la posición i+1 a la i+2, etc. y el de la posición Longitud(L), pasa a
la posición Longitud(L)+1. }
begin
if ((i<1) and i>Longitud(L)+1) or (Longitud(L)=maxlen)
then Indicar que hay un ERROR
else begin
{desplazar los ítems}
for j:= Longitud(L) downto i do
L.items[j+1]:=L.items[j];
{ Insertar el nuevo item}
L.items[i]:= nuevoItem;
L.long:=L.long+1;
end;
end;
…………………
Implementación basada en punteros (listas encadenadas)
long head
item
sgte
Para no tener la restricción del tamaño fijo del arreglo.
type
itemType=<tipo de los items de la lista>
ptr
= .. nodo;
nodo =record
item: itemtype;
sigte:ptr;
end;
TADs - Página 12
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
listaOrdenada=record
long:integer;
head:ptr;
end;
var
L:listaOrdenada;
las operaciones quedarían:
Procedure Crear (var L: listaOrdenada)
{ Crea una lista ordenada L vacía}
begin
L.long:=0;
L.head:=nil;
end;
Function Longitud(L:listaOrdenada): integer;
{ Retorna el numero de ítems que están en la lista ordenada L}
begin
Longitud:=L.long;
end;
Para implementar las otras operaciones necesitamos acceder a la
posición i de la lista, cosa qu la estructura elegida no me lo provee (las listas
enganchadas no tienen acceso directo a sus componenetes). Por lo tanto,
podríamos pensar en definir una operación propia del TAD llamasda SetPtr,
que retorna el puntero al nodo que se encuentra en una posición especificada.
Otra vez, esta operación NO estaría disponible para las aplicaciones que usen
la lista ordenada, sino que la es “privada” del TAD, me sirve para implementar
las operaciones restantes.
Function SetPtr(L: listaOrdenada; i:integer):ptr
{Retorna un puntero al nodo que se encuentra en la posición i.
Si i<1 o i>Longitud(L), retorna un puentero nulo}
begin
if (i<1) or (i>Longitud(L))
then SetPtr:= nil
else begin
p:=L.head;
for j:=1 to i-1 do p:=p..sigte;
SetPtr:=p;
end;
end;
algunas de las operaciones quedarían:
TADs - Página 13
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
UTN.- Paradigmas de Programación. 2009
Function Recuperar (L: listaOrdenada; i:integer)
{ Retorna el ítem que se encuentra en la posición i de la lista ordenada L. El valor de i debe
estar en el rango de 1 a Longitud(L). La lista no cambia luego de esta operación (esta
operación no altera la lista)}
begin
if (i<1) or i>Longitud(L)
then Indicar que hay un ERROR
else begin
p:=SetPtr(i);
Recuperar := p..item; { No testeo por p<>nil porque ya lo testee al ppio.}
end;
end;
……………………
TADs - Página 14
PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com
Descargar