Update PEC6
This commit is contained in:
parent
3333040be4
commit
7a8e9b99f4
@ -7,24 +7,21 @@
|
||||
- [18. Tipos abstractios de datos](#18-tipos-abstractios-de-datos)
|
||||
- [18.1. Tipo abstracto de datos (TAD)](#181-tipo-abstracto-de-datos-tad)
|
||||
- [18.1.1. Ejemplos de especificación e implementación](#1811-ejemplos-de-especificación-e-implementación)
|
||||
- [18.1.1.1 Ejemplo con números naturales](#18111-ejemplo-con-números-naturales)
|
||||
- [18.1.1.2 Ejemplo con números binarios](#18112-ejemplo-con-números-binarios)
|
||||
- [18.2 TAD para representar secuencias de elementos](#182-tad-para-representar-secuencias-de-elementos)
|
||||
- [18.1.1.1. Números naturales](#18111-números-naturales)
|
||||
- [18.1.1.2. Números binarios](#18112-números-binarios)
|
||||
- [18.2. TAD para representar secuencias de elementos](#182-tad-para-representar-secuencias-de-elementos)
|
||||
- [18.2.1. El TAD Pila (tStack)](#1821-el-tad-pila-tstack)
|
||||
- [18.2.1.1. Definición](#18211-definición)
|
||||
- [18.2.1.2. Operaciones](#18212-operaciones)
|
||||
- [18.2.1.3. Implementación](#18213-implementación)
|
||||
- [18.2.1.4 Ejemplo de uso](#18214-ejemplo-de-uso)
|
||||
- [18.2.1.1. Lista de operaciones sobre tStack](#18211-lista-de-operaciones-sobre-tstack)
|
||||
- [18.2.1.2. Implementación](#18212-implementación)
|
||||
- [18.2.1.3. Ejemplo de uso](#18213-ejemplo-de-uso)
|
||||
- [18.2.2. El TAD Cola (tQueue)](#1822-el-tad-cola-tqueue)
|
||||
- [18.2.2.1. Definición](#18221-definición)
|
||||
- [18.2.2.2. Operaciones](#18222-operaciones)
|
||||
- [18.2.2.3. Implementación](#18223-implementación)
|
||||
- [18.2.2.4 Ejemplo de uso](#18224-ejemplo-de-uso)
|
||||
- [18.2.2.1. Lista de operaciones sobre tQueue](#18221--lista-de-operaciones-sobre-tqueue)
|
||||
- [18.2.2.2. Implementación](#18222-implementación)
|
||||
- [18.2.2.3. Ejemplo de uso](#18223-ejemplo-de-uso)
|
||||
- [18.2.3. El TAD Lista (tList)](#1823-el-tad-lista-tlist)
|
||||
- [18.2.3.1. Definición](#18231-definición)
|
||||
- [18.2.3.2. Operaciones](#18232-operaciones)
|
||||
- [18.2.3.3. Implementación](#18233-implementación)
|
||||
- [18.2.3.4 Ejemplo de uso](#18234-ejemplo-de-uso)
|
||||
- [18.2.3.1. Lista de operaciones sobre tList](#18231--lista-de-operaciones-sobre-tlist)
|
||||
- [18.2.3.2. Implementación](#18232-implementación)
|
||||
- [18.2.3.3. Ejemplo de uso](#18233-ejemplo-de-uso)
|
||||
- [18.2.4. Sintaxis para la declaración (Definición de un TAD de tipo pila, cola o lista)](#1824-sintaxis-para-la-declaración-definición-de-un-tad-de-tipo-pila-cola-o-lista)
|
||||
- [19. Navegación de TAD](#19-navegación-de-tad)
|
||||
- [19.1. Ejemplos sobre el TAD pila](#191-ejemplos-sobre-el-tad-pila)
|
||||
@ -34,81 +31,896 @@
|
||||
|
||||
## 18. Tipos abstractios de datos
|
||||
|
||||
Vamos a ver los tipos abstractos de datos (TAD) y cómo se pueden implementar para representar secuencias de elementos como Listas, Colas y Pilas. Estos TADs emulan conceptos que encontramos fuera del mundo de la programación.
|
||||
|
||||
Unos ejemplos son:
|
||||
- De listas: una lista de la compra, una lista de tareas pendientes, una lista de reproducción de música.
|
||||
- De colas: una cola de espera en un supermercado, una cola de espera en una llamada telefónica.
|
||||
- De pilas: una pila de platos, una pila de libros, una pila de cartas.
|
||||
|
||||
Todos los TADs tienen una serie de operaciones que se pueden realizar sobre ellos. Por ejemplo, una pila tiene operaciones como `push` y `pop`, una cola tiene operaciones como `enqueue` y `dequeue`, y una lista tiene operaciones como `insert` y `delete`.
|
||||
|
||||
|
||||
### 18.1. Tipo abstracto de datos (TAD)
|
||||
|
||||
Un TAD consiste en un conjunto de valores (dominio) y el conjunto de operaciones que se pueden aplicar a este conjunto de valores.
|
||||
|
||||
El concepto de TAD ya existe en los lenguajes de programación bajo la forma de tipos predefinidos como `int`, `float`, `char`, `string`, etc. Pero también podemos definir nuestros propios TADs. Por ejemplo, en C, el tipo de datos `int` tiene como dominio todos los enteros en el rango `[MININT, MAXINT]` y las operaciones que se pueden aplicar: suma, resta, producto, cociente y módulo.
|
||||
|
||||
Implementar una TAD significa elegir una representación para el conjunto de valores del tipo de datos, así como codificar sus operaciones utilizando esa representación en un lenguaje de programación. Es posible tener varias implementaciones para un mismo TAD, pero dada la definición de un TAD, el comportamiento ha de ser siempre el mismo para cualquier implementación.
|
||||
|
||||
La utilidad de definir un TAD surge al diseñar nuevos tipos de datos. La idea es que el nuevo TAD solo puede ser manipulado a través de sus operaciones.
|
||||
|
||||
|
||||
#### 18.1.1. Ejemplos de especificación e implementación
|
||||
|
||||
##### 18.1.1.1. Números naturales
|
||||
|
||||
##### 18.1.1.1 Ejemplo con números naturales
|
||||
El conjunto de valores que engloba este TAD son todos los números enteros mayores o iguales a 0. Las operaciones que definiremos para aplicar a este conjunto son la `suma` y la `división`.
|
||||
|
||||
```alg
|
||||
type
|
||||
natural = integer;
|
||||
end type
|
||||
|
||||
function suma(x: natural, y: natural): natural
|
||||
return x + y;
|
||||
end function
|
||||
|
||||
function division(x: natural, y: natural): natural
|
||||
return x / y;
|
||||
end function
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned int natural;
|
||||
|
||||
natural suma(natural x, natural y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
natural division(natural x, natural y) {
|
||||
return x / y;
|
||||
}
|
||||
```
|
||||
|
||||
En esta definición no se han excluído los números negativos. La responsabilidad del correcto comportamiento del tipo yace en la definición de las operaciones.
|
||||
|
||||
|
||||
##### 18.1.1.2 Ejemplo con números binarios
|
||||
##### 18.1.1.2. Números binarios
|
||||
|
||||
El conjunto de valores que engloba este TAD son todos los números en su representación binaria, es decir, expresados en base 2. Las operaciones que definiremos para aplicar a este conjunto son `desplazamientoIzq` y `complemento`.
|
||||
|
||||
```alg
|
||||
const
|
||||
MAXBITS: integer:= 64;
|
||||
end const
|
||||
|
||||
type
|
||||
binario: vector[MAXBITS] of boolean;
|
||||
end type
|
||||
|
||||
action desplazamientoIzq(inout b:binario, in n integer)
|
||||
var
|
||||
i: integer;
|
||||
end var
|
||||
|
||||
for i:= n+1 to MAXBITS do
|
||||
b[i-n]:= b[i];
|
||||
end for
|
||||
|
||||
for i:= MAXBITS-n to MAXBITS do
|
||||
b[i]:= 0;
|
||||
end for
|
||||
end action
|
||||
|
||||
action complemento(inout b:binario)
|
||||
var
|
||||
i: integer;
|
||||
end var
|
||||
|
||||
for i:= 1 to MAXBITS do
|
||||
b[i]:= not b[i];
|
||||
end for
|
||||
end action
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAXBITS 64
|
||||
|
||||
typedef int binario[MAXBITS];
|
||||
|
||||
void desplazamientoIzq(binario b, int n) {
|
||||
int i;
|
||||
|
||||
for (i = n; i < MAXBITS; i++) {
|
||||
b[i-n] = b[i];
|
||||
}
|
||||
|
||||
for (i = MAXBITS-n; i < MAXBITS; i++) {
|
||||
b[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void complemento(binario b) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXBITS; i++) {
|
||||
b[i] = !b[i];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 18.2. TAD para representar secuencias de elementos
|
||||
|
||||
### 18.2 TAD para representar secuencias de elementos
|
||||
Una secuencia lineal es un conjunto de tamaño arbitrario de elementos del mismo tipo. Exceptuando el primero y el último, cada elemento tiene un único predecesor y un único sucesor.
|
||||
|
||||
En general, un TAD que representa secuencias de elementos posee las siguientes operaciones:
|
||||
- Inicializar la secuencia.
|
||||
- Insertar un elemento en la secuencia.
|
||||
- Eliminar un elemento de la secuencia.
|
||||
- Consultar el valor de un elemento en la secuencia.
|
||||
- Consultar el número de elementos de la secuencia.
|
||||
|
||||
¿Dónde insertar un elemento? ¿Qué elemento eliminar? ¿Qué elemento se puede consultar? ¿Cuántos elementos hay? Las respuestas a las anteriores preguntas son las que definen el comportamiento de las operaciones y, por lo tanto, el tipo de secuencia.
|
||||
|
||||
|
||||
#### 18.2.1. El TAD Pila (tStack)
|
||||
|
||||
- Una pila es una secuencia lineal de elementos.
|
||||
- Los elementos se insertan únicamente por un extremo de la secuencia. Por eso se dice que es una estructura LIFO (Last In, First Out).
|
||||
- La manipulación y acceso a los elementos de la pila se permite solo en un extremo de la secuencia.
|
||||
|
||||
Se puede pensar en una pila de libros dentro de una caja.
|
||||
|
||||
|
||||
##### 18.2.1.1. Definición
|
||||
##### 18.2.1.1. Lista de operaciones sobre tStack
|
||||
|
||||
| Operación | Descripción |
|
||||
| -------------- | ------------------------------------------------------------ |
|
||||
| `initStack` | Inicializa la pila. |
|
||||
| `push` | Empila un elemento en la pila. |
|
||||
| `pop` | Desempila un elemento de la pila. |
|
||||
| `top` | Devuelve copia del valor del elemento en la cima de la pila. |
|
||||
| `isEmptyStack` | Consulta si la pila está vacía (true). |
|
||||
| `isFullStack` | Consulta si la pila está llena (true). |
|
||||
| `heightStack` | Consulta el número de elementos de la pila. |
|
||||
|
||||
|
||||
##### 18.2.1.2. Operaciones
|
||||
##### 18.2.1.2. Implementación
|
||||
|
||||
Vamos a crear una implementación en un vector, donde tenemos un número máximo de elementos (MAX). Para conocer el espacio disponible de la pila en cada momento se necesita un atributo que indique el número total de elementos y que llamaremos nelem.
|
||||
|
||||
Implementación del tipo:
|
||||
|
||||
```alg
|
||||
type
|
||||
tStack = record
|
||||
A: vector[MAX] of elem; {elem represents the type of the elements in th tStack}
|
||||
nelem: integer;
|
||||
end record
|
||||
end type
|
||||
|
||||
typedef struct {
|
||||
elem A[MAX];
|
||||
int nelem;
|
||||
} tStack;
|
||||
```
|
||||
|
||||
Implementación de las operaciones del tipo:
|
||||
|
||||
Tanto la operación de apilar `push` como la de desapilar `pop`, la manipulación de elementos se realiza por el extremo final de la secuencia que es el tope de la pila.
|
||||
|
||||
```alg
|
||||
action initStack(out s: tStack)
|
||||
s.nelem:= 0;
|
||||
end action
|
||||
|
||||
action push(inout s: tStack, in e: elem)
|
||||
if s.nelem = MAX then
|
||||
{error full tStack}
|
||||
else
|
||||
s.nelem:= s.nelem + 1;
|
||||
s.A[s.nelem]:= e;
|
||||
end if
|
||||
|
||||
end action
|
||||
|
||||
action pop(inout s: tStack)
|
||||
if s.nelem = 0 then
|
||||
{error empty tStack}
|
||||
else
|
||||
s.nelem:= s.nelem - 1;
|
||||
end if
|
||||
end action
|
||||
|
||||
action top(in s: tStack, out e: elem)
|
||||
if s.nelem = 0 then
|
||||
{error empty tStack}
|
||||
else
|
||||
e:= s.A[s.nelem];
|
||||
end if
|
||||
end action
|
||||
|
||||
function isEmptyStack(s: tStack): boolean
|
||||
return s.nelem = 0;
|
||||
end function
|
||||
|
||||
function isFullStack(s: tStack): boolean
|
||||
return s.nelem = MAX;
|
||||
end function
|
||||
|
||||
function heightStack(s: tStack): integer
|
||||
return s.nelem;
|
||||
end function
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void initStack(tStack *s) {
|
||||
s->nelem = 0;
|
||||
}
|
||||
|
||||
void push(tStack *s, elem e) {
|
||||
if (s->nelem == MAX) {
|
||||
printf("\n Full Stack \n");
|
||||
} else {
|
||||
s->A[s->nelem] = e; /* First position in C is 0 */
|
||||
s->nelem++;
|
||||
}
|
||||
}
|
||||
|
||||
void pop(tStack *s) {
|
||||
if (s->nelem == 0) {
|
||||
printf("\n Empty Stack \n");
|
||||
} else {
|
||||
s->nelem--;
|
||||
}
|
||||
}
|
||||
|
||||
void top(tStack s, elem *e) {
|
||||
if (s.nelem == 0) {
|
||||
printf("\n Empty Stack \n");
|
||||
} else {
|
||||
*e = s.A[s.nelem-1];
|
||||
}
|
||||
}
|
||||
|
||||
bool isEmptyStack(tStack s) {
|
||||
return s.nelem == 0;
|
||||
}
|
||||
|
||||
bool isFullStack(tStack s) {
|
||||
return s.nelem == MAX;
|
||||
}
|
||||
|
||||
int heightStack(tStack s) {
|
||||
return (s.nelem);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##### 18.2.1.3. Implementación
|
||||
##### 18.2.1.3. Ejemplo de uso
|
||||
|
||||
Vamos a suponer un ejemplo de una pila de libros. Cada libro dispone de un código identificador y un nombre. Definimos las estructuras de datos necesarias para modelar el ejemplo:
|
||||
|
||||
```alg
|
||||
type
|
||||
tBook = record
|
||||
name: string;
|
||||
id: integer;
|
||||
end record
|
||||
|
||||
##### 18.2.1.4 Ejemplo de uso
|
||||
tBox = record
|
||||
A: vector[MAX] of tBook;
|
||||
nelem: integer;
|
||||
end record
|
||||
end type
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#define MAX_NAME_LEN = 25
|
||||
|
||||
typedef struct {
|
||||
char[MAX_NAME_LEN] name;
|
||||
int id;
|
||||
} tBook;
|
||||
|
||||
typedef struct {
|
||||
tBook A[MAX];
|
||||
int nelem;
|
||||
} tBox;
|
||||
```
|
||||
|
||||
Ok. Ahora vamos a implementar una acción que dada una pila de libros y el código de un libro, encuentre este libro en la pila. En caso de encontrarlo, lo retiramos de la pila; en caso contrario, dejamos la pila como estaba.
|
||||
|
||||
```alg
|
||||
|
||||
action findBook(inout s: tBox, in id: integer)
|
||||
var
|
||||
b: tBook;
|
||||
aux: tBox;
|
||||
found: boolean;
|
||||
end var
|
||||
|
||||
found:= false;
|
||||
initStack(aux);
|
||||
|
||||
while not isEmptyStack(s) and not found do
|
||||
top(s, b);
|
||||
|
||||
if b.id = id then
|
||||
push(aux, b);
|
||||
else
|
||||
found:= true;
|
||||
end if
|
||||
|
||||
pop(s);
|
||||
|
||||
end while
|
||||
|
||||
while not isEmptyStack(aux) do
|
||||
top(aux, b);
|
||||
push(s, b);
|
||||
pop(aux);
|
||||
end while
|
||||
|
||||
end action
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void findBook(tBox *s, int id) {
|
||||
tBook b;
|
||||
tBox aux;
|
||||
bool found;
|
||||
|
||||
found = false;
|
||||
initStack(&aux);
|
||||
|
||||
while (!isEmptyStack(*s) && !found) {
|
||||
top(*s, &b);
|
||||
|
||||
if (b.id == id) {
|
||||
push(&aux, b);
|
||||
} else {
|
||||
found = true;
|
||||
}
|
||||
|
||||
pop(s);
|
||||
}
|
||||
|
||||
while (!isEmptyStack(aux)) {
|
||||
top(aux, &b);
|
||||
push(s, b);
|
||||
pop(&aux);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 18.2.2. El TAD Cola (tQueue)
|
||||
|
||||
- Una cola es una secuencia lineal de elementos.
|
||||
- Los elementos se insertan por el final de la cola y se extraen por el principio. Por eso se dice que es una estructura FIFO (First In, First Out).
|
||||
- La manipulación y el acceso a los elementos de la cola solo se permite en los extremos.
|
||||
|
||||
##### 18.2.2.1. Definición
|
||||
Un ejemplo de una cola es una cola de personas esperando para comprar una entrada en la taquilla de un teatro.
|
||||
|
||||
##### 18.2.2.1. Lista de operaciones sobre tQueue
|
||||
|
||||
| Operación | Descripción |
|
||||
| -------------- | -------------------------------------------------------------- |
|
||||
| `initQueue` | Inicializa la cola. |
|
||||
| `enqueue` | Encola un elemento en la cola. |
|
||||
| `dequeue` | Desencola un elemento de la cola. |
|
||||
| `head` | Devuelve copia del valor del elemento en la cabeza de la cola. |
|
||||
| `isEmptyQueue` | Consulta si la cola está vacía (true). |
|
||||
| `isFullQueue` | Consulta si la cola está llena (true). |
|
||||
| `lengthQueue` | Consulta el número de elementos de la cola. |
|
||||
|
||||
|
||||
##### 18.2.2.2. Operaciones
|
||||
##### 18.2.2.2. Implementación
|
||||
|
||||
Vamos a crear una implementación en un vector, donde tenemos un número máximo de elementos (MAX). Para conocer el espacio disponible de la cola en cada momento se necesita un atributo que indique el número total de elementos y que llamaremos nelem.
|
||||
|
||||
Implementación del tipo:
|
||||
|
||||
```alg
|
||||
type
|
||||
tQueue = record
|
||||
A: vector[MAX] of elem;
|
||||
nelem: integer;
|
||||
end record
|
||||
end type
|
||||
```
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
elem A[MAX];
|
||||
int nelem;
|
||||
} tQueue;
|
||||
```
|
||||
|
||||
Implementación de las operaciones:
|
||||
|
||||
Los elementos se encolan por el final de la cola y se desencolan por el principio. Tened en cuenta que cada vez que se elemina un elemento se han de desplazar todos los elementos de la cola una posición a la izquierda.
|
||||
|
||||
```alg
|
||||
action initQueue(out q: tQueue)
|
||||
q.nelem:= 0;
|
||||
end action
|
||||
|
||||
action enqueue(inout q: tQueue, in e: elem)
|
||||
if q.nelem = MAX then
|
||||
{error full tQueue}
|
||||
else
|
||||
q.nelem:= q.nelem + 1;
|
||||
q.A[q.nelem]:= e;
|
||||
end if
|
||||
end action
|
||||
|
||||
action dequeue(inout q: tQueue)
|
||||
var
|
||||
i: integer;
|
||||
end var
|
||||
|
||||
if q.nelem = 0 then
|
||||
{error empty tQueue}
|
||||
else
|
||||
for i:= 1 to q.nelem-1 do
|
||||
q.A[i]:= q.A[i+1];
|
||||
end for
|
||||
|
||||
q.nelem:= q.nelem - 1;
|
||||
end if
|
||||
end action
|
||||
|
||||
action head(in q: tQueue, out e: elem)
|
||||
if q.nelem = 0 then
|
||||
{error empty tQueue}
|
||||
else
|
||||
e:= q.A[1];
|
||||
end if
|
||||
end action
|
||||
|
||||
function isEmptyQueue(q: tQueue): boolean
|
||||
return q.nelem = 0;
|
||||
end function
|
||||
|
||||
function isFullQueue(q: tQueue): boolean
|
||||
return q.nelem = MAX;
|
||||
end function
|
||||
|
||||
function lengthQueue(q: tQueue): integer
|
||||
return q.nelem;
|
||||
end function
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void initQueue(tQueue *q) {
|
||||
q->nelem = 0;
|
||||
}
|
||||
|
||||
void enqueue(tQueue *q, elem e) {
|
||||
if (q->nelem == MAX) {
|
||||
printf("\n Full Queue \n");
|
||||
} else {
|
||||
q->A[q->nelem] = e; /* first position in C is 0 */
|
||||
q->nelem++;
|
||||
}
|
||||
}
|
||||
|
||||
void dequeue(tQueue *q) {
|
||||
int i;
|
||||
|
||||
if (q->nelem == 0) {
|
||||
printf("\n Empty Queue \n");
|
||||
} else {
|
||||
for (i = 0; i < q->nelem-1; i++) {
|
||||
q->A[i] = q->A[i+1];
|
||||
}
|
||||
|
||||
q->nelem--;
|
||||
}
|
||||
}
|
||||
|
||||
void head(tQueue q, elem *e) {
|
||||
if (q.nelem == 0) {
|
||||
printf("\n Empty Queue \n");
|
||||
} else {
|
||||
*e = q.A[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool isEmptyQueue(tQueue q) {
|
||||
return (q.nelem == 0);
|
||||
}
|
||||
|
||||
bool isFullQueue(tQueue q) {
|
||||
return (q.nelem == MAX);
|
||||
}
|
||||
|
||||
int lengthQueue(tQueue q) {
|
||||
return (q.nelem);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##### 18.2.2.3. Implementación
|
||||
##### 18.2.2.3. Ejemplo de uso
|
||||
|
||||
Siguiendo el ejemplo de la cola de una taquilla. Cada cliente de la cola tiene asociado el ordinal en la cola desde que abrió la taquilla y la cantidad de entradas que desea adquirir. Definimos las estructuras de datos necesarias para modelar el ejemplo:
|
||||
|
||||
```alg
|
||||
type
|
||||
tClient = record
|
||||
num: integer;
|
||||
quantity: integer;
|
||||
end record
|
||||
|
||||
##### 18.2.2.4 Ejemplo de uso
|
||||
tTicketOffice = record
|
||||
A: vector[MAX] of tClient;
|
||||
nelem: integer;
|
||||
end record
|
||||
end type
|
||||
```
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
int num;
|
||||
int quantity;
|
||||
} tClient;
|
||||
|
||||
typedef struct {
|
||||
tClient A[MAX];
|
||||
int nelem;
|
||||
} tTicketOffice;
|
||||
```
|
||||
|
||||
Ahora necesitamos implementar una acción que atienda el primer cliente de la cola en la taquilla. La acción recibe como parámetros la cola `q` de clientes y un número `available` que indica la disponibilidad de entradas. En caso de haber suficientes entradas disponibles, se actualiza la cantidad de entradas disponibles y se devuelve el valor verdadero en el parámetro sold. Una vez el cliente es atendido, se elimina de la cola.
|
||||
|
||||
```alg
|
||||
action serverCliente(inout q: tTicketOffice, in available: integer, out sold: boolean)
|
||||
var
|
||||
c: tClient;
|
||||
end var
|
||||
|
||||
sold:= false;
|
||||
|
||||
if not isEmptyQueue(q) then
|
||||
head(q, c);
|
||||
|
||||
if c.quantity <= available then
|
||||
dequeue(q);
|
||||
available:= available - c.quantity;
|
||||
sold:= true;
|
||||
end if
|
||||
|
||||
dequeue(q);
|
||||
|
||||
end if
|
||||
end action
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void serverClient(tTicketOffice *q, int *available, bool *sold) {
|
||||
tClient c;
|
||||
|
||||
*sold = false;
|
||||
|
||||
if (!isEmptyQueue(*q)) {
|
||||
head(*q, &c);
|
||||
|
||||
if (c.quantity <= *available) {
|
||||
*available -= c.quantity;
|
||||
*sold = true;
|
||||
}
|
||||
|
||||
dequeue(q);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 18.2.3. El TAD Lista (tList)
|
||||
|
||||
- Una lista es una secuencia lineal de elementos.
|
||||
- Los elementos se insertan, se eliminan y se consultan en cualquier posición de la lista.
|
||||
|
||||
##### 18.2.3.1. Definición
|
||||
Para entender mejor el concepto de lista, podemos pensar en una lista de la compra del supermercado.
|
||||
|
||||
##### 18.2.3.1. Lista de operaciones sobre tList
|
||||
|
||||
| Operación | Descripción |
|
||||
| ------------- | ----------------------------------------------------------- |
|
||||
| `initList` | Inicializa la lista. |
|
||||
| `insert` | Inserta un elemento en la lista. |
|
||||
| `delete` | Elimina un elemento de la lista. |
|
||||
| `get` | Devuelve copia del valor del elemento en la posición `i`. |
|
||||
| `isEnd` | Consulta si la posición `i` es el final de la lista (true). |
|
||||
| `isEmptyList` | Consulta si la lista está vacía (true). |
|
||||
| `isFullList` | Consulta si la lista está llena (true). |
|
||||
| `lengthList` | Consulta el número de elementos de la lista. |
|
||||
|
||||
|
||||
##### 18.2.3.2. Operaciones
|
||||
##### 18.2.3.2. Implementación
|
||||
|
||||
Vamos a crear una implementación en un vector, donde tenemos un número máximo de elementos (MAX). Para conocer el espacio disponible de la lista en cada momento se necesita un atributo que indique el número total de elementos y que llamaremos nelem.
|
||||
|
||||
Implementación del tipo:
|
||||
|
||||
```alg
|
||||
type
|
||||
tList = record
|
||||
A: vector[MAX] of elem;
|
||||
nelem: integer;
|
||||
end record
|
||||
end type
|
||||
```
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
elem A[MAX];
|
||||
int nelem;
|
||||
} tList;
|
||||
```
|
||||
|
||||
Implementación de las operaciones:
|
||||
|
||||
Los elementos se insertan en cualquier posición de la lista y se eliminan de la misma forma.
|
||||
|
||||
Cada vez que se inserta un elemento en una posición `i`, se han de desplazar todos los elementos de la lista una posición a la derecha. Cada vez que se elimina un elemento de una posición `i`, se han de desplazar todos los elementos de la lista una posición a la izquierda.
|
||||
|
||||
```alg
|
||||
action initList(out l: tList)
|
||||
l.nelem:= 0;
|
||||
end action
|
||||
|
||||
action insert(inout l: tList, in e: elem, in index: integer)
|
||||
var
|
||||
i: integer;
|
||||
end var
|
||||
|
||||
if l.nelem = MAX then
|
||||
{error full tList}
|
||||
else
|
||||
for i:= l.nelem to index step -1 do
|
||||
l.A[i+1]:= l.A[i];
|
||||
end for
|
||||
|
||||
l.nelem:= l.nelem + 1;
|
||||
l.A[index]:= e;
|
||||
end if
|
||||
end action
|
||||
|
||||
action delete(inout l: tList, in index: integer)
|
||||
var
|
||||
i: integer;
|
||||
end var
|
||||
|
||||
if l.nelem = 0 then
|
||||
{error empty tList}
|
||||
else
|
||||
for i:= index to l.nelem-1 do
|
||||
l.A[i]:= l.A[i+1];
|
||||
end for
|
||||
|
||||
l.nelem:= l.nelem - 1;
|
||||
end if
|
||||
end action
|
||||
|
||||
action get(in l: tList, in index: integer, out e: elem)
|
||||
if l.nelem = 0 then
|
||||
{error empty tList}
|
||||
else
|
||||
e:= l.A[index];
|
||||
end if
|
||||
end action
|
||||
|
||||
function isEnd(l: tList, pos: integer): boolean
|
||||
return pos = l.nelem;
|
||||
end function
|
||||
|
||||
function isEmptyList(l: tList): boolean
|
||||
return l.nelem = 0;
|
||||
end function
|
||||
|
||||
function isFullList(l: tList): boolean
|
||||
return l.nelem = MAX;
|
||||
end function
|
||||
|
||||
function lengthList(l: tList): integer
|
||||
return l.nelem;
|
||||
end function
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void initList(tList *l) {
|
||||
l->nelem = 0;
|
||||
}
|
||||
|
||||
void insert(tList *l, elem e, int index) {
|
||||
int i;
|
||||
|
||||
if (l->nelem == MAX) {
|
||||
printf("\n Full List \n");
|
||||
} else {
|
||||
for (i = l->nelem; i >= index; i--) {
|
||||
l->A[i+1] = l->A[i];
|
||||
}
|
||||
|
||||
l->nelem++;
|
||||
l->A[index] = e;
|
||||
}
|
||||
}
|
||||
|
||||
void delete(tList *l, int index) {
|
||||
int i;
|
||||
|
||||
if (l->nelem == 0) {
|
||||
printf("\n Empty List \n");
|
||||
} else {
|
||||
for (i = index; i < l->nelem-1; i++) {
|
||||
l->A[i] = l->A[i+1];
|
||||
}
|
||||
|
||||
l->nelem--;
|
||||
}
|
||||
}
|
||||
|
||||
void get(tList l, int index, elem *e) {
|
||||
if (l.nelem == 0) {
|
||||
printf("\n Empty List \n");
|
||||
} else {
|
||||
*e = l.A[index];
|
||||
}
|
||||
}
|
||||
|
||||
bool isEnd(tList l, int pos) {
|
||||
return pos == l.nelem;
|
||||
}
|
||||
|
||||
bool isEmptyList(tList l) {
|
||||
return l.nelem == 0;
|
||||
}
|
||||
|
||||
bool isFullList(tList l) {
|
||||
return l.nelem == MAX;
|
||||
}
|
||||
|
||||
int lengthList(tList l) {
|
||||
return l.nelem;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
##### 18.2.3.3. Implementación
|
||||
##### 18.2.3.3. Ejemplo de uso
|
||||
|
||||
Siguiendo el ejemplo de la lista de la compra del supermercado. Cada artículo tiene asociado un nombre, el tipo de artículo clasificado según sea de panadería, frescos, bebidas, congelados, belleza o desayuno, y la cantidad de este artículo. Definimos las estructuras de datos necesarias para modelar el ejemplo:
|
||||
|
||||
```alg
|
||||
type
|
||||
tArticleType = {BAKERY, FRESH, DRINKS, FROZEN, BEAUTY, BREAKFAST}
|
||||
tArticle = record
|
||||
type: tArticleType;
|
||||
quantity: real;
|
||||
end record
|
||||
|
||||
##### 18.2.3.4 Ejemplo de uso
|
||||
tBuyList = record
|
||||
A: vector[MAX] of tArticle;
|
||||
nelem: integer;
|
||||
end record
|
||||
end type
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {BAKERY, FRESH, DRINKS, FROZEN, BEAUTY, BREAKFAST} tArticleType;
|
||||
|
||||
typedef struct {
|
||||
tArticleType type;
|
||||
float quantity;
|
||||
} tArticle;
|
||||
|
||||
typedef struct {
|
||||
tArticle A[MAX];
|
||||
int nelem;
|
||||
} tBuyList;
|
||||
```
|
||||
|
||||
Necesitamos implementar una acción que elimine de la lista de la compra `l`, todos los artículos de un tipo dado (filter) que se recibe como parámetro.
|
||||
|
||||
```alg
|
||||
action filterArticleType(inout l: tBuyList, in filter: tArticleType)
|
||||
var
|
||||
a: tArticle;
|
||||
pos: integer;
|
||||
end var
|
||||
|
||||
pos := 1;
|
||||
|
||||
while not isEnd(l, pos) do
|
||||
get(l, pos, a);
|
||||
|
||||
if a.type = filter then
|
||||
delete(l, pos);
|
||||
else
|
||||
pos := pos + 1;
|
||||
end if
|
||||
end while
|
||||
end action
|
||||
```
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
void filterArticleType(tBuyList *l, tArticleType filter) {
|
||||
elem a;
|
||||
int pos;
|
||||
|
||||
pos = 0;
|
||||
|
||||
while (!isEnd(*l, pos)) {
|
||||
get(*l, pos, &a);
|
||||
|
||||
if (a.type == filter) {
|
||||
delete(l, pos);
|
||||
} else {
|
||||
pos = pos + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 18.2.4. Sintaxis para la declaración (Definición de un TAD de tipo pila, cola o lista)
|
||||
|
||||
Para declarar un tipo pila dentro de un algoritmo, acción o función, se utiliza la siguiente sintaxis:
|
||||
|
||||
```alg
|
||||
nombreTipoPila = tStack(tipoElemento)
|
||||
```
|
||||
|
||||
por ejemplo, `tBinaryStack = tStack(tBit)` permite declarar el tipo tBinaryStack como un tipo de pila de elementos de tipo tBit. A partir de aquí, se le pueden aplicar todas las operaciones que se han definido para las pilas.
|
||||
|
||||
Como véis, en lenguaje algorítmico, la declaración queda como un tipo abstracto (su implementación es "oculta") pero en cambio, en lenguaje C, sí que se "ve" su implementación interna:
|
||||
|
||||
```c
|
||||
typedef struct{
|
||||
tBit A[MAXBITS];
|
||||
int nelem;
|
||||
} tBinaryStack;
|
||||
```
|
||||
|
||||
A partir de aquí, solo se debe utilizar con las funciones y acciones predefinidas para este tipo. De este modo, realmente lo estamos utilizando como un tipo abstracto pila.
|
||||
|
||||
De forma similar se puede declarar una cola o una lista:
|
||||
|
||||
```alg
|
||||
nombreTipoCola = tQueue(tipoElemento)
|
||||
nombreTipoLista = tList(tipolemento)
|
||||
```
|
||||
|
||||
|
||||
## 19. Navegación de TAD
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user