Vous êtes sur la page 1sur 22

Estructuras dinmicas de informacin (pila cola y arboles) Pilas

Es un tipo especial de lista abierta en la que slo se pueden insertar y eliminar nodos en uno de los extremos de la lista. Estas operaciones se conocen como "push" y "pop", respectivamente "empujar" y "tirar". Adems, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el nodo ledo. Estas caractersticas implican un comportamiento de lista LIFO (Last In First Out), el ltimo en entrar es el primero en salir. El smil del que deriva el nombre de la estructura es una pila de platos. Slo es posible aadir platos en la parte superior de la pila, y slo pueden tomarse del mismo extremo.

Uso de una Pila en una aplicacin


Consideremos un procedimiento que lee una cadena e imprime sus caracteres en orden inverso. La cadena de entrada termina con un blanco, el que no debe imprimirse como parte de la cadena inversa: Imp Inversa Repetir Leer carcter Si carcter <> blanco Entonces Meter (Pila, carcter) Hasta carcter = blanco Mientras no PilaVaca(Pila) hacer Comienza Sacar (Pila, carcter) Imprimir carcter termina

Declaraciones de tipos para manejar pilas:


Los tipos que definiremos normalmente para manejar pilas sern casi los mismos que para manejar listas, tan slo cambiaremos algunos nombres: typedef struct _nodo { int dato; struct _nodo *siguiente; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Pila; Tipo Nodo es el tipo para declarar nodos, evidentemente. P Nodo es el tipo para declarar punteros a un nodo. Pila es el tipo para declarar pilas.

Es evidente, a la vista del grfico, que una pila es una lista abierta. As que sigue siendo muy importante que nuestro programa nunca pierda el valor del puntero al primer elemento, igual que pasa con las listas abiertas. Teniendo en cuenta que las inserciones y borrados en una pila se hacen siempre en un extremo, lo que consideramos como el primer elemento de la lista es en realidad el ltimo elemento de la pila.

Operaciones bsicas con pilas:


Las pilas tienen un conjunto de operaciones muy limitado, slo permiten las operaciones de "push" y "pop":

Push: Aadir un elemento al final de la pila. Pop: Leer y eliminar un elemento del final de la pila.

Ejemplo de pila:
Supongamos que queremos construir una pila para almacenar nmeros enteros. Haremos pruebas intercalando varios "push" y "pop", y comprobando el resultado.

Algoritmo de la funcin "push":


1. Creamos un nodo para el valor que colocaremos en la pila. 2. Hacemos que nodo->siguiente apunte a Pila. 3. Hacemos que Pila apunte a nodo. void Push(Pila *pila, int v) { pNodo nuevo; /* Crear un nodo nuevo */ nuevo = (pNodo)malloc(sizeof(tipoNodo)); nuevo->valor = v; /* Aadimos la pila a continuacin del nuevo nodo */ nuevo->siguiente = *pila; /* Ahora, el comienzo de nuestra pila es en nuevo nodo */ *pila = nuevo; }

Algoritmo de la funcin "pop":


1. Hacemos que nodo apunte al primer elemento de la pila, es decir a Pila. 2. Asignamos a Pila la direccin del segundo nodo de la pila: Pila->siguiente. 3. Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la operacin pop equivale a leer y borrar. 4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar. int Pop(Pila *pila) { pNodo nodo; /* variable auxiliar para manipular nodo */ int v; /* variable auxiliar para retorno */ /* Nodo apunta al primer elemento de la pila */ nodo = *pila; if(!nodo) return 0; /* Si no hay nodos en pila retornamos 0 */ /* Asignamos a pila toda la pila menos el primer elemento */ *pila = nodo->siguiente; /* Guardamos el valor de retorno */ v = nodo->valor; /* Borrar el nodo */ free(nodo); return v; }

Cdigo del ejemplo completo:


#include <stdlib.h> #include <stdio.h>

typedef struct _nodo { int valor; struct _nodo *siguiente; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Pila; /* Funciones con pilas: */ void Push(Pila *l, int v); int Pop(Pila *l); int main() { Pila pila = NULL; Push(&pila, 20); Push(&pila, 10); printf("%d, ", Pop(&pila)); Push(&pila, 40); Push(&pila, 30); printf("%d, ", Pop(&pila)); printf("%d, ", Pop(&pila)); Push(&pila, 90); printf("%d, ", Pop(&pila)); printf("%d\n", Pop(&pila)); system("PAUSE"); return 0; }

void Push(Pila *pila, int v) { pNodo nuevo; /* Crear un nodo nuevo */ nuevo = (pNodo)malloc(sizeof(tipoNodo)); nuevo->valor = v; /* Aadimos la pila a continuacin del nuevo nodo */ nuevo->siguiente = *pila; /* Ahora, el comienzo de nuestra pila es en nuevo nodo */ *pila = nuevo; } int Pop(Pila *pila) { pNodo nodo; /* variable auxiliar para manipular nodo */ int v; /* variable auxiliar para retorno */ /* Nodo apunta al primer elemento de la pila */ nodo = *pila; if(!nodo) return 0; /* Si no hay nodos en la pila retornamos 0 */ /* Asignamos a pila toda la pila menos el primer elemento */ *pila = nodo->siguiente; /* Guardamos el valor de retorno */ v = nodo->valor; /* Borrar el nodo */ free(nodo); return v; }

Colas
Es un tipo especial de lista abierta en la que slo se pueden insertar nodos en uno de los extremos de la lista y slo se pueden eliminar nodos en el otro. Adems, como sucede con las pilas, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el nodo ledo. Este tipo de lista es conocido como lista FIFO (First In First Out), el primero en entrar es el primero en salir. El smil cotidiano es una cola para comprar, por ejemplo, las entradas del cine. Los nuevos compradores slo pueden colocarse al final de la cola, y slo el primero de la cola puede comprar la entrada.

Uso de una cola en una aplicacin


Consideremos un procedimiento que lee dos sub-cadenas de caracteres, separadas por un punto. Y determina si ambas sub-cadenas son iguales o no. Igualesverdadero Repetir Leer carcter Si carcter <> punto entonces Ins_Cola (frase, carcter) Hasta carcter =punto Mientras iguales ^ no ColaVaca(frase) hacer comienza Leer carcter Sup_Cola (frase, letra) si carcter/=letra entonces iguales falso

fin si termina mientras Si iguales entonces escribir ambas subcadenas son iguales fin si

Declaraciones de tipos para manejar colas:


Los tipos que definiremos normalmente para manejar colas sern casi los mismos que para manejar listas y pilas, tan slo cambiaremos algunos nombres: typedef struct _nodo { int dato; struct _nodo *siguiente; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Cola; tipoNodo es el tipo para declarar nodos, evidentemente. pNodo es el tipo para declarar punteros a un nodo. Cola es el tipo para declarar colas.

Es evidente, a la vista del grfico, que una cola es una lista abierta. As que sigue siendo muy importante que nuestro programa nunca pierda el valor del puntero al primer elemento, igual que pasa con las listas abiertas. Adems, debido al funcionamiento de las colas,

tambin deberemos mantener un puntero para el ltimo elemento de la cola, que ser el punto donde insertemos nuevos nodos. Teniendo en cuenta que las lecturas y escrituras en una cola se hacen siempre en extremos distintos, lo ms fcil ser insertar nodos por el final, a continuacin del nodo que no tiene nodo siguiente, y leerlos desde el principio, hay que recordar que leer un nodo implica eliminarlo de la cola.

Operaciones bsicas con colas:


De nuevo nos encontramos ante una estructura con muy pocas operaciones disponibles. Las colas slo permiten aadir y leer elementos: Aadir: Inserta un elemento al final de la cola. Leer: Lee y elimina un elemento del principio de la cola.

Ejemplo de colas:
Construiremos una cola para almacenar nmeros enteros. Haremos pruebas insertando varios valores y leyndolos alternativamente para comprobar el resultado.

Algoritmo de la funcin "Anadir":


1. Creamos un nodo para el valor que colocaremos en la cola. 2. Hacemos que nodo->siguiente apunte a NULL. 3. Si "ultimo" no es NULL, hacemos que ltimo->>siguiente apunte a nodo. 4. Actualizamos "ultimo" haciendo que apunte a nodo. 5. Si "primero" es NULL, hacemos que apunte a nodo. void Anadir(pNodo *primero, pNodo *ultimo, int v) { pNodo nuevo;

/* Crear un nodo nuevo */ nuevo = (pNodo)malloc(sizeof(tipoNodo)); nuevo->valor = v; /* Este ser el ltimo nodo, no debe tener siguiente */ nuevo->siguiente = NULL; /* Si la cola no estaba vaca, aadimos el nuevo a continuacin de ultimo */ if(*ultimo) (*ultimo)->siguiente = nuevo; /* Ahora, el ltimo elemento de la cola es el nuevo nodo */ *ultimo = nuevo; /* Si primero es NULL, la cola estaba vaca, ahora primero apuntar tambin al nuevo nodo */ if(!*primero) *primero = nuevo; }

Algoritmo de la funcin "leer":


1. Hacemos que nodo apunte al primer elemento de la cola, es decir a primero. 2. Asignamos a primero la direccin del segundo nodo de la cola: primero->siguiente. 3. Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la operacin de lectura equivale a leer y borrar. 4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar. 5. Si primero es NULL, haremos que ltimo tambin apunte a NULL, ya que la cola habr quedado vaca. int Leer(pNodo *primero, pNodo *ultimo)

{ pNodo nodo; /* variable auxiliar para manipular nodo */ int v; /* variable auxiliar para retorno */ /* Nodo apunta al primer elemento de la pila */ nodo = *primero; if(!nodo) return 0; /* Si no hay nodos en la pila retornamos 0 */ /* Asignamos a primero la direccin del segundo nodo */ *primero = nodo->siguiente; /* Guardamos el valor de retorno */ v = nodo->valor; /* Borrar el nodo */ free(nodo); /* Si la cola qued vaca, ultimo debe ser NULL tambin*/ if(!*primero) *ultimo = NULL; return v; }

Cdigo del ejemplo completo:


Tan slo nos queda escribir una pequea prueba para verificar el funcionamiento de las colas: #include <stdlib.h> #include <stdio.h> typedef struct _nodo {

int valor; struct _nodo *siguiente; } tipoNodo; typedef tipoNodo *pNodo; /* Funciones con colas: */ void Anadir(pNodo *primero, pNodo *ultimo, int v); int Leer(pNodo *primero, pNodo *ultimo); int main() { pNodo primero = NULL, ultimo = NULL; Anadir(&primero, &ultimo, 20); printf("Aadir(20)\n"); Anadir(&primero, &ultimo, 10); printf("Aadir(10)\n"); printf("Leer: %d\n", Leer(&primero, &ultimo)); Anadir(&primero, &ultimo, 40); printf("Aadir(40)\n"); Anadir(&primero, &ultimo, 30); printf("Aadir(30)\n"); printf("Leer: %d\n", Leer(&primero, &ultimo)); printf("Leer: %d\n", Leer(&primero, &ultimo)); Anadir(&primero, &ultimo, 90); printf("Aadir(90)\n"); printf("Leer: %d\n", Leer(&primero, &ultimo)); printf("Leer: %d\n", Leer(&primero, &ultimo));

system("PAUSE"); return 0; } void Anadir(pNodo *primero, pNodo *ultimo, int v) { pNodo nuevo; /* Crear un nodo nuevo */ nuevo = (pNodo)malloc(sizeof(tipoNodo)); nuevo->valor = v; /* Este ser el ltimo nodo, no debe tener siguiente */ nuevo->siguiente = NULL; /* Si la cola no estaba vaca, aadimos el nuevo a continuacin de ultimo */ if(*ultimo) (*ultimo)->siguiente = nuevo; /* Ahora, el ltimo elemento de la cola es el nuevo nodo */ *ultimo = nuevo; /* Si primero es NULL, la cola estaba vaca, ahora primero apuntar tambin al nuevo nodo */ if(!*primero) *primero = nuevo; } int Leer(pNodo *primero, pNodo *ultimo) { pNodo nodo; /* variable auxiliar para manipular nodo */ int v; /* variable auxiliar para retorno */ /* Nodo apunta al primer elemento de la pila */ nodo = *primero;

if(!nodo) return 0; /* Si no hay nodos en la pila retornamos 0 */ /* Asignamos a primero la direccin del segundo nodo */ *primero = nodo->siguiente; /* Guardamos el valor de retorno */ v = nodo->valor; /* Borrar el nodo */ free(nodo); /* Si la cola qued vaca, ultimo debe ser NULL tambin*/ if(!*primero) *ultimo = NULL; return v; }

Arboles
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 en 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. 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. Existen otros conceptos que definen las caractersticas del rbol, con 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 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, entre otros.

Declaraciones de tipos para manejar Arboles:


Para C, y basndonos en la declaracin de nodo que hemos visto ms arriba, trabajaremos con los siguientes tipos:

typedef struct _nodo {

int dato; 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 tipo Nodo 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.

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.

Operaciones bsicas con arboles:


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.

rbol Binario de Bsqueda


Un rbol binario de bsqueda es una estructura de datos que guarda informacin no repetida, en el que cada nodo apunta como mximo a otros dos nodos, y adems cumplen con un ordenamiento de tal forma que para cada elemento del ABB, los elementos menores estn a su izquierda (subrbol izquierdo), y los mayores a su derecha (subrbol derecho).

16

12

31

43

25

38

20

26

Recorridos de un rbol binario


Hay tres formas de recorrer un rbol binario: Inorden, Preorden y Posorden. Cada una de stas tiene su particularidad, y por lo tanto, su aplicacin especfica. Veamos primero cada forma y en las siguientes diapositivas las ilustraremos. Hay tres formas de recorrer un rbol binario: Inorden, Preorden y Posorden. Cada una de stas tiene su particularidad, y por lo tanto, su aplicacin especfica. Veamos primero cada forma y en las siguientes diapositivas las ilustraremos. En el recorrido Inorden, cada nodo se recorre entre su subrbol izquierdo y su subrbol derecho. En el recorrido Preorden, cada nodo se recorre antes de su subrbol izquierdo y su subrbol derecho. En el recorrido Posorden, cada nodo se recorre despus de su subrbol izquierdo y su subrbol derecho.

Recorrido In-orden

InOrden:

BDEHKMNQRSTVWZ

Recorrido Pre-orden

Pre-Orden: N E D B K H M S R Q W V T Z

Recorrido Pos-orden

Pos-Orden: B D H M K E Q R T V Z W S N.

Repblica Bolivariana de Venezuela Ministerio del Poder Popular Para la Educacin Universidad Nacional Experimental Politcnica de las Fuerzas Armadas (UNEFA). San Tom Anzotegui.

Profesor:

Bachilleres: Francis Silvera C.I.: 20.738670

San Tom, julio 2013