Sunteți pe pagina 1din 33

TDA LISTA

ESTRUCTURAS DE DATOS

OBJETIVOS

Aprovechar la abstraccin para definir comportamiento y luego operaciones en nivel de implementacin Visualizar las posibles implementaciones de un TDA ya definido Utilizar con seguridad el concepto de puntero en implementaciones dinmicas Reconocer la importancia de usar solo el comportamiento de un TDA, y no su estado

LISTAS: DEFINICION

Una lista es

Una coleccin de 0 o mas elementos

Si la lista no tiene elementos, se dice que esta vaca

En una lista, todos los elementos son de un mismo tipo


Sus elementos estn colocados uno detrs de otro Cada elemento de una lista se conoce con el nombre de NODO Son mucho ms flexibles que los arreglos Permiten trabajo dinmico con un grupo de elementos

Son estructuras lineales, es decir


Las listas

TIPOS

De acuerdo a su comportamiento, los conjuntos lineales se clasifican en

Listas, Pilas y Colas

De acuerdo a su implementacin, las listas se clasifican en


Simples Doblemente Enlazadas Circulares

LISTAS SIMPLES

Se define como un conjunto de nodos


Uno detrs de otro Del cual siempre se puede conocer al nodo inicial y al final

De cada nodo de la lista, se conoce

Un contenido, que es la informacin que almacena dentro

Puede ser de cualquier tipo de dato

Un sucesor nico

Excepto el ultimo nodo de la lista

LISTA SIMPLE: NIVEL LOGICO

Comportamiento (a/con una lista se puede)


Crear y Eliminar Conocer si esta vaca Aadir elementos y removerlos Consultar el primer y al ultimo elemento Imprimir sus elementos en pantalla Buscar un elemento con cierta informacin en la lista

Estado:
<listaSimple> ::= <comienzo> + {<ref_nodo>} + <final> <comienzo> ::= <enlace> <final> ::= <enlace>

TDA NODO: NIVEL LOGICO


Una lista esta compuesta de nodos, y por eso es importante definir el TDA Nodo Un nodo de una lista

Almacena informacin de cualquier tipo dentro y Es capaz de viajar o conocer otro nodo(el nodo siguiente) Crear y Eliminar Consultar y modificar la informacin que almacena Consultar y modificar el enlace que mantiene con otro nodo <nodo> <enlace> ::= <contenido> + <enlace> ::= <ref_nodo> | <ref_invalida>

Comportamiento

<contenido> ::= <dato>{<dato>}

LISTAS SIMPLES: NIVEL DE IMPLEMENTACION

Tenemos el concepto claro de lo que debe ser una lista


Ahora debemos ir al detalle: como darle vida a una lista

Hay varias posibilidades de implementacin


Esttica o Contigua, usando arreglos de longitud variable Dinmica, utilizando punteros

IMPLEMENTACION CONTIGUA

Se utilizan arreglos, por lo tanto


Tiene limites, que no pueden ser rebasados al aadir nuevo elementos Los nodos son adyacentes en memoria

Cada nodo es realmente un elemento del arreglo Entonces, el enlace con el siguiente nodo seria simplemente el indice del siguiente elemento dentro del arreglo OJO: En este tipo de implementacin no es necesario crear el TDA Nodo

Al crearla se debe indicar el tamao mximo del arreglo Al insertar o remover un elemento,

Todos los elementos restantes avanzarn o retrocedern

en una cierta posicin, todos los elementos restantes ruedan

No es la implementacion ideal para las listas simples Al insertarse un 25 nuevo elemento,


10 5 8 2 25 31 2 31

2 3 En uso

6 7 Desperdicio

CONTIGUAS: OPERACIONES

Creacin y Eliminacin

Busqueda y Recorrido

LSCont *LSCont_Crear(int n);

void LSCont_Vaciar(LSCont *L);


int LSCont_BuscarNodo(LSCont L, Generico G, Generico_ComoComparar fn); bool LSCont_EsNodoDeLista(LSCont L, int i); void LSCont_Recorrer(LSCont L, Generico_ComoImprimir fn);

Aadir y Remover elementos

void LSCont_InsertarNodoInicio(LSCont *L, Generico G); void LSCont_InsertarNodoFin(LSCont *L, Generico G); Generico LSCont_SacarNodoInicio(LSCont *L); Generico LSCont_SacarNodoFin(LSCont *L);

Consultar indice del Ultimo

int LSCont_ConsultarUltimo(LSCont L);


bool LSCont_EstaVacia(LSCont L); bool LSCont_EstaLlena(LSCont L);

Consultar estado de la lista, puede llenarse


CONTIGUAS: DECLARACION

La lista contigua
Es un arreglo de elementos de cualquier tipo realmente es un ARRAYU No olvidemos que hay que predefinir el mximo de nodos de la lista

Para lograr mantener control sobre la cantidad de elementos en la lista


Debe existir una referencia que controle el ultimo elemento La referencia al ultimo se mover de acuerdo a las inserciones y eliminaciones La primero nunca se mueve, siempre ser 0

typedef struct{ int ultimo; ArrayU Elementos; }LSCont;

header=0
10 5 8 25 2

last
31

MAX

Elementos

CONTIGUA: BASICAS
El ndice del ltimo elemento debe ser un ndice invlido, un valor negativo. No importara que el arreglo tenga elementos pues no sern tomados en cuenta.

last

last

-1

9
MAX-1

void LSCont_VaciarLista(LSCont *L){ L->ultimo = -1; } LSCont *LSCont_CrearLista(int max){ LSCont *nuevalista; nuevalista->Elementos = ArrayU_Crear(max, 0); nuevalista->ultimo = -1; return nuevalista; } void LSCont_EliminarLista(LSCont *L){ LSCont_VaciarLista(L); } } ArrayU_Eliminar(&(L->Elementos)); Si la lista est llena es } bool LSCont_EstaLlena(LSCont L){ return (L.ultimo == bool LSCont_EstaVacia(LSCont L){ return(L.ultimo<0);

ArrayU_Tamanio(L.Elementol)-1);

porque el ndice del ltimo ha llegado al verdadero ltimo ndice posible en el arreglo: MAX -1

CONTIGUA: BUSQUEDA
int LSCont_BuscarNodo(LSCont L, Generico G, Generico_Comparacion fn){ int i; Generico elemento; for(i = 0; i <=L.ultimo;i++){ elemento = ArrayU_ElemC(L.Elementos, i); if(f(elemento, G) == 0) return (i)

}
return(-1); }

CONTIGUA: INSERTAR
last last 9 10 0 10 1 1 1 5 2 5 8 3 8 4 5 6 7 8 9 bool LSCont_Insertar(LSCont *L, int P, Generico G){ int i, Generico ele1; if(LSCont_EstaLlena(L)) return FALSE; if(P<=-1) return FALSE; //MOVER TODOS for(i = L->ultimo; i >=P ;i--){ ele1 = ArrayU_ElemC(L->Elementos,i); ArrayU_ElemM(L->Elementos,i+1, ele1); } ArrayU_ElemM(L->Elementos, P, G); L->utlimo ++; return TRUE; }

bool LSCont_InsertarInicio(LSCont *L, Generico G){ int i; Generico ele1, ele2; //No insertar si ya esta llena if(LSCont_EstaLlena(L)) return FALSE; //Mover todo hacia delante for(i = L->ultimo; i >=0 ;i--){ ele1 = ArrayU_ElemC(L->Elementos,i); ArrayU_ElemM(L->Elementos,i+1, ele1); } ArrayU_ElemM(L->Elementos, 0, G); L->ultimo++; return(TRUE); }

9
10 0 9 1 1 1 1 5 2

last last
5 8 3 8 4 5 6 7 8 9

CONTIGUA: SACAR
bool LSCont_EliminarNodo(LSCont *L, int P){ int i; Generico ele1; if(LSCont_EstaVacia(L)) return FALSE; if(P<=-1) return FALSE //RETROCEDER TODOS for(i = P; i < L->ultimo;i++){ ele1 = ArrayU_ElemC(L->Elementos, i+1); ArrayU_ElemM(L->Elementos, i, ele1); } L->last --; return TRUE; } bool LSCont_EliminarxInfo(LSCont *L, Generico G){ int pos; if(LSCont_EstaVacia(L)) return FALSE; pos = LSCont_Localizar(L, G); if(pos >= 0) return(LSCont_EliminaNodo(L, pos);); } 4 5 6 7 8 9

Eliminar por Info, dada una cierta informacin, buscar el elemento que la tenga y eliminarlo

last last
10 0 5 1 1 8 5 2 8 3

LSE: LISTAS SIMPLES ENLAZADAS

Es una implementacin flexible y potente


Los nodos ya no son adyacentes en memoria

Contenido Enlace

Un nodo A logra un enlace con otro B, Almacenando dentro la direccin de memoria de B

NODO B
C

Al insertar o eliminar un nodo ya no hay que mover al resto de elemento, solo enlazarlo con la lista
25

NODO A

25
10 5 8 25 2 2 31 31

TDA LSE_NODO: NIVEL DE IMPLEMENTACION


Contenido: Datos enteros, reales, o incluso, de Estructuras: Estudiante, Auto, etc.... Y adems, el nodo tambin contiene un enlace con su nodo siguiente Este enlace, puede no enlazar el nodo con nadie, el nodo esta solito, no forma parte de ninguna lista O puede apuntar a otro nodo, indicando que ese es su siguiente, formando una Lista

TDA LSE_NODO: OPERACIONES

Crear y Eliminar

LSE_nodo *LSE_Nodo_Crear(Generico G); void LSE_nodo_Eliminar (LSE_nodo *p);

Consultar y Modificar Contenido

Generico LSE_nodo_GetContenido(LSE_nodo *p);


void LSE_nodo_SetContenido(LSE_nodo *p, LSE_nodo *LSE_nodo_Siguiente(LSE_nodo *p); void LSE_nodo_SetSiguiente(LSE_nodo *p, LSE_nodo *Enlace); Generico G);

Consultar y Modificar Enlaces


TDA LSE_NODO: DECLARACION

Un nodo dinmico almacena dentro

Un contenido de cualquier tipo de dato, entero, real, estructuras, etc...... Un enlace, que es la referencia al nodo siguiente, la direccin del nodo siguiente
typedef struct TLSE_Nodo{ Generico G;

struct TLSE_Nodo *sig;


} LSE_Nodo; typedef LSE_Nodo * LSE_NodoPtr;

LSE_NODO: CREAR Y DESTRUIR

Al crear un nodo se le asignara un valor inicial

Al eliminar un nodo se liberara la memoria que este ocupa


void LSE_EliminarNodo(LSE_nodo *p) { if(p) { free(p); p = NULL; } }

LSE_nodo *LSE_CrearNodo(Generico G) { LSE_nodo *p; p = (LSE_nodo *)malloc(sizeof(LSE_nodo)); if(p) { p->G = G; p->sig = NULL; } return p; }

LSE: NIVEL DE IMPLEMENTACION


En una lista hay que llevar control de las posiciones al primer y el ltimo elemento
En la lista, las posiciones son direcciones de memoria: punteros

Header y Last son punteros a Nodo en una lista enlazada

La posicin de un nodo estar dada por un puntero a dicho nodo


Una lista enlazada no tiene datos predefinidos

Los elementos o Nodos van siendo creados y eliminados a medida que se va necesitando

LSE: OPERACIONES

Crear y Eliminar

LSE * LSE_CrearLista(); void LSE_Eliminar(LSE **L); LSE_nodo *LSE_NodoInicio(LSE L); LSE_nodo *LSE_NodoFin(LSE L); bool LSE_EstaVacia(LSE L); bool LSE_InsertarNodoInicio(LSE *L, LSE_nodo *pNodo); bool LSE_InsertarNodoFin(LSE *L, LSE_nodo *pNodo); bool LSE_Insertar(LSE *L, LSE_nodo *p, LSE_nodo *nuevo); LSE_nodo *LSE_SacarNodoInicio(LSE *L); LSE_nodo *LSE_SacarNodoFin(LSE *L); bool LSE_EliminarxPos(LSE *L, LSE_nodo *p);

Consultar Primer y Ultimo


Conocer Estado

Aadir y Remover

Busqueda y Recorrido

LSE_nodo *LSE_BuscarNodo(LSE L, Generico G, Generico_fnComparar f); bool LSE_ExisteNodo(LSE L, LSE_nodo *p); void LSE_Recorrer(LSE L, Generico_fnImprimir f);

LSE: DECLARACIN

Hay varias formas de definir una lista

Solo a travs del primer elemento a la misma


typedef LSE_Nodo * LSE;

O llevando control del primero y el ltimo elemento


typedef struct{ LSE_Nodo *header; LSE_Nodo *last; }LSE;

LSE: CREAR y DESTRUIR

Al crear una lista, esta estar vaca, su primero y ultimo no apuntaran a nadie

Al Eliminar una lista, cada uno de los nodos debe ser liberado
void LSE_Vaciar(LSE *L){ LSE_nodo *p; while(!LSE_EstaVacia(*L)){ p = LSE_SacarNodoFin(L); LSE_Nodo_Eliminar(p);
}

LSE *LSE_CrearLista(){ LSE *lnueva; lnueva = malloc(sizeof(LSE)); lnueva->header = lnueva->last = NULL; return lnueva; }

header last

LSE: BUSQUEDA

Hay que ubicarse en el inicio: header E ir avanzando hasta


Encontrar el nodo con la informacin buscada o Que ya no haya mas nodos Un puntero se ubicara en el header Y luego ir avanzando al siguiente, y al siguiente y al siguiente

LSE_nodo *LSE_BuscarNodo(LSE L, Generico G, Generico_fnComparar f){ LSE_nodo *p; for(p = L.header; p!= NULL; p = LSE_Nodo_Siguiente(p)){ if(f(LSE_Nodo_Contenido(p),G) ==0) return(p); } return(NULL); }

Como no se usan ndices, se usan punteros:


Al encontrar al nodo buscado, no se retorna su posicin como ndice, esta no importa Se retorna la direccin de este nodo(puntero)
header 10 pp 5 p p 8 p p

Recomendacin: Usemos el comportamiento de LSE_Nodo, no el estado

Busco 25 30
last 25 p p 2 p 31 p p

LSE: ANTERIOR

La posicin Dada la direccin de un nodo(pos), esta funcin retorna la direccin del nodopanterior es la Hay que buscar desde el header de un nodo El nodo buscado es aquel cuyo siguiente es igual a pos fuera de Si el elemento buscado es el primero en la lista, no hay anterior la lista
p

LSE_nodo * LSE_Anterior(LSE L, LSE_nodo *p){ LSE_nodo *q; if(LSE_EstaVacia(L)) return NULL; if(L.header == p) return NULL; for(q=L.header; q!=NULL;q=q->sig){ if(q->sig ==p) return(q); } header return(NULL); } 10 qq 5 q q

Ejemplo al usar el estado de LSE_Nodo


8 q q 25 q p

last 2 q 31 q q

LSE: PRIMERO Y ULTIMO


Se pueden obtener siempre y cuando la lista no este vaca Retornaran la informacin del elemento apuntado por header y last respectivamente.

LSE_nodo *LSE_NodoInicio(LSE L){ return (L.header); }

LSE_nodo *LSE_NodoFin(LSE L){ return (L.last); }

LSE: INSERTAR

La operacin de insertar recibir


La NODO en si que se va a insertar Este nodo ya debi haber sido creado antes de insertarlo Insertar al inicio o al final Insertar en medio de la lista

Hay varios tipos de insercin


last->sig = nuevo;

INSERCION AL INICIO/FINAL
Si la lista esta vaca, tanto header como last apuntan al nuevo nodo Si no, si es al inicio el nuevo header, es el nuevo nodo Si no, si es al final, el nuevo last es el nuevo nodo

last = nuevo; last

nuevo last 18

header nuevo

header 10 5 8 25 2

31

9 nuevo->sig = header; header = nuevo; bool LSE_InsertarNodoInicio(LSE *L, LSE_nodo *nuevo){ if (!nuevo) return FALSE; if(LSE_EstaVacia(*L)){ L->header = L->last = nuevo; } else{ LSE_Nodo_ModificarEnlace( nuevo, L->header); L->header = nuevo; } return(TRUE); } bool LSE_InsertarNodoFin(LSE *L, LSE_nodo *nuevo){ if(!nuevo) return FALSE; if(LSE_EstaVacia(*L)){ L->header = L->last = nuevo; } else{ LSE_Nodo_ModificarEnlace(L->last,, nuevo); L->last = nuevo; } return(TRUE); }

INSERTAR EN MEDIO

bool LSE_Insertar(LSE *L, LSE_nodo *p, LSE_nodo *nuevo){ if(L->last==p){//Insertar al final return(LSE_InsertarNodoFin(L, nuevo)); }else{ if(!p || ! LSE_ExisteNodo(*L,p)) return FALSE; Debe recibir la posicin donde se va a if(LSE_EstaVacia(*L)) insertar L->header = L->last = nuevo; Insertemos despus else{ LSE_Nodo_ModificarEnlace( Si Lista Vaca, el nuevo header y last, es nuevo, LSE_Nodo_Siguiente(p)); el nuevo nodo LSE_Nodo_ModificarEnlace(p, nuevo); Si la posicin no existe no efectuar la } insercin } return(TRUE); Si la lista solo tiene un elemento, el nuevo

last es el nuevo nodo

} nuevo p->sig = nuevo; header 10 5 p 8 25 2 18 Nuevo->sig = p->sig; last 31

header = last = nuevo: last


header last

header nuevo

18

LSE: SACAR DE LA LISTA

La lista no debe estar vaca!!, si tiene un solo elemento, dejarla vaca


header 5 8 25 last 2 last tmp = last;

Header = header->sig; header Tmp = header; free(tmp); 10

Last = Anterior(Last); Last->sig = NULL; 31 free(tmp);

tmp

LSE_nodo *LSE_SacarNodoInicio(LSE *L){ LSE_nodo *tmp = L->header; if(LSE_EstaVacia(*L)) return NULL; if(L->header == L->last) LSE_InicializarLista(L); else { L->header = L->header->sig; } return(tmp); }

tmp LSE_nodo *LSE_SacarNodoFin(LSE *L){ LSE_nodo *tmp=L->header; if(LSE_EstaVacia(*L)) return NULL; if(L->header == L->last) LSE_InicializarLista(L); else{ tmp = L->last; L->last = LSE_Anterior(*L, L->last); L->last->sig = NULL; } return(tmp); }

LSE: SACAR JUSTO UN NODO

Lista no debe estar vaca La posicin enviada debe existir en la lista Revisar si se desea eliminar el header o el last
p_ant->sig = p->sig;

header 10 5

p 8 free(p); 25

bool LSE_EliminarxPos(LSE *L, LSE_nodo *p){ LSE_nodo *p_ant; if(LSE_EstaVacia(*L)) return 0; if(!p || !LSE_ExisteNodo(*L, p)) return FALSE; if(p==L->header) LSE_SacarNodoInicio(L); else if(p == L->last) LSE_SacarNodoFin(L); else{ p_ant = LSE_Anterior(*L,p); p_ant->sig = p->sig; p->sig = NULL; } return(TRUE); } last 2 31

p_ant = Anterior(p); pant

VISUALIZAR

Imprimir todos los nodos de la lista


void LSE_Recorrer(LSE L, Generico_fnImprimir fn){ LSE_nodo *p; for( p = L.header; p!=NULL; p = p->sig) fn(p->G); }

S-ar putea să vă placă și