Upload
trandat
View
229
Download
0
Embed Size (px)
Citation preview
5: Listas 1
ELO320 Estructuras de Datos y Algoritmos
Listas
Tomás Arredondo Vidal
Este material está basado en:
Robert Sedgewick, "Algorithms in C", (third edition), Addison-Wesley, ISBN 0-201-31663-3. 2001 material del curso ELO320 del Prof. Leopoldo Silva material en el sitio http://es.wikipedia.org
5: Listas 2
5-Listas
5.1 Definiciones y operaciones5.2 Listas simplemente enlazadas5.3 Listas doblemente enlazadas5.4 Listas circulares5.5 Listas auto organizadas y ordenadas
5: Listas 3
Definiciones y operaciones
Cada elemento o nodo se representa por una estructura, cuyos campos pueden ser leídos y escritos a través de un puntero a la estructura.
Suele existir un campo que se denomina clave, que identifica únicamente al nodo. La clave puede ser numérica o alfanumérica.
Operaciones posibles sobre listas incluyen: Recorrer Buscar Seleccionar Insertar Descartar
5: Listas 4
5-Listas
5.1 Definiciones y operaciones5.2 Listas simplemente enlazadas5.3 Listas doblemente enlazadas5.4 Listas circulares5.5 Listas auto organizadas y ordenadas
5: Listas 5
Listas simplemente enlazadas Listas que requieren un solo
enlace (puntero) entre un nodo y su sucesor
Elementos se direccionan en tiempo constante O(1), los elementos tienen un costo de acceso de O(n) en el peor caso
Las operaciones deben considerar que estas listas pueden estar vacías lo cual requiere un tratamiento especial
El uso de un centinela simplifica las operaciones al hacer que todos los nodos sean tratados de forma igual
5: Listas 6
Ejemplo: Lista simplemente enlazadatypedef struct moldenodo
{
int clave;
struct moldenodo *proximo;
} nodo, *pnodo;
pnodo CreaNodo(int dato)
{ pnodo pn=NULL;
if ( (pn= (pnodo) malloc(sizeof(nodo))) ==NULL) exit(1);
else
{ pn->clave=dato;
pn->proximo=NULL;
}
return(pn);
}
pnodo lista=NULL;
pnodo listaC = CreaNodo(0);
5: Listas 7
Ejemplo: Recorrer la lista y contar nodos int LargoLista(pnodo p)
{ int numeroelementos = 0;
while (p != NULL)
{
numeroelementos ++;
p = p ->proximo; //recorre la lista
}
return (numeroelementos);
}
int LargoLista(pnodo p)
{ int numeroelementos = 0;
for ( ; p != NULL; p=p->proximo) numeroelementos ++;
return (numeroelementos);
}
5: Listas 8
Ejemplo: Buscar un nodopnodo Buscar(pnodo p, int valor)
{ while (p != NULL)
{
if (p->clave== valor)
return (p); //lo encontró
else p = p ->proximo; //recorrer: O(n)
}
return (p); //retorna NULL si no lo encontró.
}
Como usar esta función?
pnodo q;
if ( (q= Buscar(lista, 5)) == NULL)
{ /* no encontró nodo con clave = 5*/
}
else
{ /* lo encontró. …..*/
}
if ( (q= Buscar(listaC->proximo, 5)) == NULL)
{ /* no encontró nodo con clave = 5*/
}
else
{ /* lo encontró. …..*/
}
5: Listas 9
Ejemplo: Seleccionar un valor extremo (mínimo)pnodo SeleccionarMinimo(pnodo p)
{ int min; pnodo t;
if (p==NULL) return (NULL);
else
{ min=p->clave; //Inicia min
t=p;
p=p->proximo;
}
while (p != NULL)
{ if (p->clave <min )
{ min=p->clave;
t=p;
}
p = p ->proximo; //recorre la lista. O(n)
}
return (t);
}
5: Listas 10
Ejemplo: Buscar el último nodo
pnodo ApuntarAlFinal(pnodo p) // como programar?
{
pnodo t;
if (p==NULL)
{
return (NULL);
}
else while (p != NULL)
{
t=p;
p = p ->proximo; //recorre la lista. O(n)
}
return (t);
}
5: Listas 11
Listas: inserción Hay dos variables de tipo puntero a
nodo: p apunta a un nodo de una lista y n apunta a un nodo correctamente inicializado (e.g. retorno de CreaNodo).
El nodo apuntado por n puede ser insertado después del nodo apuntado por p usando:
n->proximo = p->proximo; Para completar la lista se usa:
p->proximo = n; Como seria el diagrama final?
5: Listas 12
Ejemplo: insertar después Si el argumento posición toma valor
NULL, se producirá un error, por eso se verifica su existencia,
pnodo InsDespues( pnodo posicion,
pnodo nuevo)
{
if (nuevo == NULL)
return (NULL);
if (posicion != NULL)
{ nuevo->proximo = posicion->proximo;
posicion->proximo=nuevo;
return (posicion);
}
return(nuevo);
}
Ejemplo de uso:pnodo lista=NULL; //inicializar lista
pnodo pos=NULL;
lista=InsDespues(pos, CreaNodo(1));
pos =Buscar(lista, 1);
InsDespues(pos, CreaNodo(2));
pos =Buscar(lista, 2);
InsDespues(pos, CreaNodo(3));
pos =Buscar(lista, 2);
InsDespues(pos, CreaNodo(4));
5: Listas 13
Listas: inserción antes Si se desea insertar antes de la posición p; se
requiere una variable temporal para efectuar el intercambio (i.e. temp) :pnodo p = NULL; //inicializar lista
p = InsDespues(p,CreaNodo(1));
InsDespues(p,CreaNodo(2));
pnodo n = CreaNodo(3);
// Como es el diagrama?
int temp;
n->proximo = p->proximo;
p->proximo = n;
temp=p->clave;
p->clave=n->clave;
n->clave=temp;
// Como es el diagrama final?
p
1 2
3
n
5: Listas 14
Listas: inserción al final Si se desea insertar al final:pnodo InsertaNodoalFinal(pnodo posicion, int dato) { pnodo temp=posicion;
if (temp != NULL) { while (temp->proximo !=NULL)
temp=temp->proximo; //O(n) temp->proximo=CreaNodo(dato); return (temp->proximo); //retorna NULL si no se pudo crear} else return (CreaNodo(dato));
} // Ejemplo uso?
5: Listas 15
Inserción: cabeza y cola Usando variables globales
cabeza y cola:static pnodo cabeza=NULL; static pnodo cola=NULL;
pnodo insertainicio(int clave) { pnodo t=CreaNodo(clave); if(cabeza==NULL) cola=t; t->proximo=cabeza; cabeza=t; //O(1)
return(t); }
Insertafinal( )?
pnodo insertafinal(int clave)
{ pnodo t =CreaNodo(clave); if(cola==NULL) { cola=cabeza=t;}
else {
cola->proximo=t; cola=t;} //O(1)
return(t);
}
5: Listas 16
Inserción con referencias Usando referencias:void ins_nodo_ref(pnodo *p, pnodo t)
{ if (*p==NULL)
*p=t; //inserta en lista vacía.
else {
t->proximo=*p; //lee var. externa.
*p=t; //escribe en var. externa.
}
}
Uso?:
pnodo lista1=NULL;
Insertanodo_ref(&lista1, CreaNodo(4));
Insertanodo_ref(&lista1, CreaNodo(3));
Insertanodo_ref(&lista1, CreaNodo(2));
Insertanodo_ref(&lista1, CreaNodo(1));
5: Listas 17
Listas: descarte La variable p apunta al nodo
anterior al que se desea descartar, t apunta al nodo que se desea
desligar de la lista después de ejecutada la acción:
t=p->proximo; Para mantener la lista ligada:
p->proximo = t->proximo; Después se libera el espacio del
nodo descartado:free(t);
t=NULL;
5: Listas 18
5-Listas
5.1 Definiciones y operaciones5.2 Listas simplemente enlazadas5.3 Listas doblemente enlazadas5.4 Listas circulares5.5 Listas auto organizadas y ordenadas
5: Listas 19
Listas doblemente enlazadas Estas listas requieren dos
enlaces (punteros) entre un nodo, su sucesor y su antecesor:
typedef struct moldecelda
{ int clave;
struct moldecelda *nx; //next struct struct modecelda *pr; // previous
} nodo, *pnodo;
5: Listas 20
Listas doblemente enlazadas: insertar después
Diagramas muestran las variables antes de insertar el nodo apuntado por q a la lista dada por p.
Como seria el código para insertar?q->nx = p->nx; q->pr = p; p->nx = q ; q->nx->pr = q;
Como seria descartar el nodo q? q->pr->nx = q->nx; q->nx->pr = q->pr; free(q);
5: Listas 21
Listas doblemente enlazadas: condiciones
Las operaciones de insertar, buscar y descartar deben considerar las condiciones en los bordes, y que la lista pueda estar vacía.
Una forma usual de tratar simplificadamente las condiciones de borde, es definir un nodo vacío, denominado cabecera o centinela.
5: Listas 22
5-Listas
5.1 Definiciones y operaciones5.2 Listas simplemente enlazadas5.3 Listas doblemente enlazadas5.4 Listas circulares5.5 Listas auto organizadas y ordenadas
5: Listas 23
Listas circulares En listas simplemente enlazadas, sin o con cabecera,
puede escogerse que el último nodo apunte al primero, con esto se logra que el primer nodo pueda ser cualquier nodo de la lista.
La inserción al inicio, en el caso de la figura debe tratarse de manera especial, con costo O(n), para que el último nodo apunte al nuevo primero.
Si la lista es con centinela, y si el último apunta al centinela, no es necesario introducir código adicional.
5: Listas 24
5-Listas
5.1 Definiciones y operaciones5.2 Listas simplemente enlazadas5.3 Listas doblemente enlazadas5.4 Listas circulares5.5 Listas auto organizadas, ordenadas
5: Listas 25
Listas auto organizadas y ordenadas En listas auto organizadas la operación buscar
mueve a la primera posición el elemento encontrado. De esta manera los elementos más buscados van
quedando cerca del inicio. En listas ordenadas se mantienen los nodos
ordenados según el orden de las claves. Se puede tratar las listas en base a arreglos.
Pudiendo ser éstos: arreglos de nodos, en los cuales se emplean punteros; o bien arreglos que contienen la información de vínculos en base a cursores que almacenan índices.