You are on page 1of 35

MATERIA:

Estructura de Datos II
CARRERA:

Ingeniera en Sistemas Computacionales


TEMA DE INVESTIGACIN:

Cola doblemente circular, listas y rboles


ALUMNO:

Francisco Chirino Carbajal


CUATRIMESTRE: CUARTO CATEDRTICO: GRUPO: NICO

Ing. Eloy Herrera Trujillo

19 de Septiembre de 2013.

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

INTRODUCCIN

En este pequeo trabajo de investigacin vamos a hablar sobre las estructuras de datos de Colas doblemente circular, Listas y rboles, las cuales nos sirven para almacenar y recuperar sus elementos atendiendo a un estricto orden.

Colas doblemente circular, listas y rboles.

Pgina 2 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

COLAS DOBLEMENTE CIRCULAR, LISTAS Y RBOLES

COLA CIRCULAR. Una cola circular o anillo es una estructura de datos en la que los elementos estn de forma circular y cada elemento tiene un sucesor y un predecesor. Los elementos pueden consultarse, aadirse y eliminarse nicamente desde la cabeza del anillo que es una posicin distinguida. Existen dos operaciones de rotaciones, una en cada sentido, de manera que la cabeza del anillo pasa a ser el elemento sucesor, o el predecesor, respectivamente, de la cabeza actual. Ejemplo: La cola es una estructura de datos, donde la insercin del tem se hace en un final (fin de la cola) y la recuperacin /borrado de elementos se hace otro al final (el inicio de la cola). Como el primer elemento insertado es el primero en ser recuperado. Las colas se refieren en first in first out.

Colas doblemente circular, listas y rboles.

Pgina 3 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

La cola lineal de la figura anterior almacena cuatro enteros, con el entero 1 en primer lugar. Esa cola est llena y no puede almacenar ms datos adicional es porque rear identifica la parte final de la cola. La razn de la posicin vaca, que identifica front, implica el comportamiento lineal de la cola. Inicialmente, front y rear identifican la posicin ms a la izquierda, lo que indica que la cola est vaca. Para almacenar el entero 1, rear avanza una posicin hacia la derecha y almacena 1 en esa posicin. Para recuperar/borrar el entero 1, front avanza una posicin hacia la derecha. La cola circular de la figura anterior tiene siete datos enteros, con el entero 1 primero. Esta cola est llena y no puede almacenar ms datos hasta que front avance una posicin en sentido horario (para recuperar el entero 1) y rear avance una posicin en la misma direccin (para identificar la posicin que contendr el nuevo entero). Al igual que con la cola lineal, la razn de la posicin vaca, que identifica front, implica el comportamiento circular de la cola. Inicialmente, front y rear identifican la misma posicin, lo que indica una cola vaca. Entonces rear avanza una posicin por cada nueva insercin. De forma similar, front avanza una posicin por cada recuperacin/borrado. Una cola circular o anillo es una estructura de datos en la que los elementos estn de forma circular y cada elemento tiene un sucesor y un predecesor. Los elementos pueden consultarse, aadirse y eliminarse nicamente desde la cabeza del anillo que es una posicin distinguida. Existen dos operaciones de rotaciones, una en cada sentido, de manera que la cabeza del anillo pasa a ser el elemento sucesor, o el predecesor, respectivamente, de la cabeza actual.

Colas doblemente circular, listas y rboles.

Pgina 4 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Bueno este es un ejemplo de una cola circular, pero para demostrar cmo es su funcionamiento es de un tamao predefinido, en este caso es una cola esttica. BICOLA O COLA DOBLE La bicola o doble cola es un tipo de cola especial que permiten la insercin y eliminacin de elementos de ambos extremos de la cola. Puede representarse a partir de un vector y dos ndices, siendo su representacin ms frecuente una lista circular doblemente enlazada. Todas las operaciones de este tipo de datos tienen coste constante. Una cola doble es una estructura de datos en la cual las operaciones de agregar y retirar se practican por ambos lados. Una cola doble es una estructura en la que, por la forma en que se realizan las operaciones, puede comportarse como pila o como cola. Una lista doblemente enlazada es una lista lineal en la que cada nodo tiene dos enlaces, uno al nodo siguiente, y otro al anterior. Las listas doblemente enlazadas no necesitan un nodo especial para acceder aellas, pueden recorrerse en ambos sentidos a partir de cualquier nodo, esto es porque a partir de cualquier nodo, siempre es posible alcanzar cualquier nodo dela lista, hasta que se llega a uno de los extremos. COLAS DOBLES Existe una variable de la cola simple que es la bicola (doble cola). Es una cola bidimensional en la que las inscripciones y eliminaciones se pueden realizar en cualquiera de los dos extremos de la cola. Insercin Eliminacin

Eliminacin Insercin Existen dos variantes de la bicola (cola doble): Cola doble con entrada restringida: Acepta valor, inserciones solo al final de la columna. Cola doble con salida restringida: Acepta eliminaciones solo al inicio de la cola. Indica Memoria Dinmica Crear I I=NULL Crear M M=NULL
Colas doblemente circular, listas y rboles. Pgina 5 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Crear F F=NULL Mientras si (Quiere dar de alta) Si I=Null Entonces Crear Nodo I I sig=NULL M=I F=I Si no Crear nodo F Fsig =M M=F COLA DOBLE CON SALIDA REESTRINGIDA Acepta eliminaciones solo al inicio de la cola. I MF Crear I Crear F Crear M I=NULL, F= NULL , M= NULL Si I=NULL Crear Nodo I Isig1= NULL Isig2 = NULL F=I M=I Si no Crear nodo F Msig1 =F Fsig2=M Fsig1=I M=F Isig2=F Solo se da de baja al inicio de la cola Solo se da de alta al final de la cola.
Colas doblemente circular, listas y rboles. Pgina 6 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

I MF BAJA AL FINAL DE LA COLA M= Fsig2 Msig1=I Isig2 = M F=M BAJA AL PRINCIPIO DE LA COLA M=I I=Msig1 Fsig1=M Msig2=F I=M M=F

Colas doblemente circular, listas y rboles.

Pgina 7 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

LISTAS

Definicin Una lista es una estructura de datos secuencial. Una manera de clasificarlas es por la forma de acceder al siguiente elemento: lista densa: la propia estructura determina cul es el siguiente elemento de la lista. Ejemplo: un array. lista enlazada: la posicin del siguiente elemento de la estructura la determina el elemento actual. Es necesario almacenar al menos la posicin de memoria del primer elemento. Adems es dinmica, es decir, su tamao cambia durante la ejecucin del programa. Una lista enlazada se puede definir recursivamente de la siguiente manera: una lista enlazada es una estructura vaca o un elemento de informacin y un enlace hacia una lista (un nodo). Grficamente se suele representar as:

Como se ha dicho anteriormente, pueden cambiar de tamao, pero su ventaja fundamental es que son flexibles a la hora de reorganizar sus elementos; a cambio se ha de pagar una mayor lentitud a la hora de acceder a cualquier elemento. En la lista de la figura anterior se puede observar que hay dos elementos de informacin, x e y. Supongamos que queremos aadir un nuevo nodo, con la informacin p, al comienzo de la lista. Para hacerlo basta con crear ese nodo, introducir la informacin p, y hacer un enlace hacia el siguiente nodo, que en este caso contiene la informacin x. Qu ocurre si quisiramos hacer lo mismo sobre un array?. En ese caso sera necesario desplazar todos los elementos de informacin "hacia la derecha", para poder introducir el nuevo elemento, una operacin muy engorrosa.

Colas doblemente circular, listas y rboles.

Pgina 8 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Implementacin. Para representar en lenguaje C esta estructura de datos se utilizarn punteros, un tipo de datos que suministra el lenguaje. Se representar una lista vaca con la constante NULL. Se puede definir la lista enlazada de la siguiente manera: struct lista { int clave; struct lista *sig; }; Como se puede observar, en este caso el elemento de informacin es simplemente un nmero entero. Adems se trata de una definicin autorreferencial. Pueden hacerse definiciones ms complejas. Ejemplo: struct cl { char nombre[20]; int edad; }; struct lista { struct cl datos; int clave; struct lista *sig; }; Cuando se crea una lista debe estar vaca. Por tanto para crearla se hace lo siguiente: struct lista *L; L = NULL; Operaciones bsicas sobre listas Insercin al comienzo de una lista: Es necesario utilizar una variable auxiliar, que se utiliza para crear el nuevo nodo mediante la reserva de memoria y asignacin de la clave. Posteriormente es necesario reorganizar los enlaces, es decir, el nuevo nodo debe apuntar al que era el primer elemento de la lista y a su vez debe pasar a ser el primer elemento.

Colas doblemente circular, listas y rboles.

Pgina 9 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

En el siguiente ejemplo se muestra un programa que crea una lista con cuatro nmeros. Notar que al introducir al comienzo de la lista, los elementos quedan ordenados en sentido inverso al de su llegada. Notar tambin que se ha utilizado un puntero auxiliar p para mantener correctamente los enlaces dentro de la lista. #include <stdlib.h> struct lista { int clave; struct lista *sig; }; int main(void) { struct lista *L; struct lista *p; int i; L = NULL; /* Crea una lista vacia */ for (i = 4; i >= 1; i--) { /* Reserva memoria para un nodo */ p = (struct lista *) malloc(sizeof(struct lista)); p->clave = i; /* Introduce la informacion */ p->sig = L; /* reorganiza */ L = p; /* los enlaces */ } return 0; } Recorrido de una lista. La idea es ir avanzando desde el primer elemento hasta encontrar la lista vaca. Antes de acceder a la estructura lista es fundamental saber si esa estructura existe, es decir, que no est vaca. En el caso de estarlo o de no estar inicializada es posible que el programa falle y sea difcil detectar donde, y en algunos casos puede abortarse inmediatamente la ejecucin del programa, lo cual suele ser de gran ayuda para la depuracin.
Colas doblemente circular, listas y rboles. Pgina 10 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Como se ha dicho antes, la lista enlazada es una estructura recursiva, y una posibilidad para su recorrido es hacerlo de forma recursiva. A continuacin se expone el cdigo de un programa que muestra el valor de la clave y almacena la suma de todos los valores en una variable pasada por referencia (un puntero a entero). Por el hecho de ser un proceso recursivo se utiliza un procedimiento para hacer el recorrido. Ntese como antes de hacer una operacin sobre el elemento se comprueba si existe. int main(void) { struct lista *L; struct lista *p; int suma; L = NULL; /* crear la lista */ ... suma = 0; recorrer(L, &suma); return 0; } void recorrer(struct lista *L, int *suma) { if (L != NULL) { printf("%d, ", L->clave); *suma = *suma + L->clave; recorrer(L->sig, suma); } } Sin embargo, a la hora de hacer un programa, es ms eficaz si el recorrido se hace de forma iterativa. En este caso se necesita una variable auxiliar que se desplace sobre la lista para no perder la referencia al primer elemento. Se expone un programa que hace la misma operacin que el anterior, pero sin recursin. int main(void) { struct lista *L;
Colas doblemente circular, listas y rboles. Pgina 11 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

struct lista *p; int suma; L = NULL; /* crear la lista */ ... p = L; suma = 0; while (p != NULL) { printf("%d, ", p->clave); suma = suma + p->clave; p = p->sig; } return 0; } A menudo resulta un poco difcil de entender la instruccin p = p->sig; Simplemente cambia la direccin actual del puntero p por la direccin del siguiente enlace. Tambin es comn encontrar instrucciones del estilo: p = p->sig->sig; Esto puede traducirse en dos instrucciones, de la siguiente manera: p = p->sig; p = p->sig; Obviamente slo debe usarse cuando se sepa que p->sig es una estructura no vaca, puesto que si fuera vaca, al hacer otra vez p = p->sig se producira una referencia a memoria no vlida. Y si queremos insertar en una posicin arbitraria de la lista o queremos borrar un elemento? Como se trata de operaciones algo ms complicadas (tampoco mucho) se expone su desarrollo y sus variantes en los siguientes tipos de listas: las listas ordenadas y las listas reorganizables. Asimismo se estudiarn despus las listas que incorporan cabecera y centinela. Tambin se estudiarn las listas con doble enlace. Todas las implementaciones se harn de forma iterativa, y se deja propuesta por ser ms sencilla su implementacin recursiva, aunque es recomendable utilizar la versin iterativa.

Colas doblemente circular, listas y rboles.

Pgina 12 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Listas ordenadas Las listas ordenadas son aquellas en las que la posicin de cada elemento depende de su contenido. Por ejemplo, podemos tener una lista enlazada que contenga el nombre y apellidos de un alumno y queremos que los elementos -los alumnos- estn en la lista en orden alfabtico. La creacin de una lista ordenada es igual que antes: struct lista *L; L = NULL; Cuando haya que insertar un nuevo elemento en la lista ordenada hay que hacerlo en el lugar que le corresponda, y esto depende del orden y de la clave escogidos. Este proceso se realiza en tres pasos: 1. Localizar el lugar correspondiente al elemento a insertar. Se utilizan dos punteros: anterior y actual, que garanticen la correcta posicin de cada enlace. 2. Reservar memoria para l (puede hacerse como primer paso). Se usa un puntero auxiliar (nuevo) para reservar memoria. 3. Enlazarlo. Esta es la parte ms complicada, porque hay que considerar la diferencia de insertar al principio, no importa si la lista est vaca, o insertar en otra posicin. Se utilizan los tres punteros antes definidos para actualizar los enlaces. A continuacin se expone un programa que realiza la insercin de un elemento en una lista ordenada. Suponemos claves de tipo entero ordenadas ascendentemente. #include <stdio.h> #include <stdlib.h> struct lista { int clave; struct lista *sig; }; /* prototipo */ void insertar(struct lista **L, int elem); int main(void) {
Colas doblemente circular, listas y rboles. Pgina 13 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

struct lista *L; L = NULL; /* Lista vacia */ /* para probar la insercion se han tomado 3 elementos */ insertar(&L, 0); insertar(&L, 1); insertar(&L, -1); return 0; } void insertar(struct lista **L, int elem) { struct lista *actual, *anterior, *nuevo; /* 1.- se busca su posicion */ anterior = actual = *L; while (actual != NULL && actual->clave < elem) { anterior = actual; actual = actual->sig; } /* 2.- se crea el nodo */ nuevo = (struct lista *) malloc(sizeof(struct lista)); nuevo->clave = elem; /* 3.- Se enlaza */ if (anterior == NULL || anterior == actual) { /* inserta al principio */ nuevo->sig = anterior; *L = nuevo; /* importante: al insertar al principio actuliza la cabecera */ } else { /* inserta entre medias o al final */ nuevo->sig = actual; anterior->sig = nuevo; } }

Colas doblemente circular, listas y rboles.

Pgina 14 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Se puede apreciar que se pasa la lista L con el parmetro **L . La razn para hacer esto es que cuando se inserta al comienzo de la lista (porque est vaca o es donde corresponde) se cambia la cabecera. Un ejemplo de prueba: suponer que se tiene esta lista enlazada: 1 -> 3 -> 5 -> NULL Queremos insertar un 4. Al hacer la bsqueda el puntero actual apunta al 5. El puntero anterior apunta al 3. Y nuevo contiene el valor 4. Como no se inserta al principio se hace que el enlace siguiente a nuevo sea actual, es decir, el 5, y el enlace siguiente a anterior ser nuevo, es decir, el 4. La mejor manera de entender el funcionamiento es haciendo una serie de seguimientos a mano o con la ayuda del depurador. A continuacin se explica el borrado de un elemento. El procedimiento consiste en localizarlo y borrarlo si existe. Aqu tambin se distingue el caso de borrar al principio o borrar en cualquier otra posicin. Se puede observar que el algoritmo no tiene ningn problema si el elemento no existe o la lista est vaca. void borrar(struct lista **L, int elem) { struct lista *actual, *anterior; /* 1.- busca su posicion. Es casi igual que en la insercion, ojo al (<) */ anterior = actual = *L; while (actual != NULL && actual->clave < elem) { anterior = actual; actual = actual->sig; } /* 2.- Lo borra si existe */ if (actual != NULL && actual->clave == elem) { if (anterior == actual) /* borrar el primero */ *L = actual->sig; /* o tambien (*L)->sig; */ else /* borrar en otro sitio */ anterior->sig = actual->sig; free(actual); } }
Colas doblemente circular, listas y rboles. Pgina 15 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Ejemplo: para borrar la clave '1' se indica as: borrar(&L, 1); Listas reorganizables Las listas reorganizables son aquellas en las que cada vez que se accede a un elemento ste se coloca al comienzo de la lista. Si el elemento al que se accede no est en la lista entonces se aade al comienzo de la misma. Cuando se trata de borrar un elemento se procede de la misma manera que en la operacin de borrado de la lista ordenada. Notar que el orden en una lista reorganizable depende del acceso a un elemento, y no de los valores de las claves. No se va a desarrollar el procedimiento de insercin / acceso en una lista, se deja como ejercicio. De todas formas es sencillo. Primero se busca ese elemento, si existe se pone al comienzo de la lista, con cuidado de no perder los enlaces entre el elemento anterior y el siguiente. Y si no existe pues se aade al principio y ya est. Por ltimo se actualiza la cabecera. Cabecera ficticia y centinela Como se ha observado anteriormente, a la hora de insertar o actualizar elementos en una lista ordenada o reorganizable es fundamental actualizar el primer elemento de la lista cuando sea necesario. Esto lleva un coste de tiempo, aunque sea pequeo salvo en el caso de numerosas inserciones y borrados. Para subsanar este problema se utiliza la cabecera ficticia. La cabecera ficticia aade un elemento (sin clave, por eso es ficticia) a la estructura delante del primer elemento. Evitar el caso especial de insertar delante del primer elemento. Grficamente se puede ver as:

Se declara una lista vaca con cabecera, reservando memoria para la cabecera, de la siguiente manera: struct lista { int clave; struct lista *sig; } ... struct lista *L;
Colas doblemente circular, listas y rboles. Pgina 16 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

L = (struct lista *) malloc(sizeof(struct lista)); L->sig = NULL; Antes de implementar el proceso de insercin en una lista con cabecera, se explicar el uso del centinela, y se realizarn los procedimientos de insercin y borrado aprovechando ambas ideas. El centinela es un elemento que se aade al final de la estructura, y sirve para acotar los elementos de informacin que forman la lista. Pero tiene otra utilidad: el lector habr observado que a la hora de buscar un elemento de informacin, ya sea en la insercin o en el borrado, es importante no dar un paso en falso, y por eso se comprueba que no se est en una posicin de informacin vaca. Pues bien, el centinela evita ese problema, al tiempo que acelera la bsqueda. A la hora de la bsqueda primero se copia la clave que buscamos en el centinela, y a continuacin se hace una bsqueda por toda la lista hasta encontrar el elemento que se busca. Dicho elemento se encontrar en cualquier posicin de la lista, o bien en el centinela en el caso de que no estuviera en la lista. Como se sabe que el elemento est en algn lugar de la lista (aunque sea en el centinela) no hay necesidad de comprobar si estamos en una posicin vaca. Cuando la lista est vaca la cabecera apunta al centinela. El centinela siempre se apunta a s mismo. Esto se hace as por convenio. Grficamente se puede representar as:

A continuacin se realiza una implementacin de lista enlazada ordenada, que incluye a la vez cabecera y centinela. struct lista { int clave; struct lista *sig;
Colas doblemente circular, listas y rboles. Pgina 17 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

}; /* lista con cabecera y centinela */ struct listacc { struct lista *cabecera, *centinela; }; Procedimiento de inicializacin (ntese el *LCC): void crearLCC(struct listacc *LCC) { LCC->cabecera = (struct lista *) malloc(sizeof(struct lista)); LCC->centinela = (struct lista *) malloc(sizeof(struct lista)); LCC->cabecera->sig = LCC->centinela; LCC->centinela->sig = LCC->centinela; /* opcional, por convenio */ } Procedimiento de insercin: void insertarLCC(struct listacc LCC, int elem) { struct lista *anterior, *actual, *nuevo; /* 1.- busca */ anterior = LCC.cabecera; actual = LCC.cabecera->sig; LCC.centinela->clave = elem; while (actual->clave < elem) { anterior = actual; actual = actual->sig; } /* 2.- crea */ nuevo = (struct lista *) malloc(sizeof(struct lista)); nuevo->clave = elem; /* 3.- enlaza */ nuevo->sig = actual; anterior->sig = nuevo;
Colas doblemente circular, listas y rboles. Pgina 18 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

} Procedimiento de borrado: void borrarLCC(struct listacc LCC, int elem) { struct lista *anterior, *actual; /* 1.- busca */ anterior = LCC.cabecera; actual = LCC.cabecera->sig; LCC.centinela->clave = elem; while (actual->clave < elem) { anterior = actual; actual = actual->sig; } /* 2.- borra si existe */ if (actual != LCC.centinela && actual->clave == elem) { anterior->sig = actual->sig; free(actual); } } Ejemplo de uso: #include <stdio.h> #include <stdlib.h> struct lista { int clave; struct lista *sig; }; struct listacc { struct lista *cabecera, *centinela; }; void crearLCC(struct listacc *LCC); void insertarLCC(struct listacc LCC, int elem); void borrarLCC(struct listacc LCC, int elem);
Colas doblemente circular, listas y rboles. Pgina 19 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

int main(void) { struct listacc LCC; crearLCC(&LCC); insertarLCC(LCC, 3); borrarLCC(LCC, 3); return 0; } La realizacin de la lista reorganizable aprovechando la cabecera y el centinela se deja propuesta como ejercicio. Listas doblemente enlazadas Son listas que tienen un enlace con el elemento siguiente y con el anterior. Una ventaja que tienen es que pueden recorrerse en ambos sentidos, ya sea para efectuar una operacin con cada elemento o para insertar/actualizar y borrar. La otra ventaja es que las bsquedas son algo ms rpidas puesto que no hace falta hacer referencia al elemento anterior. Su inconveniente es que ocupan ms memoria por nodo que una lista simple. Se realizar una implementacin de lista ordenada con doble enlace que aproveche el uso de la cabecera y el centinela. A continuacin se muestra un grfico que muestra una lista doblemente enlazada con cabecera y centinela, para lo que se utiliza un nico nodo que haga las veces de cabecera y centinela.

- Declaracin: struct listaDE { int clave;


Colas doblemente circular, listas y rboles. Pgina 20 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

struct listaDE *ant, *sig; }; - Procedimiento de creacin: void crearDE(struct listaDE **LDE) { *LDE = (struct listaDE *) malloc(sizeof(struct listaDE)); (*LDE)->sig = (*LDE)->ant = *LDE; } - Procedimiento de insercin: void insertarDE(struct listaDE *LDE, int elem) { struct listaDE *actual, *nuevo; /* busca */ actual = LDE->sig; LDE->clave = elem; while (actual->clave < elem) actual = actual->sig; /* crea */ nuevo = (struct listaDE *) malloc(sizeof(struct listaDE)); nuevo->clave = elem; /* enlaza */ actual->ant->sig = nuevo; nuevo->ant = actual->ant; nuevo->sig = actual; actual->ant = nuevo; } - Procedimiento de borrado: void borrarDE(struct listaDE *LDE, int elem) {
Colas doblemente circular, listas y rboles. Pgina 21 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

struct listaDE *actual; /* busca */ actual = LDE->sig; LDE->clave = elem; while (actual->clave < elem) actual = actual->sig; /* borra */ if (actual != LDE && actual->clave == elem) { actual->sig->ant = actual->ant; actual->ant->sig = actual->sig; free(actual); } } Para probarlo se pueden usar las siguientes instrucciones: struct listaDE *LDE; ... crearDE(&LDE); insertarDE(LDE, 1); borrarDE(LDE, 1); Listas circulares Las listas circulares son aquellas en las que el ltimo elemento tiene un enlace con el primero. Su uso suele estar relacionado con las colas, y por tanto su desarrollo se realizar en el tema de colas. Por supuesto, se invita al lector a desarrollarlo por su cuenta. Algoritmos de ordenacin de listas * Un algoritmo muy sencillo: Se dispone de una lista enlazada de cualquier tipo cuyos elementos son todos comparables entre s, es decir, que se puede establecer un orden, como por ejemplo nmeros enteros. Basta con crear una lista de tipo ordenada e ir insertando en ella los elementos que se quieren ordenar al tiempo que se van borrando de la lista original sus elementos. De esta manera se obtiene una lista ordenada con todos los elementos de la lista original. Este
Colas doblemente circular, listas y rboles. Pgina 22 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

algoritmo se llama Insercin Directa; ver Algoritmos de Ordenacin. La complejidad para ordenar una lista de n elementos es: cuadrtica en el peor caso (n * n) -que se da cuando la lista inicial ya est ordenada- y lineal en el mejor (n) -que se da cuando la lista inicial est ordenada de forma inversa. Para hacer algo ms rpido el algoritmo se puede implementar modificando los enlaces entre los elementos de la lista en lugar de aplicar la idea propuesta anteriormente, que requiere crear una nueva lista y borrar la lista no ordenada. El algoritmo anterior es muy rpido y sencillo de implementar, pues ya estn creadas las estructuras de listas ordenadas necesarias para su uso. Eso s, en general es ineficaz y no debe emplearse para ordenar listas grandes. Para ello se emplea la ordenacin por fusin de listas. * Un algoritmo muy eficiente: ordenacin por fusin o intercalacin. Problemas propuestos: - La ordenacin por fusin no recursiva: consiste en desarrollar un algoritmo para fusionar dos listas pero que no sea recursivo. No se trata de desarrollar una implementacin iterativa del programa anterior, sino de realizar una ordenacin por fusin ascendente. Se explica mediante un ejemplo: 3 -> 2 -> 1 -> 6 -> 9 -> 0 -> 7 -> 4 -> 3 -> 8 se fusiona el primer elemento con el segundo, el tercero con el cuarto, etctera: [(3) -> (2)] -> [(1) -> (6)] -> [(9) -> (0)] -> [(7) -> (4)] -> [(3) -> (8)] queda: 2 -> 3 -> 1 -> 6 -> 0 -> 9 -> 4 -> 7 -> 3 -> 8 se fusionan los dos primeros (primera sublista) con los dos siguientes (segunda sublista), la tercera y cuarta sublista, etctera. Observar que la quinta sublista se fusiona con una lista vaca, lo cual no supone ningn inconveniente para el algoritmo de fusin. [(2 -> 3) -> (1 -> 6)] -> [(0 -> 9) -> (4 -> 7)] -> [(3 -> 8)] queda: 1 -> 2 -> 3 -> 6 -> 0 -> 4 -> 7 -> 9 -> 3 -> 8 se fusionan los cuatro primeros con los cuatro siguientes, y aparte quedan los dos ltimos: [(1 -> 2 -> 3 -> 6) -> (0 -> 4 -> 7 -> 9)] -> [(3 -> 8)] queda: 0 -> 1 -> 2 -> 3 -> 4 -> 6 -> 7 -> 9 -> 3 -> 8

Colas doblemente circular, listas y rboles.

Pgina 23 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

se fusionan los ocho primeros con los dos ltimos, y el resultado final es una lista totalmente ordenada: 0 -> 1 -> 2 -> 3 -> 3 -> 4 -> 6 -> 7 -> 8 -> 9 Para una lista de N elementos, ordena en el mejor y en el peor caso en un tiempo proporcional a: NlogN. Observar que para ordenar una lista de 2 elementos requiere un paso de ordenacin, una lista de 4 elementos requiere dos pasos de ordenacin, una lista de 8 elementos requiere tres pasos de ordenacin, una lista de 16 requiere cuatro pasos, etctera. Es decir: log 2 = 1 log 4 = 2 log 8 = 3 log 16 = 4 log 32 = 5 De ah el logaritmo en base 2. N aparece porque en cada paso se requiere recorrer toda la lista, luego el tiempo es proporcional a NlogN. Se pide: codificar el algoritmo de ordenacin por fusin ascendente.

Colas doblemente circular, listas y rboles.

Pgina 24 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

RBOLES

Definicin. Un rbol es una estructura no lineal en la que cada nodo puede apuntar a uno o varios nodos. Tambin se suele dar una definicin recursiva: un rbol es una estructura compuesta por un dato y varios rboles. Esto son definiciones simples. Pero las caractersticas que implican no lo son tanto.

Definiremos varios conceptos. En relacin con otros nodos:


Nodo hijo: cualquiera de los nodos apuntados por uno de los nodos del rbol. En el ejemplo, 'L' y 'M' son hijos de 'G'. Nodo padre: nodo que contiene un puntero al nodo actual. En el ejemplo, el nodo 'A' es padre de 'B', 'C' y 'D'.

Los rboles con los que trabajaremos tienen otra caracterstica importante: cada nodo slo puede ser apuntado por otro nodo, es decir, cada nodo slo tendr un padre. Esto hace que estos rboles estn fuertemente jerarquizados, y es lo que en realidad les da la apariencia de rboles.

Colas doblemente circular, listas y rboles.

Pgina 25 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

En cuanto a la posicin dentro del rbol:


Nodo raz: nodo que no tiene padre. Este es el nodo que usaremos para referirnos al rbol. En el ejemplo, ese nodo es el 'A'. Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L', 'M', 'N' y 'O'. Nodo rama: aunque esta definicin apenas la usaremos, estos son los nodos que no pertenecen a ninguna de las dos categoras anteriores. En el ejemplo: 'B', 'C', 'D', 'E', 'G' y 'J'.

Otra caracterstica que normalmente tendrn nuestros rboles es que todos los nodos contengan el mismo nmero de punteros, es decir, usaremos la misma estructura para todos los nodos del rbol. Esto hace que la estructura sea ms sencilla, y por lo tanto tambin los programas para trabajar con ellos. Tampoco es necesario que todos los nodos hijos de un nodo concreto existan. Es decir, que pueden usarse todos, algunos o ninguno de los punteros de cada nodo. Un rbol en el que en cada nodo o bien todos o ninguno de los hijos existe, se llama rbol completo. En una cosa, los rboles se parecen al resto de las estructuras que hemos visto: dado un nodo cualquiera de la estructura, podemos considerarlo como una estructura independiente. Es decir, un nodo cualquiera puede ser considerado como la raz de un rbol completo. Existen otros conceptos que definen las caractersticas del rbol, en relacin a su tamao:

Orden: es el nmero potencial de hijos que puede tener cada elemento de rbol. De este modo, diremos que un rbol en el que cada nodo puede apuntar a otros dos es de orden dos, si puede apuntar a tres ser de orden tres, etc. Grado: el nmero de hijos que tiene el elemento con ms hijos dentro del rbol. En el rbol del ejemplo, el grado es tres, ya que tanto 'A' como 'D' tienen tres hijos, y no existen elementos con ms de tres hijos. Nivel: se define para cada elemento del rbol como la distancia a la raz, medida en nodos. El nivel de la raz es cero y el de sus hijos uno. As sucesivamente. En el ejemplo, el nodo 'D' tiene nivel 1, el nodo 'G' tiene nivel 2, y el nodo 'N', nivel 3. Altura: la altura de un rbol se define como el nivel del nodo de mayor nivel. Como cada nodo de un rbol puede considerarse a su vez como la raz de un rbol, tambin

Colas doblemente circular, listas y rboles.

Pgina 26 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

podemos hablar de altura de ramas. El rbol del ejemplo tiene altura 3, la rama 'B' tiene altura 2, la rama 'G' tiene altura 1, la 'H' cero, etc. Los rboles de orden dos son bastante especiales, de hecho les dedicaremos varios captulos. Estos rboles se conocen tambin como rboles binarios. Frecuentemente, aunque tampoco es estrictamente necesario, para hacer ms fcil moverse a travs del rbol, aadiremos un puntero a cada nodo que apunte al nodo padre. De este modo podremos avanzar en direccin a la raz, y no slo hacia las hojas. Es importante conservar siempre el nodo raz ya que es el nodo a partir del cual se desarrolla el rbol, si perdemos este nodo, perderemos el acceso a todo el rbol. El nodo tpico de un rbol difiere de los nodos que hemos visto hasta ahora para listas, aunque slo en el nmero de nodos. Veamos un ejemplo de nodo para crear rboles de orden tres: struct nodo { int dato; struct nodo *rama1; struct nodo *rama2; struct nodo *rama3; }; O generalizando ms: #define ORDEN 5 struct nodo { int dato; struct nodo *rama[ORDEN]; }; Declaraciones de tipos para manejar rboles en C Para C, y basndonos en la declaracin de nodo que hemos visto ms arriba, trabajaremos con los siguientes tipos: typedef struct _nodo { int dato;
Colas doblemente circular, listas y rboles. Pgina 27 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

struct _nodo *rama[ORDEN]; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Arbol; Al igual que hicimos con las listas que hemos visto hasta ahora, declaramos un tipo tipoNodo para declarar nodos, y un tipo pNodo para es el tipo para declarar punteros a un nodo. rbol es el tipo para declarar rboles de orden ORDEN.

El movimiento a travs de rboles, salvo que implementemos punteros al nodo padre, ser siempre partiendo del nodo raz hacia un nodo hoja. Cada vez que lleguemos a un nuevo nodo podremos optar por cualquiera de los nodos a los que apunta para avanzar al siguiente nodo. En general, intentaremos que exista algn significado asociado a cada uno de los punteros dentro de cada nodo, los rboles que estamos viendo son abstractos, pero las aplicaciones no tienen por qu serlo. Un ejemplo de estructura en rbol es el sistema de directorios y ficheros de un sistema operativo. Aunque en este caso se trata de rboles con nodos de dos tipos, nodos directorio y nodos fichero, podramos considerar que los nodos hoja son ficheros y los nodos rama son directorios. Otro ejemplo podra ser la tabla de contenido de un libro, por ejemplo de este mismo curso, dividido en captulos, y cada uno de ellos en subcaptulos. Aunque el libro sea algo lineal, como una lista, en el que cada captulo sigue al anterior, tambin es posible acceder a cualquier punto de l a travs de la tabla de contenido. Tambin se suelen organizar en forma de rbol los organigramas de mando en empresas o en el ejrcito, y los rboles genealgicos.
Colas doblemente circular, listas y rboles. Pgina 28 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

Operaciones bsicas con rboles Salvo que trabajemos con rboles especiales, como los que veremos ms adelante, las inserciones sern siempre en punteros de nodos hoja o en punteros libres de nodos rama. Con estas estructuras no es tan fcil generalizar, ya que existen muchas variedades de rboles. De nuevo tenemos casi el mismo repertorio de operaciones de las que disponamos con las listas: Aadir o insertar elementos. Buscar o localizar elementos. Borrar elementos. Moverse a travs del rbol. Recorrer el rbol completo. Los algoritmos de insercin y borrado dependen en gran medida del tipo de rbol que estemos implementando, de modo que por ahora los pasaremos por alto y nos centraremos ms en el modo de recorrer rboles. Recorridos por rboles. El modo evidente de moverse a travs de las ramas de un rbol es siguiendo los punteros, del mismo modo en que nos movamos a travs de las listas. Esos recorridos dependen en gran medida del tipo y propsito del rbol, pero hay ciertos recorridos que usaremos frecuentemente. Se trata de aquellos recorridos que incluyen todo el rbol. Hay tres formas de recorrer un rbol completo, y las tres se suelen implementar mediante recursividad. En los tres casos se sigue siempre a partir de cada nodo todas las ramas una por una. Supongamos que tenemos un rbol de orden tres, y queremos recorrerlo por completo. Partiremos del nodo raz: RecorrerArbol(raiz);

La funcin RecorrerArbol, aplicando recursividad, ser tan sencilla como invocar de nuevo a la funcin RecorrerArbol para cada una de las ramas:

Colas doblemente circular, listas y rboles.

Pgina 29 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

void RecorrerArbol(Arbol a) { if(a == NULL) return; RecorrerArbol(a->rama[0]); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); }

Lo que diferencia los distintos mtodos de recorrer el rbol no es el sistema de hacerlo, sino el momento que elegimos para procesar el valor de cada nodo con relacin a los recorridos de cada una de las ramas.

Los tres tipos son: Pre-orden En este tipo de recorrido, el valor del nodo se procesa antes de recorrer las ramas: void PreOrden(Arbol a) { if(a == NULL) return; Procesar(dato); RecorrerArbol(a->rama[0]); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); } Si seguimos el rbol del ejemplo en pre-orden, y el proceso de los datos es sencillamente mostrarlos por pantalla, obtendremos algo as: ABEKFCGLMDHIJNO

Colas doblemente circular, listas y rboles.

Pgina 30 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

In-orden En este tipo de recorrido, el valor del nodo se procesa despus de recorrer la primera rama y antes de recorrer la ltima. Esto tiene ms sentido en el caso de rboles binarios, y tambin cuando existen ORDEN-1 datos, en cuyo caso procesaremos cada dato entre el recorrido de cada dos ramas (este es el caso de los rboles-b): void InOrden(Arbol a) { if(a == NULL) return; RecorrerArbol(a->rama[0]); Procesar(dato); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); } Si seguimos el rbol del ejemplo en in-orden, y el proceso de los datos es sencillamente mostrarlos por pantalla, obtendremos algo as: KEBFALGMCHDINJO Post-orden En este tipo de recorrido, el valor del nodo se procesa despus de recorrer todas las ramas: void PostOrden(Arbol a) { if(a == NULL) return; RecorrerArbol(a->rama[0]); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); Procesar(dato); } Si seguimos el rbol del ejemplo en post-orden, y el proceso de los datos es sencillamente mostrarlos por pantalla, obtendremos algo as: KEFBLMGCHINOJDA Eliminar nodos en un rbol El proceso general es muy sencillo en este caso, pero con una importante limitacin, slo podemos borrar nodos hoja: El proceso sera el siguiente: 1. Buscar el nodo padre del que queremos eliminar. 2. Buscar el puntero del nodo padre que apunta al nodo que queremos borrar.
Colas doblemente circular, listas y rboles. Pgina 31 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

3. Liberar el nodo. 4. padre->nodo[i] = NULL;. Cuando el nodo a borrar no sea un nodo hoja, diremos que hacemos una "poda", y en ese caso eliminaremos el rbol cuya raz es el nodo a borrar. Se trata de un procedimiento recursivo, aplicamos el recorrido PostOrden, y el proceso ser borrar el nodo. El procedimiento es similar al de borrado de un nodo: 1. Buscar el nodo padre del que queremos eliminar. 2. Buscar el puntero del nodo padre que apunta al nodo que queremos borrar. 3. Podar el rbol cuyo padre es nodo. 4. padre->nodo[i] = NULL;. En el rbol del ejemplo, para podar la rama 'B', recorreremos el subrbol 'B' en postorden, eliminando cada nodo cuando se procese, de este modo no perdemos los punteros a las ramas apuntadas por cada nodo, ya que esas ramas se borrarn antes de eliminar el nodo. De modo que el orden en que se borrarn los nodos ser: KEFyB rboles ordenados A partir del siguiente captulo slo hablaremos de rboles ordenados, ya que son los que tienen ms inters desde el punto de vista de TAD, y los que tienen ms aplicaciones genricas. Un rbol ordenado, en general, es aquel a partir del cual se puede obtener una secuencia ordenada siguiendo uno de los recorridos posibles del rbol: inorden, preorden o postorden. En estos rboles es importante que la secuencia se mantenga ordenada aunque se aadan o se eliminen nodos. Existen varios tipos de rboles ordenados, que veremos a continuacin: rboles binarios de bsqueda (ABB): son rboles de orden 2 que mantienen una secuencia ordenada si se recorren en inorden.

Colas doblemente circular, listas y rboles.

Pgina 32 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

rboles AVL: son rboles binarios de bsqueda equilibrados, es decir, los niveles de cada rama para cualquier nodo no difieren en ms de 1. rboles perfectamente equilibrados: son rboles binarios de bsqueda en los que el nmero de nodos de cada rama para cualquier nodo no difieren en ms de 1. Son por lo tanto rboles AVL tambin. rboles 2-3: son rboles de orden 3, que contienen dos claves en cada nodo y que estn tambin equilibrados. Tambin generan secuencias ordenadas al recorrerlos en inorden. rboles-B: caso general de rboles 2-3, que para un orden M, contienen M-1 claves.

Colas doblemente circular, listas y rboles.

Pgina 33 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

CONCLUSIN

Podemos concluir que los temas de Colas doblemente circular, listas y rboles son otros tipos de estructuras de datos o procedimientos que se siguen en la programacin para indicarle el orden a los programas o sistemas que se deben de seguir dentro de un computador. Entend que las colas circulares trabajan igual que la cola normal, nada ms que ste almacena datos de forma circular y almacena el dato conforme el front va avanzando, ese front avanza mientras vas eliminando datos y vas ms despacio para ir almacenando los datos. Las listas enlazadas son muy verstiles. Adems, pueden definirse estructuras ms complejas a partir de las listas, como por ejemplo arrays de listas, etc. En algunas ocasiones los grafos se definen como listas de adyacencia. Tambin se utilizan para las tablas de hash (dispersin) como arrays de listas. Son eficaces igualmente para disear colas de prioridad, pilas y colas sin prioridad, y en general cualquier estructura cuyo acceso a sus elementos se realice de manera secuencial. Los rboles se parecen al resto de las estructuras que hemos visto: dado un nodo cualquiera de la estructura, podemos considerarlo como una estructura independiente. Es decir, un nodo cualquiera puede ser considerado como la raz de un rbol completo

Colas doblemente circular, listas y rboles.

Pgina 34 de 35

Estructura de Datos II
Ingeniera en Sistemas Computacionales Francisco Chirino Carbajal

BIBLIOGRAFA:

http://es.scribd.com/doc/41088779/Cola-Circular-Cola-Doble http://www.algoritmia.net/articles.php?id=13 http://www.conclase.net/c/edd/?cap=006b#6_6

Colas doblemente circular, listas y rboles.

Pgina 35 de 35

You might also like