Estructuras Dinámicas de Datos

Anuncio
Estructuras Dinámicas de Datos
1.
Introducción.
Los datos estáticos pueden clasificarse en elementales y estructurados. Ambos tipos
de datos pueden ser internos si se encuentran en la memoria RAM del ordenador y externos si
están almacenados en un medio de almacenamiento masivo, como un disco duro o un CDROM.
Los datos dinámicos son sólo internos y no ocupan un tamaño fijo en la memoria
RAM.
Código Datos
Zona
libre
Figura 1. Disposición de un programa en memoria RAM.
La zona de datos contiene exclusivamente datos estáticos. Por otra parte, en la zona
libre el programa almacena los resultados parciales de su ejecución. En esta última zona
pueden realizarse las siguientes operaciones básicas:
•
•
obtener_nodo(p)
liberar_nodo(p)
donde p es un puntero a nodos.
Un puntero es una variable de un tipo de datos especial, el cual almacena la dirección
en memoria RAM donde hay un dato. Un puntero puede señalar incluso datos estructurados.
Los punteros a datos diferentes no se pueden mezclar y siempre deben inicializarse.
2.
Listas enlazadas.
Las listas enlazadas se dividen en ordenadas y no ordenadas.
plista
info
sig
info
sig
Figura 2. Lista enlazada.
1
info
sig
info
Sea plista el puntero a una lista enlazada. Una lista está vacía si y sólo si su puntero
plista tiene valor nulo.
registro nodolista
info: información;
sig: registro nodolista↑;
fregistro
2.1.
/* a definir previamente */
Algoritmos.
A continuación se indican los algoritmos que se van a desarrollar para la manipulación
de listas enlazadas no ordenadas:
1.
2.
3.
4.
5.
6.
Determinar si una lista está vacía.
Inicializar una lista.
Añadir nodos a una lista por el principio y por el final.
Localizar una información en una lista.
Suprimir un elemento de una lista.
Imprimir una lista.
Las operaciones a realizar sobre un puntero p, las cuales se codificarán en el lenguaje
de programación correspondiente, son:
•
•
•
p↑: nodo señalado por p.
p↑.info: campo de información del nodo señalado por p.
p↑.sig: puntero que señala al siguiente nodo. Puede tener valor nulo.
Se define NULO como una constante que indica que el puntero no apunta a ningún
nodo.
función lista_vacía(ent: plista: nodolista↑)
si plista = NULO
retorna cierto
sino
retorna falso
fsi
ffunción
función inilista(sal: plista: nodolista↑)
plista := NULO
ffunción
2
función añadir_principio(e/s: plista: nodolista↑; ent: a: información)
obtener_nodo(p);
p↑.info := a;
p↑.sig := plista;
plista := p
ffunción
función añadir_fin(e/s: plista: nodolista↑; ent: a: información)
var p, paux: nodolista↑ fvar
obtener_nodo(p);
p↑.info := a;
p↑.sig := NULO;
si lista_vacía(plista)
plista := p;
sino
paux := plista;
mientras paux↑.sig ≠ NULO
paux := paux↑.sig
fmientras
paux↑.sig := p
fsi
ffunción
función imprimir(ent: plista: nodolista↑)
var p: nodolista↑ fvar
p := plista;
mientras p ≠ NULO
escribir(p↑.info);
p := p↑.sig
fmientras
ffunción
función suprimir(e/s: plista: nodolista↑; ent: a: información;
sal: encontrado: lógico)
var p, paux, pant: nodolista↑ fvar
p := plista;
pant := NULO;
encontrado := falso;
mientras p ≠ NULO y no encontrado
si p↑.info = a
encontrado := verdadero
sino
pant := p;
p := p↑.sig
fsi
fmientras;
3
si encontrado
si pant = NULO
plista := p↑.sig
sino
pant↑.sig := p↑.sig
fsi;
liberar_nodo(p)
fsi
ffunción
plista
info
sig
info
sig
info
sig
info
sig
Figura 3. Lista circular.
plista
info
info
info
info
Figura 4. Lista doblemente enlazada.
2.2.
Ejercicios.
1.
Diseñar los subalgoritmos recursivos para imprimir una lista enlazada en orden directo
e inverso.
función imprimir(ent: plista: nodolista↑)
si no lista_vacía(plista)
escribir(plista↑.info);
imprimir(plista↑.sig)
fsi
ffunción
función imprimir_revés(ent: plista: nodolista↑)
si no lista_vacía(plista)
imprimir_revés(plista↑.sig);
escribir(plista↑.info)
fsi
ffunción
4
2.
Diseñar un algoritmo para suprimir el nodo i-ésimo de una lista enlazada.
función suprimir_iésimo(e/s: plista: nodolista↑; ent: i: entero;
sal: encontrado: lógico)
var
p, pant: nodolista↑;
cont: entero
fvar
p := plista;
pant := NULO;
encontrado := falso;
cont := 1;
mientras p ≠ NULO y cont < i
pant := p;
p := p↑.sig;
i := i + 1
fmientras;
si p ≠ NULO
si pant = NULO
plista := p↑.sig
sino
pant↑.sig := p↑.sig
fsi;
liberar_nodo(p);
encontrado := cierto
fsi
ffunción
3.
Escribir un programa que lea por teclado un conjunto de nombres de personas y su
correspondiente edad, construya una lista a medida que se lee la información, la
imprima y finalmente la elimine. Se supone que el formato de los datos de entrada es
un entero, un espacio y una secuencia de veinte caracteres. La entrada de datos finaliza
cuando se introduce una edad negativa.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TAM 21
struct informacion {
int edad;
char nombre[TAM];
};
struct nodo_l {
struct informacion info;
struct nodo_l *sig;
};
5
typedef struct nodo_l nodolista;
void inilista(nodolista **),
leer_datos(int *, char[]),
anadir_fin(nodolista **, nodolista *),
imprimir(nodolista *),
suprimir(nodolista *);
unsigned lista_vacia(nodolista *);
int main() {
nodolista *p, *plista;
char nombre[TAM];
int edad;
inilista(&plista);
leer_datos(&edad, nombre);
while (edad >= 0) {
p = (nodolista *) malloc (sizeof(nodolista));
(p->info).edad = edad;
strcpy((p->info).nombre, nombre);
p->sig = NULL;
anadir_fin(&plista, p);
leer_datos(&edad, nombre);
}
putchar('\n');
imprimir(plista);
suprimir(plista);
system("pause");
return 0;
}
void inilista (nodolista **plista) {
*plista = NULL;
}
void leer_datos(int *edad, char nombre[]) {
printf("Edad y nombre: ");
scanf("%d %s", edad, nombre);
}
void anadir_fin(nodolista **plista, nodolista *p) {
nodolista *paux;
if (lista_vacia(*plista))
*plista = p;
else {
paux = *plista;
while (paux->sig)
paux = paux->sig;
paux->sig = p;
}
}
6
unsigned lista_vacia(nodolista *plista) {
return plista == NULL;
}
void imprimir(nodolista *plista) {
nodolista *p = plista;
while (p) {
printf("Nombre: %s, Edad: %d.\n",
(p->info).nombre, (p->info).edad);
p = p->sig;
}
}
void suprimir(nodolista *plista) {
if (plista) {
suprimir(plista->sig);
free(plista);
}
}
3.
Pilas.
Son listas cuyos nodos se añaden y se suprimen por el principio de las mismas.
pila
Figura 5. Estructura de una pila.
3.1.
Algoritmos.
función pila_vacía(ent: pila: nodopila↑)
si pila = NULO
retorna cierto
sino
retorna falso
fsi
ffunción
7
función inipila(sal: pila: nodopila↑)
pila := NULO
ffunción
función apila(e/s: pila: nodopila↑; ent: p: nodopila↑)
p↑.sig := pila;
pila := p
ffunción
función desapila(e/s: pila: nodopila↑; sal: p: nodopila↑)
p := pila;
pila := pila↑.sig
ffunción
Antes de utilizar la función desapila() se debe comprobar que la pila no esté
vacía.
3.2.
Ejercicios.
1.
Escribir un programa que imprima una lista al revés utilizando una pila.
#include <stdio.h>
#include <stdlib.h>
typedef unsigned informacion;
struct nodo {
informacion info;
struct nodo *sig;
};
typedef struct nodo nodopilista;
void inilista(nodopilista **),
anadir_fin(nodopilista **, nodopilista *),
suprimir(nodopilista *),
inipila(nodopilista **),
apila(nodopilista **, nodopilista *),
desapila(nodopilista **, nodopilista **);
unsigned lista_vacia(nodopilista *),
pila_vacia(nodopilista *);
int main() {
nodopilista *plista, *pila, *p, *paux;
unsigned i;
inilista(&plista);
inipila(&pila);
8
for (i = 0; i <= 10; i++) {
p = (nodopilista *) malloc (sizeof(nodopilista));
p->info = i;
p->sig = NULL;
anadir_fin(&plista, p);
}
paux = plista;
while (paux) {
p = (nodopilista *) malloc (sizeof(nodopilista));
p->info = paux->info;
p->sig = NULL;
apila(&pila, p);
paux = paux->sig;
}
imprimir(pila);
suprimir(plista);
system("pause");
return 0;
}
void inilista (nodopilista **plista) {
*plista = NULL;
}
void anadir_fin(nodopilista **plista, nodopilista *p) {
nodopilista *paux;
if (lista_vacia(*plista))
*plista = p;
else {
paux = *plista;
while (paux->sig)
paux = paux->sig;
paux->sig = p;
}
}
unsigned lista_vacia(nodopilista *plista) {
return plista == NULL;
}
void suprimir(nodopilista *plista) {
if (!lista_vacia(plista)) {
suprimir(plista->sig);
free(plista);
}
}
void inipila(nodopilista **pila) {
*pila = NULL;
}
9
void apila(nodopilista **pila, nodopilista *p) {
p->sig = *pila;
*pila = p;
}
void desapila(nodopilista **pila, nodopilista **p) {
*p = *pila;
*pila = (*pila)->sig;
}
unsigned pila_vacia(nodopilista *pila) {
return pila == NULL;
}
imprimir(nodopilista *pila) {
nodopilista *p;
puts("Datos de la lista en orden inverso:\n");
while (!pila_vacia(pila)) {
desapila(&pila, &p);
printf("Dato: %u.\n", p->info);
free(p);
}
putchar('\n');
}
4.
Colas.
Son estructuras dinámicas donde los datos se añaden por el principio de éstas y se
extraen por el final de la mismas.
cola
info
sig
info
sig
info
sig
info
sig
info
p
Figura 6. Estructura de una cola.
4.1.
Algoritmos.
función inicola(sal: cola: nodocola↑)
cola := NULO
ffunción
10
sig
función cola_vacía(ent: cola: nodocola↑)
si cola = NULO
retorna cierto
sino
retorna falso
fsi
ffunción
función inscola(e/s: cola: nodocola↑; ent: p: nodocola↑)
si cola_vacía(cola)
p↑.sig := p
sino
p↑.sig := cola↑.sig;
cola↑.sig := p
fsi;
cola := p
ffunción
función sacacola(e/s: cola: nodocola↑; sal: p: nodocola↑)
si cola ≠ cola↑.sig
p := cola↑.sig;
cola↑.sig := p↑.sig
sino
p := cola;
cola := NULO
fsi
ffunción
Antes de utilizar la función sacacola() se debe comprobar que la cola no esté
vacía.
4.2.
Ejercicios.
1.
Diseñar los siguientes algoritmos para gestionar una cola con dos punteros: El primero
de ellos (CA) se usa para añadir elementos y el segundo (CS) para suprimirlos.
•
•
•
•
función cola_vacía(ent: ca, cs: nodocola↑)
función ini_cola(sal: ca, cs: nodocola↑)
función inscola(sal: cs: nodocola↑; e/s: ca: nodocola↑)
función sacacola(e/s: ca, cs: nodocola↑)
11
Descargar