You are on page 1of 73

CESVER Material Bibliogrfico de Apoyo Didctico

ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

MATERIAL BIBLIOGRFICO
DE APOYO DIDCTICO

Licenciatura:
INGENIERIA EN SISTEMAS
COMPUTACIONALES

Asignatura:
ALGORITMOS Y ESTRUCTURA
DE DATOS II

Cuatrimestre:
SEXTO

Nombre del compilador:


ING. JUAN ALBERTO VAZQUEZ
GONZALEZ

ING JUAN ALBERTO VAZQUEZ G.


Pgina 1 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

INDICE
PRESENTACION
INTRODUCCION
MANEJO DE LA ANTOLOGIA

1. INTRODUCCIN A LAS ESTRUCTURAS DINAMICAS


1.1. Definicin.
1.1.1.Nodo.
1.1.2.Apuntador.
1.1.3.Simbologa.
1.2. Operaciones Bsicas.
1.2.1.Declaracin.
1.2.2.Inicializacin de apuntador.
1.2.3.Solicitud de memoria para un nodo.
1.2.4.Liberacin del espacio utilizado por un nodo.
1.3. Comparacin entre las estructuras estticas y dinmicas.

2. LISTAS, PILAS Y COLAS


2.1. Listas.
2.1.1.Creacin.
2.1.2.Insercin de un nodo.
2.1.3.Borrado de un nodo.
2.1.4.Recorrido.
2.1.5.Aplicaciones.
2.2. Pilas.
2.2.1.Creacin.
2.2.2.Operacin push.
2.2.3.Operacin pop.
2.2.4.Aplicacin.
2.3. Colas.
2.3.1.Creacin.
2.3.2.Insercin de un nodo.
2.3.3.Borrado de un nodo.
2.3.4.Aplicacin.
2.4. Otras listas.
2.4.1.Listas circulares.
2.4.2.Listas doblemente encadenadas.
2.4.3.Listas circulares doblemente encadenadas.
2.5. Matrices de apuntadores.
2.6. Implementacin de matrices utilizando listas y colas.

3. RECURSION
3.1. Definicin.
3.2. Ejemplos y aplicaciones.
3.3. Diseo de algoritmos recursivos.
3.4. Implementacin de la recursin utilizando pilas.

4. ARBOLES
4.1. Definicin.
4.2. Definicin de rbol binario.
4.3. Definicin de rbol binario de bsqueda.
4.4. Operaciones sobre rboles binarios de bsqueda.
4.4.1.Creacin.
4.4.2.Adicin de un nodo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 2 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

4.4.3.Bsqueda de un nodo.
4.4.4.Recorrido del rbol.
4.4.4.1. Preorden.
4.4.4.2. Inorden.
4.4.4.3. Postorden.
4.4.5.Implementacin.
4.5. Otros tipos de rbol.

GLOSARIO
BIBLIOGRAFIA
REFERENCIAS

ING JUAN ALBERTO VAZQUEZ G.


Pgina 3 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

INTRODUCCION:

En las sesiones anteriores se ha hecho una introduccin a las estructuras de datos,


definiendo tipos y estructuras de datos primitivos tales como enteros, real, carcter,
utilizados para conseguir tipos de datos ms complicados como arreglos, denominados
estructuras de datos compuestos. Tienen una estructura porque sus datos estn
relacionados entre s. Los arreglos estn soportados en la mayora de los lenguajes de
programacin debido a que son necesarios en casi todas las aplicaciones.
La potencia y flexibilidad de un lenguaje estn directamente relacionadas con las
estructuras de datos que posee. La programacin de algoritmos complicados puede
resultar muy difcil en un lenguaje con estructuras de datos limitadas.
Cuando una aplicacin particular requiere una estructura de datos no soportada por
el lenguaje, se hace necesaria una labor de programacin para representarla. Se dice
que necesitamos implementar la estructura de datos.
Una estructura de datos se dice que es esttica cuando el tamao ocupado en
memoria es fijo, es decir siempre ocupa la misma cantidad de espacio de memoria. En el
caso de los vectores, se debe anticipar (declarar o dimensionar) la longitud de esa lista
cuando se escribe un programa es imposible ampliar el espacio de memoria disponible
Los arrays unidimensionales son estructuras estticas lineales ordenadas
secuencialmente. Las estructuras se convierten en dinmicas cuando los elementos
pueden ser insertados o suprimidos directamente sin necesidad de algoritmos complejos.
Se distinguen las estructuras dinmicas de las estticas por los modos en que se
realizan las inserciones y borrado de elementos.
Estas estructuras dinmicas forman parte de lo que se conoce como datos abstractos
y es necesario que usted como Licenciado en Sistemas Computacionales las conozca ya
que son aplicables a un sinnmero de aplicaciones.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 4 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

MANEJO DE LA ANTOLOGA

Esta, como muchas otras antologas que he realizado han sido cubiertas
perfectamente en el saln de clases garantizando con este material el
aprendizaje y una posterior evaluacin prospera.
La antologa comprende 4 unidades correspondientes a la materia de
Algoritmo y Estructura de datos I que imparte el Centro de Estudios Superiores de
Veracruz (CESVER), incluye adems despus de cada unidad una evaluacin y
una serie de actividades a realizar.
Al final de esta Antologa localizara un glosario de trminos que corresponde
a las palabras marcadas (subrayadas, con cursiva y encerradas en color gris).
Posterior al glosario una serie de libros recomendados para profundizar en los
temas vistos hasta aqu y una serie de referencias de Internet que ampliaran
evidentemente el conocimiento.
La mejor forma de tratar esta antologa y pretendiendo evitar que se quede
con lagunas en su conocimiento es llevar una doble revisin de los temas que
aqu se tratan, amplindolos con un buen libre de C++ (le aconsejo C++ en 21
das) y mucha disposicin para adquirir el conocimientos.
Es importante mencionar que el ultimo capitulo en su mayora fue diseado
por alumnos del 5 semestre de Ingeniera en Sistemas computacionales, me
gusto y veo bueno ponerlo.
Desendole lo mejor dejo este material que me costo mucho realizar en sus
manos
Comencemos...

ING JUAN ALBERTO VAZQUEZ G.


Pgina 5 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

OBJETIVO(S) GENERAL(ES) DE LA ASIGNATURA

Al finalizar el curso, el alumno:

 Disear algoritmos utilizando estructuras de datos estticas y


programacin modular, implementndolos mediante lenguajes
declarativos.

CRITERIOS Y PROCEDIMIENTOS DE EVALUACIN Y ACREDITACIN

EVALUACIN SOBRE EXPERIENCIAS DE 20%


APRENDIZAJE
EXAMEN PARCIAL 30%
EXAMEN FINAL 50%

ING JUAN ALBERTO VAZQUEZ G.


Pgina 6 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Unidad
INTRODUCCIN A LAS
ESTRUCTURAS DINAMICAS 1
1.1. Definicin.
1.1.1. Nodo.
1.1.2. Apuntador.
1.1.3. Simbologa.
1.2. Operaciones Bsicas.
1.2.1. Declaracin.
1.2.2. Inicializacin de apuntador.
1.2.3. Solicitud de memoria para un nodo.
1.2.4. Liberacin del espacio utilizado por un nodo.
1.3. Comparacin entre las estructuras estticas y dinmicas.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 7 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

INTRODUCCION:

Al finalizar este capitulo podremos construir agrupaciones dinmicas incluyendo un


puntero como campo de un registro, de manera que a travs de este puntero podamos
acceder a otros elementos de la agrupacin. A estos registros, que contienen un puntero
se les suele llamar NODOS, y son la base de las agrupaciones dinmicas, ya que gracias
a estos punteros podemos enlazar todos los elementos de informacin que queramos
(limitados tan solo por la capacidad fsica de la memoria del ordenador) y adems gracias
a la instruccin malloc podemos reservar memoria para nuevos elementos a medida que
nos vaya haciendo falta.
Estos sern los temas que estaremos tocando a lo largo de este capitulo para poder
avanzar adecuadamente le sugerir utilizar el compilador de C++.

OBJETIVO:
Conoceremos el concepto de apuntador y lo utilizaremos en la creacin de nodos.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 8 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

INTRODUCCIN A LAS ESTRUCTURAS


DINAMICAS

1.1. Definicin.

Una de las aplicaciones ms interesantes y potentes de la memoria dinmica y los


punteros son las estructuras dinmicas de datos. Las estructuras bsicas disponibles en
C y C++ tienen una importante limitacin: no pueden cambiar de tamao durante la
ejecucin. Los arreglos estn compuestos por un determinado nmero de elementos,
nmero que se decide en la fase de diseo, antes de que el programa ejecutable sea
creado.
En muchas ocasiones se necesitan estructuras que puedan cambiar de tamao
durante la ejecucin del programa. Por supuesto, podemos hacer 'arrays' dinmicos, pero
una vez creados su tamao ser fijo y para hacer que crezcan o disminuyan de tamao,
deberemos reconstruirlas desde el principio.
Las estructuras dinmicas nos permiten crear estructuras de datos que se adapten a
las necesidades reales a las que suelen enfrentarse nuestros programas. Pero no slo
eso, como veremos, tambin nos permitir crear estructuras de datos muy flexibles, ya
sea en cuanto al orden, la estructura interna o las relaciones entre los elementos que las
componen.
Las estructuras de datos estn compuestas de otras pequeas estructuras a las que
llamaremos nodos o elementos, que agrupan los datos con los que trabajar nuestro
programa y adems uno o ms punteros autorreferenciales
autorreferenciales, es decir, punteros a objetos
del mismo tipo nodo.
Las estructuras dinmicas son una implementacin de TDAs o TADs (Tipos
Abstractos de Datos). En estos tipos el inters se centra ms en la estructura de los datos
que en el tipo concreto de informacin que almacenan.
Dependiendo del nmero de punteros (en ocasiones llamados tambin apuntadores)
y de las relaciones entre nodos, podemos distinguir varios tipos de estructuras dinmicas.
Enumeraremos ahora slo de los tipos bsicos:
 Listas abiertas: cada elemento slo dispone de un puntero, que apuntar al
siguiente elemento de la lista o valdr NULL
NULL si es el ltimo elemento.
 Pilas: son un tipo especial de lista, conocidas como listas LIFO (Last In, First
Out: el ltimo en entrar es el primero en salir). Los elementos se "amontonan"
o apilan, de modo que slo el elemento que est encima de la pila puede ser
ledo, y slo pueden aadirse elementos encima de la pila.
 Colas: otro tipo de listas, conocidas como listas FIFO (First In, First Out: El
primero en entrar es el primero en salir). Los elementos se almacenan en fila,
pero slo pueden aadirse por un extremo y leerse por el otro.
 Listas circulares: o listas cerradas, son parecidas a las listas abiertas, pero el
ltimo elemento apunta al primero. De hecho, en las listas circulares no puede
hablarse de "primero" ni de "ltimo". Cualquier nodo puede ser el nodo de
entrada y salida.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 9 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

 Listas doblemente enlazadas: cada elemento dispone de dos punteros, uno a


punta al siguiente elemento y el otro al elemento anterior. Al contrario que las
listas abiertas anteriores, estas listas pueden recorrerse en los dos sentidos.
 Arboles: cada elemento dispone de dos o ms punteros, pero las referencias
nunca son a elementos anteriores, de modo que la estructura se ramifica y
crece igual que un rbol.
 Arboles binarios: son rboles donde cada nodo slo puede apuntar a dos
nodos.
 Arboles binarios de bsqueda (ABB): son rboles binarios ordenados. Desde
cada nodo todos los nodos de una rama sern mayores, segn la norma que
se haya seguido para ordenar el rbol, y los de la otra rama sern menores.
 Arboles AVL: son ta tambin
mbin rboles de bsqueda, pero su estructura est ms
optimizada para reducir los tiempos de bsqueda.
 Arboles B: son estructuras ms complejas, aunque tambin se trata de rboles
de bsqueda, estn mucho ms optimizados que los anteriores.
 Tablas HASH: son estructuras auxiliares para ordenar listas.
 Grafos: es el siguiente nivel de complejidad, podemos considerar estas
estructuras como rboles no jerarquizados.
 Diccionarios.

1.1.1. Nodo.
En estructuras de datos dinmicas un nodo es un registro que contiene un dato de
inters y al menos un puntero para referenciar (apuntar) a otro nodo. Si la estructura tiene
slo un puntero, la nica estructura que se puede construir con el es una lista, si el nodo
tiene ms de un puntero ya se pueden construir estructuras ms complejas como rboles
o grafos.
Entonces en un nodo podemos tener como mnimo dos campos de donde uno de
ellos es un puntero, es decir contiene informacin que permite localizar el siguiente nodo
de la estructura.
La construccin de un nodo quedara d del siguiente modo:
struct nodo {
int dato;
struct nodo *otronodo;
};
El campo "otronodo" puede apuntar a un objeto del tipo nodo. De este modo, cada
nodo puede usarse como un ladrillo para construir listas de datos, y cada uno mantendr
ciertas relaciones con otros nodos.
Para acceder a un nodo de la estructura slo necesitaremos un puntero (tambin
llamado apuntador) a un nodo.

1.1.2. Apuntador.
Una de las cosas ms difciles que encuentran los principiantes en C es entender el
concepto de apuntadores.
Un apuntador es una variable cuyo contenido es una direccin en memoria.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 10 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

La memoria de una computadora se puede ver como una sucesin de bytes. Por
ejemplo, a una computadora de 256MB de memoria RAM le caben 256 x 1024 x 1024 =
268,435,456 bytes (aunque algunas compaas en realidad manejan 256x1000x1024). Si
los enumerramos, el primer byte sera el cero y el ltimo el 268,435,455. Esta
numeracin es lo que se llama direccin de memoria (equivalente en algunos sistemas a
un long int) cualquiera que fuera el tamao de la memoria de nuestra computadora.
Un apuntador es til para poder referirnos a una posicin de memoria reservada por
nuestro programa para alguna variable, ya sea solo para ver su contenido o para
cambiarlo. Cuando nosotros declaramos una variable tipo int, char, float, apuntadores,
etc., estamos reservando memoria para dicha variable. Esta se llama memoria esttica
en el sentido de que existir y estar reservada a todo lo largo del bloque en que fu
declarada. As un int reserva 2 bytes, un char reserva un byte y un float y un apuntador
reservan 4 bytes (en mquinas tipo PC). En estos bytes se escribe el valor de la variable
(al que tambin llamar su contenido). As:
int j=23;
Float x=3.14;
char c='e';
En memoria se veran como:

En realidad lo que se almacena son las representaciones binarias de estos valores.


Las direcciones de memoria se acostumbran escribir en base 16.
Declaremos ahora unos cuantos apuntadores:
int *aj;
float *ax=&x;
char *ac;
aj=&j;
ac=&c;
Aqu los apuntadores se llaman aj, ax y ac. A aj se le asigna la direccin de j (se
escribe &j), a ax la direccin de x y a ac la direccin de c. Note que &j tiene que ser un
apuntador a entero, puesto que se asigna a aj. Si las variables se almacenaran en las
posiciones indicadas en la figura anterior, con la declaracin de las nuevas variables el
dibujo quedara como el siguiente:

Es decir, en aj se guarda la direccin del primer byte de j (en este caso un 0x108) y
similarmente para ax y ac. Esto es lo que sucede si quisiramos ver como funcionan por
dentro los apuntadores. Como se ve en el cdigo no es necesario saber estos valores
que estn en base 16, ya que simplemente basta escribir aj=&j para tener el valor de la
direccin, lo podemos leer como que aj apunta a j, ax apunta a x y ac apunta a c. Esto lo
denotaremos con el siguiente diagrama:
ING JUAN ALBERTO VAZQUEZ G.
Pgina 11 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Con esto podemos ver o modificar el contenido de j, x y c va sus apuntadores. Para


esto utilizamos la sintaxis del asterisco: *aj es otro nombre para j, *ax es otro nombre
para x y *ac es otro nombre para c. *ax por ejemplo, se lee el valor de lo que apunta ax (y
como ax apunta a x, entonces *ax es el valor que tiene x esto es 3.14.
printf("%d", *aj); /* imprime el entero 23 */
*ax=*aj-15; /* la variable x contendr ahora un 8.00 (o sea j-15) */
*c='f'; /* la variable c contendr la letra 'f' */
Un Apuntador entonces es una variable que contiene una direccin de memoria, la
cual corresponder a un dato o a una variable que contiene el dato. Los apuntadores
tambin deben de seguir las mismas reglas que se aplican a las dems variables, deben
tener nombre nicos y deben de declararse antes de usarse.
Una variable en un programa es algo con un nombre, que contiene un valor que
puede variar. El modo en que el compilador
compilador y el enlazador (linker) manejan esto es
asignando un espacio o bloque especfico de la memoria dentro de la computadora para
guardar el valor de una variable.

1.1.3. Simbologa.
Hemos con anterioridad representado de forma grafica un nodo, ahora lo que nos
interesara ser llevar esta misma representacin a la creacin de ms elementos como lo
puede ser una lista que se enlaza por medio de un apuntador al nodo siguiente.

Lista 5 12 S 14.7 a null

En este caso se trata de una lista que contiene un primer nodo con un apuntador y un
dato (5) este nodo apunta a otro nodo con otro dato y as sucesivamente hasta llegar a un
dato nulo (NULL).
Hasta aqu hemos visto que un nodo se crea a partir de un apuntador y un dato, en el
cuatrimestre pasado se trabajo con datos y hemos dado anteriormente la definicin de
apuntador y si adems usted es observador se habr dado cuenta que existe el smbolo
(*) junto a la variable apuntador, este smbolo se utiliza para accesar el valor de una
variable a travs del apuntador a ella.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 12 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

1.2. Operaciones Bsicas.


Algunas de las cosas que usted puede hacer con los apuntadores son:
 Guardar y leer la direccin de un objeto del tipo referenciado
 Alterar o recuperar los contenidos en esa direccin (indireccin)
 Sumar o restar un entero
 Restarlo de otro apuntador del mismo tipo
 Compararlo con otro apuntador
 Asignarlo o compararlo a NULL
 Pasarlo como argumento a una funcin
Hemos de ver las operaciones aritmticas bsicas que son realizables con punteros.
Suma.
p+1.
Sumar uno a un puntero significa obtener una direccin igual a la direccin inicial
(contenido de p) ms un nmero de bytes igual al nmero de bytes asociado al tipo del
puntero.
Si p es un puntero a carcter, p + 1 significa sumar uno.
Si p es un puntero a entero, p + 1 significa sumar dos bytes.
Incremento.
p+1 p++
p
Sumar al contenido de p un nmero de bytes igual al tipo base, muy similar al
anterior no creo necesaria la explicacin.
Resta.
Resta
p-1.
Significa obtener una direccin igual al valor de p menos un nmero de bytes igual al
tipo base del puntero.
Decremento.
p-1 p--
p
Restar al contenido del puntero p un nmero de bytes igual al tipo base.
Comparacin.
La comparacin de dos punteros, mediante los operadores != y ==, permite
determinar si apuntan a la misma variable referenciada citado en la siguiente instruccin
(caso a) o si no apuntan a nada (caso b).
a) if (punt1 == punt2)
b) if (punt1 != NULL)

1.2.1. Declaracin.
Un apuntador se declara de la siguiente manera:
type * name.
donde type es cualquier tipo de dato.
Ejemplos de declaraciones de apuntadores
int * apEntero; //Apunta a un entero
float *apFloat; //Apuntador a un dato tipo float
char * cadena; //Apuntador a datos de tipo caracter
Se pueden declarar apuntadores a cualquier objeto en memoria, incluyendo arreglos,
estructuras, funciones e incluso otros apuntadores.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 13 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Ojo, para tener acceso al valor de una variable a travs del apuntador a ella, precede
el apuntador con un asterisco. Por ejemplo, cout<<*cadena, nos va a mostrar el valor del
carcter almacenado en esa direccin. Este valor es alcanzado en forma indirecta a
travs de un apuntador, a este proceso se le llama indireccin o dereferenciacin.
El siguiente programa declara un apuntador y lo usa para ver el valor de la variable.
int main(void)
{
int i = 7, j = 8;
int *ip, *jp;
ip = &i;
jp = &j;
printf("La direccin %p contiene %d (i)\n", ip, *ip);
printf("La direccin %p contiene %d (j)\n", jp, *jp);
*ip = 9;
printf("Ahora la direccin %p contiene %d (i)\n", ip, i);
*jp = 10;
printf("Ahora la direccin %p contiene %d (j)\n", jp, j);
return 0;
}

1.2.2. Inicializacin de apuntador.


Para declarar un apuntador a una variable, hacemos:
int *ip;
Un apuntador siempre apunta a un objeto de algn tipo, as que el tipo referenciado
siempre debe aparecer en la declaracin (nosotros hablamos de apuntador a int,
apuntador a char, etc.).
Cuando un asterisco precede a un apuntador, la expresin resultante se refiere al
valor apuntado. La declaracin int *ip; indica que *ip es un int, por tanto ip es un
apuntador a int. El proceso de referirse a memoria indirectamente por medio de un
apuntador es llamado indireccin o derreferencia. La indireccin puede ocurrir en
cualquier lado de un estatuto de asignacin.
El siguiente programa muestra cmo encontrar la direccin de variables.
int main(void)
{
int i = 7, j = 8;
printf(i == %d, &i == %p\n, i, &i);
printf(j == %d, &j == %p\n, j, &j);
return 0;
}

El operador & regresa la direccin de un objeto dato (variable). El caracter de


conversin %p despliega una direccin en un formato dependiente del compilador
(usualmente hexadecimal).
La salida en el programa anterior ser:
i == 7, &i == FFF4
j == 8, &j == FFF2
La distribucin de la memoria para i y j del ejemplo anterior se muestra a
continuacin: j i
... 0008 0007 ...
FFF2 FFF4

ING JUAN ALBERTO VAZQUEZ G.


Pgina 14 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

1.2.3. Solicitud de memoria para un nodo.


En el cuatrimestre anterior se trabajo con vectores y matrices estticas,
caracterizados por quedar su tamao establecido antes de la ejecucin del programa, y
permanece igual durante toda la ejecucin.
Por ejemplo, supongamos las siguientes declaraciones:
#define MAX 20
int valores[MAX];
int num_elem;
El vector valores queda definido como un tamao de 20 nmeros enteros. Durante la
ejecucin del programa el vector puede tener a lo mucho 20 valores. Por ello, usualmente
disponemos de una variable entera (en este caso num_elem), que nos dice cuntos
valores hay en cada momento en el vector. Si tenemos que recorrer todos los valores del
vector, lo haramos asi:
for (i=0; i<num_elem; i++)
Este planteamiento tiene dos problemas:
Si durante todo el programa tenemos 20 valores en el vector, estamos usando ms
espacio de memoria del estrictamente necesario (porque estamos usando espacio para
20 enteros, aunque necesitemos menos)
Si durante la ejecucin del programa tenemos ms de 20 valores, no podemos
almacenarlos porque no hay espacio suficiente en el vector
La forma de resolver esta situacin es trabajar con vectores y matrices cuyo tamao
se define durante la ejecucin, que pueda crecer y decrecer para adaptarse a las
necesidades de la aplicacin. Para poder hacer esto, necesitamos operaciones de
gestin dinmica de la memoria.
Las operaciones bsicas de gestin dinmica de la memoria en lenguaje C son::
 malloc:
alloc Asigna un cierto espacio de memoria a una estructura de datos (por
ejemplo, un vector)
 free:
free Libera el espacio de memoria asignado a una estructura de datos (ese
espacio queda libre para ser asignado en el futuro a otras estructuras).
El siguiente cdigo construye un vector de enteros del tamao que indica el usuario
por teclado, rellena el vector con los datos que introduce el usuario, amplia el tamao del
vector y sigue rellenando, y finalmente, libera el espacio de memoria ocupado por el
vector.
#include <stdio.h>
#include <stdlib.h>
void main ()
{
// declaramos un puntero a un entero
int *vector;
int num_elem=0;
int i, mas;

printf ("Escribe el numero de elementos del vector\n");


scanf ("%d",&num_elem);

// Ahora se el tamao inicial del vector. Reservo espacio de memoria


vector = (int *) malloc (num_elem*sizeof (int));
if (vector == NULL)
printf ("Operacion incorrecta");
else

ING JUAN ALBERTO VAZQUEZ G.


Pgina 15 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

{
// cargo el vector con los datos leidos del teclado
for (i=0; i<num_elem; i++)
{
printf ("Escribe siguiente elemento:\n ");
scanf ("%d",&vector[i]);
};

// Aado ms elementos
printf ("Cuantos elementos quieres aadir?\n");
scanf ("%d",&mas);

// reajusto el tamao del vector


vector = (int *) realloc (vector, (num_elem+mas)*sizeof (int));
if (vector == NULL)
printf ("Operacion incorrecta");
else
{
for (i=num_elem; i<num_elem+mas; i++)
{
printf ("Escribe siguiente elemento:\n ");
scanf ("%d",&vector[i]);
};
num_elem = num_elem + mas;
}
}
//Mandaremos a imprimir nuestro vector resultante
for (i=0; i<num_elem; i++)
{
printf (" %d\ ", vector[i]);
}

// ya no necesito el vector y libero el espacio de memoria


free (vector);
}
Como puede observarse, para trabajar con un vector dinmico de enteros, los
primero que hay que hacer es declarar un puntero a un entero (en el ejemplo, el puntero
se llama vector). Ese puntero, que inicialmente apunta a cualquier parte, deber apuntar
al sitio de memoria en que comienza el vector de enteros. Cuando hemos averiguado
cuntos enteros debe contener el vector (en nuestro ejemplo num_elem), entonces
usamos la funcin malloc para pedirle al computador que nos busque espacio de
memoria suficiente para albergar un vector de ese tamao. El parmetro de la funcin
malloc justamente es el espacio de memoria necesario, y que en este caso es el espacio
equivalente a num_elem datos cada uno de tamao igual al que ocupa un nmero entero
(la funcin sizeof nos indica el tamao que ocupan los datos cuyo tipo es el que le
indicamos a continuacin entre parntesis). La funcin malloc nos da la direccin de
memoria donde comienza el espacio que ha reservado, y asignamos esa direccin al
puntero vector. Fjate que la palabra malloc est precedida por (int *) para indicar
simplemente que la funcin malloc retornar un apuntador a un entero.
Si la funcin malloc ha tenido problemas para buscar el espacio de memoria (por
ejemplo, no ha encontrado espacio suficiente) entonces malloc retorna el valor NULL.
Debemos, por tanto, asegurarnos de que la operacin de reserva de memoria ha
funcionado bien antes de empezar a usar el vector.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 16 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Si la operacin de reserva de memoria ha funcionado bien, entonces podemos ya


usar el vector exactamente igual que si fuese un vector esttico, con la diferencia de que
ahora el vector ocupa exactamente el espacio que ha elegido el usuario una vez iniciada
la ejecucin del programa.
Despus de haber entendido adecuadamente esta funcin la creacin de nuestro
nodo que como ya se dijo estar integrada por un dato y un apuntador a siguiente nodo.
Esta estructura se ilustra en el cdigo siguiente:
typedef struct _nodo {
int valor;
struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
Hasta aqu solo hemos creado la estructura nodo con los dos datos que nos interesa
para poder utilizarla es necesario requerir el espacio de memoria necesario.
nuevo = (pNodo)malloc(sizeof(tipoNodo));
nuevo->valor = v;

1.2.4. Liberacin del espacio utilizado por un nodo.


Una vez reservada la zona de memoria, podemos utilizarla con seguridad. Si no
queremos que nuestro programa consuma ms memoria de la cuenta, debemos
acordarnos de liberarla cuando no la necesitemos ms. Para ello est la funcin free() a
la que se le pasa la direccin de memoria que queremos liberar.
free (puntero);
 Si hacemos que nuestro puntero apunte a una variable local, cuando la variable
desaparezca, nuestro puntero queda apuntando a una direccin de memoria que
ya no es vlida. Por ejemplo
char * funcion ()
{
char resultado;
char *puntero;
resultado = algun_valor;
puntero = &resultado;
return puntero;
}
 Al liberar una zona de memoria con free() nuestro puntero queda apuntando a una
direccin que ya no contiene un dato til y por lo mismo intentar hacer uso de esta
variable apuntador puede traer serios problemas.
char *puntero = NULL;
puntero = malloc();
free (puntero);
*puntero = 'A';

ING JUAN ALBERTO VAZQUEZ G.


Pgina 17 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

1.3. Comparacin entre las estructuras estticas y dinmicas.


Del cuatrimestre anterior sabemos que las estructuras estticas son aquellas en las
cuales el tamao ocupado en memoria se define antes de que el programa se ejecute y
no puede modificarse durante la ejecucin del programa.
Estas estructuras estn implementadas en casi todos los lenguajes.
Su principal caracterstica es que ocupan solo una casilla de memoria, por lo tanto
una variable simple hace referencia a un nico valor a la vez, dentro de este grupo de
datos se encuentra: enteros, reales, caracteres y bolanos.
Como vera existe gran diferencia de las estructuras dinmicas en las cuales no existe
limitacin o restriccin en el tamao de memoria ocupada.
Mediante el uso de un tipo de datos especifico, denominado puntero, es posible
construir estructuras de datos dinmicas que no son soportadas por la mayora de los
lenguajes, pero que en aquellos que si tienen estas caractersticas ofrecen soluciones
eficaces y efectivas en la solucin de problemas complejos.
Se caracteriza por el hecho de que con un nombre se hace referencia a un grupo de
casillas de memoria. Es decir un dato estructurado tiene varios componentes.
Conocer ambos tipos de estructuras le ser til cuando tenga que programar, dado
que si la memoria es mucha una estructura esttica puede ser utilizada, pero si por el
contrario de lo que usted carece es de memoria entonces la estructura dinmica es ms
aconsejable.

ACTIVIDAD:

Realice ejercicios que presenten por caractersticas el uso de punteros y memoria y


que adems tengan la posibilidad de tomar y liberar memoria.

EVALUACION:

Defina los conceptos de apuntador, nodo y estructura dinmica.


Construya la estructura nodo
Disee un programa donde haga uso de la estructura nodo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 18 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Unidad
LISTAS PILAS Y COLAS 2
2.1. Listas.
2.1.1. Creacin.
2.1.2. Insercin de un nodo.
2.1.3. Borrado de un nodo.
2.1.4. Recorrido.
2.1.5. Aplicaciones.
2.2. Pilas.
2.2.1. Creacin.
2.2.2. Operacin push.
2.2.3. Operacin pop.
2.2.4. Aplicacin.
2.3. Colas.
2.3.1. Creacin.
2.3.2. Insercin de un nodo.
2.3.3. Borrado de un nodo.
2.3.4. Aplicacin.
2.4. Otras listas.
2.4.1. Listas circulares.
2.4.2. Listas doblemente encadenadas.
2.4.3. Listas circulares doblemente encadenadas.
2.5. Matrices de apuntadores.
2.6. Implementacin de matrices utilizando listas y colas.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 19 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

INTRODUCCION:

Las estructuras dinmicas son colecciones de elementos con un tamao que puede
variar cuando se ejecuta el programa (en tiempo de ejecucin del programa). Las colas y
las pilas entran dentro de la clasificacin de estructuras dinmicas.
En la codificacin de estas estructuras dinmicas (pilas y colas) hay que separar dos
conceptos:
1. El mecanismo con el que se insertan/extraen los elementos de la estructura
dinmica (que determinara el que sea pila o cola).
2. El soporte o mecanismo fsico en el que esta implementada la estructura dinmica
(este soporte puede ser una tabla unidimensional o multidimensional, una lista, etc.).
Por lo tanto, es importante destacar que cuando se define una estructura dinmica de
este tipo (pila o cola) se esta especificando como se accede a los datos, pero no como se
gestionan internamente.
En este capitulo se introducen los conceptos relacionados con pilas y colas, y se
llevara el capitulo a travs de algunos ejemplos.

OBJETIVO:
Conocer los conceptos de pilas, colas y listas dinmicas

ING JUAN ALBERTO VAZQUEZ G.


Pgina 20 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

LISTAS PILAS Y COLAS

2.1. Listas.
La forma ms simple de estructura dinmica es la lista abierta. En esta forma los
nodos se organizan de modo que cada uno apunta al siguiente, y el ltimo no apunta a
nada, es decir, el puntero del nodo siguiente vale NULL.
En las listas abiertas existe un nodo especial: el prim
primero.
ero. Normalmente diremos que
nuestra lista es un puntero a ese primer nodo y llamaremos a ese nodo la cabeza de la
lista. Eso es porque mediante ese nico puntero podemos acceder a toda la lista.
Cuando el puntero que usamos para acceder a la lista vale N NULL,
ULL, diremos que la
lista est vaca.
Con las listas tendremos un pequeo repertorio de operaciones bsicas que se
pueden realizar:
o Aadir o insertar elementos.
o Buscar o localizar elementos.
o Borrar elementos.
Cada una de estas operaciones tendr varios casos especiales, por ejemplo, no ser
lo mismo insertar un nodo en una lista vaca, o al principio de una lista no vaca, o la final,
o en una posicin intermedia.

2.1.1. Creacin.
El nodo tpico para construir listas tiene esta forma:
typedef struct _nodo {
int dato;
struct _nodo *siguiente;
} tipoNodo;

typedef tipoNodo *pNodo;


typedef tipoNodo *Lista;
tipoNodo es el tipo para declarar nodos, evidentemente.
pNodo es el tipo para declarar punteros a un nodo.
Lista es el tipo para declarar listas, como pue
puede
de verse, un puntero a un nodo y una
lista son la misma cosa. En realidad, cualquier puntero a un nodo es una lista, cuyo
primer elemento es el nodo apuntado.

Es muy importante que nuestro programa nunca pierda el valor del puntero al primer
elemento, ya que si no existe ninguna copia de ese valor, y se pierde, ser imposible
acceder al nodo y no podremos liberar el espacio de memoria que ocupa.

NOTA: AL FINAL DE LA SECCION 2.1 ENCONTRARA MARCADO EN COLOR


VERDE UN EJEMPLO COMPLETO DE UNA ESTRUC
ESTRUCTURA
TURA LISTA.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 21 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

2.1.2. Insercin de un nodo.


Existen cuatro modos de insercin de un nodo.
Insertar un elemento en una lista vaca:
Este es, evidentemente, el caso ms sencillo. Partiremos de que ya tenemos el nodo
a insertar y, por supuesto un puntero que apunte a l, adems el puntero a la lista valdr
NULL:

El proceso es muy simple, bastar con que:


nodo->siguiente
>siguiente apunte a NULL.
Lista apunte a nodo.
Insertar un elemento en la primera posicin de una lista:
Podemos considerar el caso anterior como un caso particul particular
ar de ste, la nica
diferencia es que en el caso anterior la lista es una lista vaca, pero siempre podemos, y
debemos considerar una lista vaca como una lista.
De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una
lista, en este caso no vaca:

El proceso sigue siendo muy sencillo:


Hacemos que nodo->siguiente
>siguiente apunte a Lista.
Hacemos que Lista apunte a nodo.

Insertar un elemento en la ltima posicin de una lista:


Este es otro caso especial. Para este caso partiremos de una lista no vaca:

El proceso en este caso tampoco es excesivamente complicado:


Necesitamos un puntero que seale al ltimo elemento de la lista. La manera de
conseguirlo es empezar por el primero y avanzar hasta que el nodo que tenga como
siguiente el valor NULL.
Hacer que nodo->siguiente
>siguiente sea NULL.
Hacer que ultimo->siguiente
>siguiente sea n
nodo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 22 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

Insertar un elemento a continuacin de un nodo cualquiera de una lista:


De nuevo podemos considerar el caso anterior como un caso particular de este.
Ahora el nodo "anterior" ser aquel a continuacin del cual insertaremos el nuevo nodo:

Suponemoss que ya disponemos del nuevo nodo a insertar, apuntado por nodo, y un
puntero al nodo a continuacin del que lo insertaremos.
El proceso a seguir ser:
Hacer que nodo->siguiente
>siguiente seale a anterior
anterior->siguiente.
Hacer que anterior->siguiente
>siguiente seale a nodo.

Como vera son deducciones bastantes obvias al final del capitulo usted encontrara el
cdigo completo de este programa es obligacin del maestro del curso explicarle las
dudas que usted tenga.

NOTA: AL FINAL DE LA SECCION 2.1 ENCONTRARA MARCADO EN COLOR


VERDE UN EJEMPLO COMPLETO DE UNA ESTRU
ESTRUCCTURA LISTA.

2.1.3. Borrado de un nodo.

De nuevo podemos encontrarnos con varios casos, segn la posicin del nodo a
eliminar.
Eliminar el primer nodo de una lista abierta:
Es el caso ms simple. Partiremos de una lista con uno o ms nodos, y usaremos un
puntero auxiliar, nodo:

Hacemos que nodo apunte al primer elemento de la lista, es decir a Lista.


Asignamos a Lista la direccin del segundo nodo de la lista: Lista
Lista->siguiente.
>siguiente.
Liberamos la memoria asignada al primer nod
nodo,
o, el que queremos eliminar.
Si no guardamos el puntero al primer nodo antes de actualizar Lista, despus nos
resultara imposible liberar la memoria que ocupa. Si liberamos la memoria antes de
actualizar Lista, perderemos el puntero al segundo nodo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 23 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

Si la lista slo tiene un nodo, el proceso es tambin vlido, ya que el valor de Lista-
Lista
>siguiente es NULL, y despus de eliminar el primer nodo la lista quedar vaca, y el
valor de Lista ser NULL.
De hecho, el proceso que se suele usar para borrar listas ccompletas
ompletas es eliminar el
primer nodo hasta que la lista est vaca.
Eliminar un nodo cualquiera de una lista abierta:
En todos los dems casos, eliminar un nodo se puede hacer siempre del mismo
modo. Supongamos que tenemos una lista con al menos dos elementelementos,
os, y un puntero al
nodo anterior al que queremos eliminar. Y un puntero auxiliar nodo.

El proceso es parecido al del caso anterior:


Hacemos que nodo apunte al nodo que queremos borrar.
Ahora, asignamos como nodo siguiente del nodo anterior, el siguiente
siguient al que
queremos eliminar: anterior->siguiente
>siguiente = nodo
nodo->siguiente.
Eliminamos la memoria asociada al nodo que queremos eliminar.

Si el nodo a eliminar es el ltimo, el procedimiento es igualmente vlido, ya que


anterior pasar a ser el ltimo, y anteri
anterior->siguiente valdr NULL.

NOTA: AL FINAL DE LA SECCION 2.1 ENCONTRARA MARCADO EN COLOR


VERDE UN EJEMPLO COMPLETO DE UNA ESTRUCTURA
ESTRUCTURA LISTA.

2.1.4. Recorrido.
Muy a menudo necesitaremos recorrer una lista, ya sea buscando un valor particular
o un nodo concreto. Las listas abiertas slo pueden recorrerse en un sentido, ya que
cada nodo apunta al siguiente, pero no se puede obtener, por ejemplo, un puntero al
nodo anterior desde un nodo cualquiera si no se empieza desde el principio.
Para recorrer una lista procederemos siempre del mismo modo, usaremos un puntero
auxiliar como ndice:
Asignamos al puntero ndice el valor de Lista.
Abriremos un bucle (llamado comcomnmente ciclo) que al menos debe tener una
condicin, que el ndice no sea NULL.
Dentro del bucle asignaremos al ndice el valor del nodo siguiente al ndice actual.
Por ejemplo, para mostrar todos los valores de los nodos de una lista, podemos usar
el siguiente bucle en C:
typedef struct _nodo {
int dato;
struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;

ING JUAN ALBERTO VAZQUEZ G.


Pgina 24 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

typedef tipoNodo *Lista;


...
pNodo indice;
...
indice = Lista;
while(indice) {
printf("%d\n", indice->dato);
indice = indice->siguiente;
}
Supongamos que slo queremos mostrar los valores hasta que encontremos uno que
sea mayor que 100, podemos sustituir el bucle por:
...
indice = Lista;
while(indice && indice->dato <= 100) {
printf("%d\n", indice->dato);
indice = indice->siguiente;
}
...
Si analizamos la condicin del bucle, tal vez encontremos un posible error: Qu
pasara si ningn valor es mayor que 100, y alcancemos el final de la lista?. Podra
pensarse que cuando ndice sea NULL, si intentamos acceder a ndice->dato se
producir un error.
En general eso ser cierto, no puede accederse a punteros nulos. Pero en este caso,
ese acceso est dentro de una condicin y forma parte de una expresin "and".
Recordemos que cuando se evala una expresin "and", se comienza por la
izquierda, y la evaluacin se abandona cuando una de las expresiones resulta falsa, de
modo que la expresin "ndice->dato <= 100" nunca se evaluar si indice es NULL.
Si hubiramos escrito la condicin al revs, el programa nunca funcionara bien. Esto
es algo muy importante cuando se trabaja con punteros.

NOTA: AL FINAL DE LA SECCION 2.1 ENCONTRARA MARCADO EN COLOR


VERDE UN EJEMPLO COMPLETO DE UNA ESTRUCTURA
ESTRUCTURA LISTA.

2.1.5. Aplicaciones.
Un ejemplo claro de aplicacin de esta estructura es la representacin de una lista de
alumnos.
Si tenemos una lista con n elementos, las posiciones de la lista irn de la 1 a la n
elementos (no se debe contar a partir de la posicin 0).
Es increble que despus de tantas listas que han hecho (ingredientes, compras,
libros, etc) no tenga algo en que darle utilidad a esto, por eso lo invito a terminar esta
seccin analizando el cdigo en C++ para la estructura dinmica lista.

#include <stdlib.h>
#include <stdio.h>
typedef struct _nodo {
int valor;
struct _nodo *siguiente;

ING JUAN ALBERTO VAZQUEZ G.


Pgina 25 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Lista;

/* Funciones con listas: */


void Insertar(Lista *l, int v);
void Borrar(Lista *l, int v);
int ListaVacia(Lista l);
void BorrarLista(Lista *);
void MostrarLista(Lista l);
int main() {
Lista lista = NULL;
pNodo p;
Insertar(&lista, 20);
Insertar(&lista, 10);
Insertar(&lista, 40);
Insertar(&lista, 30);
MostrarLista(lista);
Borrar(&lista, 10);
Borrar(&lista, 15);
Borrar(&lista, 45);
Borrar(&lista, 30);
Borrar(&lista, 40);
MostrarLista(lista);
BorrarLista(&lista);
getchar();
return 0;
}
void Insertar(Lista *lista, int v) {
pNodo nuevo, anterior;
/* Crear un nodo nuevo */
nuevo = (pNodo)malloc(sizeof(tipoNodo));
nuevo->valor = v;
/* Si la lista est vaca */
if(ListaVacia(*lista) || (*lista)->valor > v) {
/* Aadimos la lista a continuacin del nuevo nodo */
nuevo->siguiente = *lista;
/* Ahora, el comienzo de la lista es nuevo nodo */
*lista = nuevo;
}
else {
/* Buscar el nodo de valor menor a v */
anterior = *lista;
/* Avanzamos hasta el ltimo elemento o hasta que
el siguiente tenga un valor mayor que v */
while(anterior->siguiente && anterior->siguiente-
>valor <= v)

ING JUAN ALBERTO VAZQUEZ G.


Pgina 26 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

anterior = anterior->siguiente;
/* Insertamos el nuevo nodo despus del nodo
anterior */
nuevo->siguiente = anterior->siguiente;
anterior->siguiente = nuevo;
}
}
void Borrar(Lista *lista, int v) {
pNodo anterior, nodo;
nodo = *lista;
anterior = NULL;
while(nodo && nodo->valor < v) {
anterior = nodo;
nodo = nodo->siguiente;
}
if(!nodo || nodo->valor != v) return;
else { /* Borrar el nodo */
if(!anterior) /* Primer elemento */
*lista = nodo->siguiente;
else /* un elemento cualquiera */
anterior->siguiente = nodo->siguiente;
free(nodo);
}
}
int ListaVacia(Lista lista) {
return (lista == NULL);
}
void BorrarLista(Lista *lista) {
pNodo nodo;
while(*lista) {
nodo = *lista;
*lista = nodo->siguiente;
free(nodo);
}
}
void MostrarLista(Lista lista) {
pNodo nodo = lista;
if(ListaVacia(lista)) printf("Lista vaca\n");
else {
while(nodo) {
printf("%d -> ", nodo->valor);
nodo = nodo->siguiente;
}
printf("\n");
}
}

ING JUAN ALBERTO VAZQUEZ G.


Pgina 27 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

2.2. Pilas.
Las pilas son estructuras dinmicas que tienen una disciplina de extraccin/insercin
especfica. Esta disciplina se conoce como LIFO (Last In, First Out). Con una disciplina
de gestin de este tipo, el elemento ms recientemente almacenado es el primero en ser
recuperado.
Para poder trabajar con una pila ser necesario realizar las dos operaciones citadas
(extraccin e insercin) con la disciplina especificada ((LIFO).
LIFO). Estas operaciones se van a
realizar con funciones.
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 d de la pila.

2.2.1. Creacin.
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;
tipoNodo es el tipo para declarar nodos, evidentemente.
pNodo 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.
abiert 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
onsideramos como el primer elemento de la lista es en realidad el
ltimo elemento de la pila.
NOTA: AL FINAL DE LA SECCION 2 2.2
.2 ENCONTRARA MARCADO EN COLOR
VERDE UN EJEMPLO COMPLETO DE UNA ESTRUCTURA PILA. PILA.

2.2.2. Operacin push.


Las operaciones con pilas son muy simples, no hay casos especiales, salvo que la
pila est vaca.
Push en una pila vaca:
Partiremos de que ya tenemos el nodo a insertar y, por supuesto un puntero que
apunte a l, adems el puntero a la pila valdr NULL:

ING JUAN ALBERTO VAZQUEZ G.


Pgina 28 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

El proceso es muy simple, bastar con que:


nodo->siguiente
>siguiente apunte a NULL.
Pila apunte a nodo.

Push en una pila no vaca:


Podemos considerar el caso anterior como un caso particular de ste, la nica
diferencia es que podemos y debemos trabajar con una pila vaca como con una pila
normal.
De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una
pila, en este caso no vaca:

El proceso sigue siendo muy sencillo:


Hacemos que nodo->siguiente
>siguiente apunte a Pila.
Hacemos que Pila apunte a nodo.

NOTA: AL FINAL DE LA SECCION 2.2


2.2 ENCONTRARA MARCADO EN COLOR
VERDE UN EJEMPLO COMPLETO DE UNA ESTRUCTURA PILA.
PILA.

2.2.3. Operacin pop.


Ahora slo existe un caso posible, ya que slo podemos leer desde un extremo de la
pila.
Partiremos de una pila con uno o ms nodos, y usaremos un puntero auxiliar, nodo:

Hacemos que nodo apunte al primer elemento de la pila, es decir a Pila.


Asignamos a Pila la direccin del segundo nodo de la pila: Pila
Pila->siguiente.
>siguiente.
Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la
operacin
eracin pop equivale a leer y borrar.
Liberamos la memoria asignada al primer nodo, el que queremos eliminar.

Si la pila slo tiene un nodo, el proceso sigue siendo vlido, ya que el valor de Pila-
Pila
>siguiente es NULL, y despus de eliminar el ltimo nod
nodo
o la pila quedar vaca, y el valor
de Pila ser NULL.
NOTA: AL FINAL DE LA SECCION 2 2.2
.2 ENCONTRARA MARCADO EN COLOR
VERDE UN EJEMPLO COMPLETO DE UNA ESTRUCTURA PILA. PILA.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 29 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

2.2.4. Aplicacin.
El uso de las pilas est ampliamente extendido en aplicaciones relacionadas con
compiladores y sistemas operativos. Tambin se utiliza en cualquier entorno en el que se
utilice la disciplina LIFO (Last In First Out), es decir, en situaciones donde siempre hay
que recuperar el ltimo valor que se almacen.
Recuerdo que el cuatrimestre pasado le comente que las pilas se hacen tiles por
ejemplo en las expresiones matemticas con los parntesis pero tambin lo son cuando
se guarda por ejemplo el historial de internet recordemos que cuando damos atrs
realmente estamos regresando a un valor que fue el ultimo en ser visitado.
He intentado dejarle la estructura pila para que sea analizada en C++.
#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));
getchar();
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;
}

ING JUAN ALBERTO VAZQUEZ G.


Pgina 30 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

int Pop(Pila *pila) {


pNodo nodo; /* var
variable
iable 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 l la
a pila menos el primer
elemento */
*pila = nodo
nodo->siguiente;
/* Guardamos el valor de retorno */
v = nodo->valor;
>valor;
/* Borrar el nodo */
free(nodo);
return v;
}
2.3. Colas.
Una cola 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
primer de la cola
puede comprar la entrada.
2.3.1. Creacin.
El nodo tpico para construir pilas es el mismo que vimos en los captulos anteriores
para la construccin de listas y pilas:
typedef struct _nodo {
int dato;
struct _nodo *siguiente;
} tipoNodo;

typedef
edef 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 a


abierta.
bierta. 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

ING JUAN ALBERTO VAZQUEZ G.


Pgina 31 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

las colas, tambin deberemos mantener un puntero para el lti ltimo


mo 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 tienee nodo siguiente, y leerlos desde el principio, hay que recordar que leer un
nodo implica eliminarlo de la cola.
De nuevo nos encontramos ante una estructura con muy pocas operaciones
disponibles. Las colas slo permiten aadir y leer elementos:
 Aadir: Inserta
serta un elemento al final de la cola.
 Leer: Lee y elimina un elemento del principio de la cola.
NOTA: AL FINAL DE LA SECCION 2 2.3
.3 ENCONTRARA MARCADO EN COLOR VERDE
UN EJEMPLO COMPLETO DE UNA ESTRUCTURA COL A.

2.3.2. Insercin de un nodo.


Las operaciones con colas son muy sencillas, prcticamente no hay casos
especiales, salvo que la cola est vaca.
Aadir elemento en una cola vaca:
Partiremos de que ya tenemos el nodo a insertar y, por supuesto un puntero que
apunte a l, adems los punteros que definen la cola, primero y ultimo que valdrn NULL:

El proceso es muy simple, bastar con que:


nodo->siguiente
>siguiente apunte a NULL.
Y que los punteros primero y ltimo apunten a nodo.

Aadir elemento en una cola no vaca:


De nuevo partiremos de un nodo a insertar, co conn un puntero que apunte a l, y de una
cola, en este caso, al no estar vaca, los punteros primero y ltimo no sern nulos:

El proceso sigue siendo muy sencillo:


Hacemos que nodo->siguiente
>siguiente apunte a NULL.
Despus que ultimo->siguiente
>siguiente apunte a nodo.
Y actualizamos ltimo,, haciendo que apunte a nodo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 32 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

NOTA: AL FINAL DE LA SECCION 2


2.3
.3 ENCONTRARA MARCADO EN COLOR VERDE
UN EJEMPLO COMPLETO DE UNA ESTRUCTURA COL A.

2.3.3. Borrado de un nodo.


Ahora tambin existen dos casos, que la cola tenga un solo elemento o que tenga
ms de uno.
Leer un elemento en una cola con ms de un elemento:
Usaremos un puntero a un nodo auxiliar:

Hacemos que nodo apunte al primer elemento de la cola, es decir a primero.


Asignamos a primero la direccin del segundo nodo de la pila: p
primero
rimero->siguiente.
Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la
operacin de lectura en colas implica tambin borrar.
Liberamos la memoria asignada al primer nodo, el que queremos eliminar.

Leer un elemento en una cola con un solo elemento:


Tambin necesitamos un puntero a un nodo auxiliar:

Hacemos que nodo apunte al primer elemento de la pila, es decir a primero.


Asignamos NULL a primero, que es la direccin del segundo nodo terico de la cola:
primero->siguiente.
Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la
operacin de lectura en colas implica tambin borrar.
Liberamos la memoria asignada al primer nodo, el que queremos eliminar.
Hacemos que ultimo apunte a NULL, ya que la lectur
lectura
a ha dejado la cola vaca.

NOTA: AL FINAL DE LA SECCION 2


2.3
.3 ENCONTRARA MARCADO EN COLOR VERDE
UN EJEMPLO COMPLETO DE UNA ESTRUCTURA COL A.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 33 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

2.3.4. Aplicacin.
La colas tienen muchas aplicaciones en los sistemas computacionales casos tpicos
podra ser la cola de impresin o el mismo procesador de la computadora que recibe
ordenes a cumplir pero que deben de almacenarse en una memoria para irse procesando
en el orden en el cual van llegando y es que es obvio que se deben establecer
prioridades pero aun as las prioridades llevan una serie de instrucciones que siguen una
estructura de cola.
Dada la gran importancia en este capitulo de las colas he dejado aqu el cdigo
completo de una cola elaborada para ser diseada en C++.

#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));
getchar();
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;

ING JUAN ALBERTO VAZQUEZ G.


Pgina 34 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

/* Si la cola no estaba vaca, aadimos el nuevo a


continuacin de ultimo */
if(*ultimo) (*ultimo)
(*ultimo)->siguiente = nuevo;
/* Ahora, el ltimo elemento de la cola es e 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 */
/* Asignam
Asignamos
os a primero la direccin del segundo nodo
*/
*primero = nodo
nodo->siguiente;
/* Guardamos el valor de retorno */
v = nodo->valor;
>valor;
/* Borrar el nodo */
free(nodo);
/* Si la cola qued vaca, ultimo debe ser NULL
tambin*/
if(!*primero) *u
*ultimo = NULL;
return v;
}
2.4. Otras listas.

2.4.1. Listas circulares.


Una lista circular es una lista lilineal en la que el ltimo nodo apunta
punta al primero.

A pesar de que las listas circulares simplifiquen las operaciones sobre ellas, tambin
introducen algunas complicaciones. Por ejemplo, en un proceso de bsqueda, no es tan
sencillo dar por terminada la bsqueda cuando el elemento buscado no existe.
Por ese motivo se suele resaltar un nodo en particular, que no tiene por qu ser
siempre el mismo. Cualquier nodo puede cumplir ese propsito, y puede variar durante la
ejecucin del programa.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 35 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

Otra alternativa que se usa a menudo, y que simplifica en cierto modo el uso de listas
circulares es crear un nodo especial de har la funcin de nodo cabecera. De este modo,
la
a lista nunca estar vaca, y se eliminan casi todos los casos especiales.
El nodo tpico es el mismo que para construir listas abiertas:
A todos los efectos, las listas circulares son como las listas abiertas en cuanto a las
operaciones que se pueden real realizar sobre ellas:
Aadir elemento en una lista circular vaca:
Partiremos de que ya tenemos el nodo a insertar y, por supuesto un puntero que
apunte a l, adems el puntero que define la lista, que valdr NULL:

El proceso es muy simple, bastar con que:


lista apunta a nodo.
>siguiente apunte a nodo.
lista->siguiente

Aadir elemento en una lista circular no vaca:


De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una
lista, en este caso, el puntero no ser nulo:

El proceso sigue siendo


endo muy sencillo:
Hacemos que nodo->siguiente
>siguiente apunte a lista
lista->siguiente.
Despus que lista->siguiente
>siguiente apunte a nodo.

Eliminar un elemento de la lista.


Consideraremos los dos primeros casos como uno slo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 36 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

El primer paso es conseguir que lista apunte al nodo anterior al que queremos
eliminar. Esto se consigue haciendo que lista valga lista lista->siguiente
>siguiente mientras lista-
lista
>siguiente sea distinto de nodo.
Hacemos que lista->siguiente
>siguiente apunte a nodo
nodo->siguiente.
Eliminamos el nodo.

Hemos llegado a el final del estudio de las listas circulares, como lo he venido
haciendo en captulos anteriores pondr un ejemplo que esta compilado en C++ de una
lista circular.

#include <stdio.h>

typedef struct _nodo {


int valor;
struct _nodo *siguiente;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Lista;
// Funciones con listas:
void Insertar(Lista *l, int v);
void Borrar(Lista *l, int v);
void BorrarLista(Lista *);
void MostrarLista(Lista l);
int main() {
Lista lista = NULL;
pNodo p;
Insertar(&lis
Insertar(&lista, 10);
Insertar(&lista, 40);
Insertar(&lista, 30);
Insertar(&lista, 20);
Insertar(&lista, 50);
MostrarLista(lista);
Borrar(&lista, 30);
Borrar(&lista, 50);
MostrarLista(lista);
BorrarLista(&lista);
getchar();
return 0;
}

void Insertar(Lista *lista, int v) {

ING JUAN ALBERTO VAZQUEZ G.


Pgina 37 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

pNodo nodo;
// Creamos un nodo para el nuvo valor a insertar
nodo = (pNodo)malloc(sizeof(tipoNodo));
nodo->valor = v;
// Si la lista est vaca, la lista ser el nuevo nodo
// Si no lo est, insertamos el nuevo nodo a
continuacin del apuntado
// por lista
if(*lista == NULL) *lista = nodo;
else nodo->siguiente = (*lista)->siguiente;
// En cualquier caso, cerramos la lista circular
(*lista)->siguiente = nodo;
}

void Borrar(Lista *lista, int v) {


pNodo nodo;
nodo = *lista;
// Hacer que lista apunte al nodo anterior al de valor
v
do {
if((*lista)->siguiente->valor != v) *lista =
(*lista)->siguiente;
} while((*lista)->siguiente->valor != v && *lista !=
nodo);
// Si existe un nodo con el valor v:
if((*lista)->siguiente->valor == v) {
// Y si la lista slo tiene un nodo
if(*lista == (*lista)->siguiente) {
// Borrar toda la lista
free(*lista);
*lista = NULL;
}
else {
// Si la lista tiene ms de un nodo, borrar el
nodo de valor v
nodo = (*lista)->siguiente;
(*lista)->siguiente = nodo->siguiente;
free(nodo);
}
}
}
void BorrarLista(Lista *lista) {
pNodo nodo;
// Mientras la lista tenga ms de un nodo
while((*lista)->siguiente != *lista) {
// Borrar el nodo siguiente al apuntado por lista
nodo = (*lista)->siguiente;

ING JUAN ALBERTO VAZQUEZ G.


Pgina 38 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

(*lista)
(*lista)->siguiente = nodo->siguiente;
free(nodo);
}
// Y borrar el ltimo nodo
free(*lista);
*lista = NULL;
}
void MostrarLista(Lista lista) {
pNodo nodo = lista;
do {
printf("%d -> ", nodo->valor);
nodo = nodo
nodo->siguiente;
} while(nodo != lista);
printf("\n");
n");
}

2.4.2. Listas doblemente encadenadas.


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 a ellas,
pueden recorrerse en ambos sentidos a partir de cualquier nodo, esto es porque a partir
de cualquier nodo, siempre es posible alcanzar cualquier nodo de la lista, hasta que se
llega a uno de los extremos.

El nodo tpico es el mismo que para construir las listas que hemos visto, salvo
sa que
tienen otro puntero al nodo anterior:
struct nodo {
int dato;
struct nodo *siguiente;
struct nodo *anterior;
};
Nos encontramos ahora ante un tipo de estructura algo diferente de las que hemos
estado viendo, as que entraremos en ms detalles.
Vamos a intentar ver todos los casos posibles de insercin de elementos en listas
doblemente enlazadas.
Aadir elemento en una lista doblemente enlazada vaca:
Partiremos de que ya tenemos el nodo a insertar y, por supuesto un puntero que
apunte a l, adems el puntero que define la lista, que valdr NULL:

ING JUAN ALBERTO VAZQUEZ G.


Pgina 39 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

El proceso es muy simple, bastar con que:


lista apunta a nodo.
lista->siguiente y lista->anterior
>anterior apunten a null.

Insertar un elemento en la primera posicin de la lista:


Partimos de una lista no vaca. Para simplificar, consideraremos que lista apunta al
primer elemento de la lista doblemente enlazada:

El proceso es el siguiente:
nodo->siguiente
>siguiente debe apuntar a Lista.
nodo->anterior
>anterior apuntar a Lista
Lista->anterior.
Lista->anterior
>anterior debe apun
apuntar a nodo.

Recuerda que Lista no tiene por qu apuntar a ningn miembro concreto de una lista
doblemente enlazada, cualquier miembro es igualmente vlido como referencia.
Insertar un elemento en la ltima posicin de la lista:
Igual que en el caso ante anterior,
rior, partiremos de una lista no vaca, y de nuevo para
simplificar, que Lista est apuntando al ltimo elemento de la lista:

El proceso es el siguiente:
nodo->siguiente
>siguiente debe apuntar a Lista
Lista->siguiente (NULL).
Lista->siguiente
>siguiente debe apuntar a nodo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 40 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

nodo->anterior
>anterior apuntar a Lista.

Insertar un elemento a continuacin de un nodo cualquiera de una lista:


Bien, este caso es ms genrico, ahora partimos de una lista no vaca, e
insertaremos un nodo a continuacin de uno nodo cualquiera que no sea el ltimo de la
lista:

El proceso sigue siendo muy sencillo:


Hacemos que nodo->siguiente
>siguiente apunte a lista
lista->siguiente.
Hacemos que Lista->siguiente
>siguiente apunte a nodo.
Hacemos que nodo->anterior
>anterior apunte a lista.
Hacemos que nodo->siguiente
>siguiente->anterior apunte a nodo.

Loo que hemos hecho es trabajar como si tuviramos dos listas enlazadas, los dos
primeros pasos equivalen a lo que hacamos para insertar elementos en una lista abierta
corriente.
Los dos siguientes pasos hacen lo mismo con la lista que enlaza los nodos en
sentido contrario.
Eliminar el nico nodo en una lista doblemente enlazada:
En este caso, ese nodo ser el apuntado por Lista.

Eliminamos el nodo.
Hacemos que Lista apunte a NULL.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 41 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

Eliminar el primer nodo de una lista doblemente enlazada:


Tenemos los dos casos posibles, que el nodo a borrar est apuntado por Lista o que
no. Si lo est, simplemente hacemos que Lista sea Lista
Lista->siguiente.

Si nodo apunta a Lista, hacemos que Lista apunte a Lista


Lista->siguiente.
>siguiente.
Hacemos que nodo->siguiente
>siguiente->anterior apunte a NULL
Borramos el nodo apuntado por nodo.

El paso 2 depara el nodo a borrar del resto de la lista, independientemente del nodo
al que apunte Lista.
Eliminar el ltimo nodo de una lista doblemente enlazada:
De nuevo tenemos los dos casos posibles, que el nodo a borrar est apuntado por
Lista o que no. Si lo est, simplemente hacemos que Lista sea Lista
Lista->anterior.
>anterior.

Si nodo apunta a Lista, hacemos que Lista apunte a Lista


Lista->anterior.
Hacemos que nodo->anterior
>anterior->siguiente apunte a NULL
Borramos el nodo apuntado
puntado por nodo.

El paso 2 depara el nodo a borrar del resto de la lista, independientemente del nodo
al que apunte Lista.
Eliminar un nodo intermedio de una lista doblemente enlazada:
De nuevo tenemos los dos casos posibles, que el nodo a borrar est apuntado por
Lista o que no. Si lo est, simplemente hacemos que Lista sea ListaLista->anterior
>anterior o Lista-
Lista
>siguiente
ING JUAN ALBERTO VAZQUEZ G.
Pgina 42 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

Se trata de un caso ms general de los dos casos anteriores..

Si nodo apunta a Lista, hacemos que Lista apunte a Lista Lista->anterior


>anterior (o Lista-
Lista
>siguiente).
Hacemos que nodo->anterior
>anterior->siguiente apunte a nodo->siguiente.
Hacemos que nodo->siguiente
>siguiente->anterior apunte a nodo->anterior.
Borramos el nodo apuntado por nodo.

Finalmente el cdigo para ser compilado en C++ es mostrado a continuacin.


#include
ude <stdio.h>
#define ASCENDENTE 1
#define DESCENDENTE 0
typedef struct _nodo {
int valor;
struct _nodo *siguiente;
struct _nodo *anterior;
} tipoNodo;
typedef tipoNodo *pNodo;
typedef tipoNodo *Lista;
/* Funciones con listas: */
void Insertar(Lista *l, int v);
void Borrar(Lista *l, int v);
void BorrarLista(Lista *);
void MostrarLista(Lista l, int orden);
int main() {
Lista lista = NULL;
pNodo p;
Insertar(&lista, 20);
Insertar(&lista, 10);
Insertar(&lista, 40);
Insertar(&lista,
ar(&lista, 30);
MostrarLista(lista, ASCENDENTE);
MostrarLista(lista, DESCENDENTE);
Borrar(&lista, 10);
Borrar(&lista, 15);
Borrar(&lista, 45);
Borrar(&lista, 30);
MostrarLista(lista, ASCENDENTE);

ING JUAN ALBERTO VAZQUEZ G.


Pgina 43 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

MostrarLista(lista, DESCENDENTE);
BorrarLista(&lista);
getchar();
return 0;
}
void Insertar(Lista *lista, int v) {
pNodo nuevo, actual;
/* Crear un nodo nuevo */
nuevo = (pNodo)malloc(sizeof(tipoNodo));
nuevo->valor = v;
/* Colocamos actual en la primera posicin de la lista
*/
actual = *lista;
if(actual) while(actual->anterior) actual = actual-
>anterior;
/* Si la lista est vaca o el primer miembro es mayor
que el nuevo */
if(!actual || actual->valor > v) {
/* Aadimos la lista a continuacin del nuevo nodo
*/
nuevo->siguiente = actual;
nuevo->anterior = NULL;
if(actual) actual->anterior = nuevo;
if(!*lista) *lista = nuevo;
}
else {
/* Avanzamos hasta el ltimo elemento o hasta que
el siguiente tenga
un valor mayor que v */
while(actual->siguiente &&actual->siguiente->valor
<= v)
actual = actual->siguiente;
/* Insertamos el nuevo nodo despus del nodo
anterior */
nuevo->siguiente = actual->siguiente;
actual->siguiente = nuevo;
nuevo->anterior = actual;
if(nuevo->siguiente) nuevo->siguiente->anterior =
nuevo;
}
}
void Borrar(Lista *lista, int v) {
pNodo nodo;
/* Buscar el nodo de valor v */
nodo = *lista;
while(nodo && nodo->valor < v) nodo = nodo->siguiente;
while(nodo && nodo->valor > v) nodo = nodo->anterior;

ING JUAN ALBERTO VAZQUEZ G.


Pgina 44 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

/* El valor v no est en la lista */


if(!nodo || nodo->valor != v) return;
/* Borrar el nodo */
/* Si lista apunta al nodo que queremos borrar,
apuntar a otro */
if(nodo == *lista)
if(nodo->anterior) *lista = nodo->anterior;
else *lista = nodo->siguiente;
if(nodo->anterior) /* no es el primer elemento */
nodo->anterior->siguiente = nodo->siguiente;
if(nodo->siguiente) /* no es el ltimo nodo */
nodo->siguiente->anterior = nodo->anterior;
free(nodo);
}
void BorrarLista(Lista *lista) {
pNodo nodo, actual;
actual = *lista;
while(actual->anterior) actual = actual->anterior;
while(actual) {
nodo = actual;
actual = actual->siguiente;
free(nodo);
}
*lista = NULL;
}
void MostrarLista(Lista lista, int orden) {
pNodo nodo = lista;
if(!lista) printf("Lista vaca");
nodo = lista;
if(orden == ASCENDENTE) {
while(nodo->anterior) nodo = nodo->anterior;
printf("Orden ascendente: ");
while(nodo) {
printf("%d -> ", nodo->valor);
nodo = nodo->siguiente;
}
}
else {
while(nodo->siguiente) nodo = nodo->siguiente;
printf("Orden descendente: ");
while(nodo) {
printf("%d -> ", nodo->valor);
nodo = nodo->anterior;
}
}
printf("\n");
}

ING JUAN ALBERTO VAZQUEZ G.


Pgina 45 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

2.4.3. Listas circulares doblemente encadenadas.


Realmente resultara difcil intentar entender esta seccin sin un antecedente de lo
que es una lista doblemente enlazada o una lista circular dado que para realizar listas
circulares doblemente enlazada solo habr que seguir la lgica que se ha venido
planteando con anterioridad, utilizando y haciendo la mezcla de ambas partes.

2.5. Matrices de apuntadores.


De cuatrimestre anteriores sabemos que una matriz es una coleccin de datos en
dos dimensiones y en el cuatrimestre anterior estuvimos conociendo como disear
matrices a partir de arreglos pero, Que pasa si la matriz que queremos utilizar no
conocemos en un inicio su tamao?
Esta pregunta no poda ser contestada anteriormente porque no conocamos el
concepto de puntero, hasta ahora tan til, y es que adems de resolver el problema de
las pilas y las colas tambin nos ayuda en la creacin de matrices que no tienen porque
ser definidas desde el inicio, sino que pueden ser creadas haciendo uso de apuntadores,
para mejor comprensin he diseado este ejemplo que es recomendable realice en un
compilador con ayuda de su profesor.
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
int nc, nr;
int **M; // definicin de un apuntador de apuntadores a
entero
printf("dame el numero de renglones\n");
scanf("%d",&nr);
// creamos un vector de apuntadores a entero
*M=(int *)malloc(sizeof(int*)*nr);
printf("dame el numero de columnas\n");
scanf("%d",&nc);
// creamos un vector de enteros de tamao nc
for(int i=0; i<nr; i++)
M[i]=(int*)malloc(sizeof(int)*nc);
// Una vez que se aparto memoria para construir el
arreglo de dos dimensiones,
// la variable apuntador a apuntadores se utiliza como
una matriz
// llenamos la matriz de nr renglones por nc columnas
for(i=0; i<nr; i++)
for(int j=0; j<nc; j++){
printf("dame un entero\n");
scanf("%d",&M[i][j]);
}
system("clear");
// escribimos la matriz de forma rectangular

ING JUAN ALBERTO VAZQUEZ G.


Pgina 46 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

for(i=0; i<nr; i++){


for(j=0; j<nc; j++)
printf("%d\t",M[i][j]);
printf("\n");
}
}
Tal vez no le sea esto muy conmovedor pero estoy seguro que le servir para crear
aplicaciones ms potentes que cuando lo haga con arreglos.

2.6. Implementacin de matrices utilizando listas y colas.

En una pila y una cola no solo podemos insertar datos, sino tambin matrices y
tratarlas como se tratan los datos un lenguaje que hace esto es OpenGL el cual contiene
comandos para insertar matrices en las pilas o para eliminarlos.
Tal vez usted opine que son muy pocos los que utilizan Open GL o aplicaciones
similares y la verdad es que tiene la razon pero yo le dira que son pocos los que tienen
inters por aprender nuevas cosas por lo mismo mi invitacin es llevarlo a conocer las
enormes aplicaciones que puede tener haciendo uso de punteros y arreglos.
Finalmente dejo para que investigue los comandos glPushMatrix() y glPopMatrix()
ojala y esto lo motive a aprender mas.

ACTIVIDAD:

Realice una tabla comparativa de las estructuras vistas de modo que con esa tabla
pueda diferenciar una cola de una lista y una pila.

EVALUACION:

Qu diferencia existe entre aadir elementos a una lista, una cola y una pila?
Qu diferencia existe entre borrar elementos a una lista, una cola y una pila?
Qu importancia tiene manejar matrices en las listas, pilas y colas?
Qu de diferente tiene una lista circular de una lista no circular a la hora de eliminar
elementos?
Cmo explicara el proceso de eliminar un elemento en una lista doblemente
enlazada?

ING JUAN ALBERTO VAZQUEZ G.


Pgina 47 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Unidad
RECURSION 3
3.1. Definicin.
3.2. Ejemplos y aplicaciones.
3.3. Diseo de algoritmos recursivos.
3.4. Implementacin de la recursin utilizando pilas.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 48 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

INTRODUCCION:

Una funcin puede, en su definicin, llamarse a s misma. Esto no ahorra memoria


(hay mltiples copias de variables), por lo que hay que tener cuidado de no realizar una
recursin demasiado grande, o sin salida, ya que de hacerlo, esta multiplicacin de las
variables automticas de la funcin hara que el programa corra fuera de la pila, atacando
otras regiones del programa, y produciendo que el proceso "reviente".
Hay problemas que son ms naturalmente tratados a travs de la recursin. En
muchos casos, esto no quiere decir eficiencia, pero si compacidad y "elegancia" del
cdigo; pero en otros casos, se obtienen soluciones tanto elegantes como eficientes a un
problema dado.
Generalmente en un problema que se define en forma recursiva hay una solucin
trivial
trivial y otra que se define en base al problema mismo. En la implementacin de una
funcin recursiva tambin, habr una solucin trivial y una solucin recursiva.

OBJETIVO:
Conoceremos las ventajas y desventajas de la recursin y haremos uso de ejemplos
en los cuales se hace uso de la ella.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 49 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

RECURSION
3.1. Definicin.

La recursividad es una caracterstica soportada por muchos lenguajes de


programacin y constituye, por si sola, un potente recurso para el diseo de algoritmos, y
por lo tanto, para solucin de problemas. En este tema se presenta la tcnica, as como,
las estrategias a seguir para disear algoritmos que la empleen.
La recursividad permite que un procedimiento o funcin se invoque a si misma dentro
de su definicin. En este sentido, la recursividad, es anloga a la definicin por induccin
de un concepto, es decir, la definicin de un concepto en trminos de si misma.
Conceptualmente la recursividad proporciona al igual que la iteracin un mecanismo
de repeticin de acciones, aunque los planteamientos son distintos. En la solucin
iterativa, la solucin del problema se basa en identificar el problema ms elemental y
repetir la resolucin de ese problema elemental un nmero determinado de veces. En la
solucin recursiva el planteamiento es diferente y se basa en descomponer los datos de
forma simple y aplicar de nuevo el algoritmo sobre los datos ya descompuestos por
ejemplo, la funcin FACTORIAL de un nmero entero N, que se denota N!, se adapta a la
definicin de funcin recursiva: se define para los valores elementales 0 y 1:
0! = 1
1! = 1
y, para el resto de los valores se puede obtener utilizando estos:
2! = 2 * 1!
3! = 3 * 2!
4! = 4 * 3!
.................
N! = N * (N-1)!
Hay funciones matemticas que no admiten un mtodo de obtencin recursivo; las
hay que admiten tanto un mtodo recursivo como un mtodo no recursivo (iterativo), y las
hay que slo admiten un mtodo recursivo.

3.2. Ejemplos y aplicaciones.

Hemos visto que la funcin factorial es una funcin que se puede definir
recursivamente y cuyo dominio es el de los enteros positivos. La funcin factorial, que se
representa con el smbolo de exclamacin, se define como:
n! = n X (n - 1) X (n - 2) X ... X 1
lo cual significa que n! es igual al producto de todos los enteros no negativos entre n y 1,
inclusivos. Consideremos los factoriales de los enteros no negativos del 1 al 5:
1! = 1
2! = 2 X 1
3! = 3 X 2 X 1
4! = 4 X 3 X 2 X 1
5! = 5 X 4 X 3 X 2 X 1
Consideremos ahora la ejecucin de la funcin recursiva Factorial.
#include <stdio.h>
double Factorial(int N);

ING JUAN ALBERTO VAZQUEZ G.


Pgina 50 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

main()
{
int i;

for(i = 1; i < 10; i++)


printf("%d!=%f\n", Factorial(i);
}
double Factorial(int N)
{
if(N == 0) /* Solucin Trivial */
return 1;
return N * Factorial(N-1); /* Solucin Recursiva */
}
cout << factorial(N)<< endl;
system("PAUSE");
return 0;
}
Como puedes ver, la funcin Factorial se llama a si misma para hallar el valor de (N-
1)!. A este tipo de recursin, donde un procedimiento se llama a s mismo, se le
denomina recursin explcita o recursin directa. Si un procedimiento P llama a otro Q, Q
llama a R, R llama a S,... , y Z llama de nuevo a P, entonces tambin tenemos recursin,
y a este tipo de recursin se le denomina recursin implcita o recursin indirecta.
En C++, cuando se llama a un procedimiento (o funcin), se guarda la direccin de la
sentencia llamante como direccin de retorno, se asigna memoria a las variables locales
del procedimiento, y al finalizar la ejecucin del procedimiento, se libera la memoria
asignada a las variables locales y se devuelve la ejecucin al punto en que se hizo la
llamada haciendo uso de la direccin de retorno.
Pero qu es la direccin de retorno?
Cuando una sentencia escrita en un lenguaje de alto nivel se traduce a cdigo
mquina, dicha sentencia suele representar varias lneas de cdigo mquina, es decir, la
traduccin no es una a una sino una a muchas. Cuando nos referimos a la direccin de
retorno, nos estamos refiriendo a la direccin de la instruccin que sigue a la instruccin
de llamada al procedimiento. Esta direccin podra estar en medio de la traduccin de
una sentencia de alto nivel (como en el caso de las llamadas a funciones) o podra ser la
primera instruccin de la traduccin de la sentencia de alto nivel, as como la propia
llamada a la funcin.
Podemos extraer entonces las siguientes conclusiones:
a) Para poder resolver un problema de forma recursiva se debe poder definir en
trminos de una versin ms pequea del mismo problema.
b) En cada llamada recursiva debe disminuir el tamao del problema.
c) El diseo de la solucin del problema ha de ser tal que asegure la ejecucin
del caso base y por tanto, el fin del proceso recursivo.
La recursin, si se usa con cuidado, nos permitir solucionar de forma elegante
algunos problemas. En este apartado se va a resolver otro problema usando un
procedimiento recursivo.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 51 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Una sucesin de nmeros muy conocida y usada en matemticas es justamente la sucesin de


Fibonacci, que se construye de la siguiente manera:
a) La sucesin empieza con dos unos.
b) Cualquier trmino de la sucesin se obtiene de sumar los dos anteriores. Por ejemplo, el
noveno trmino de la sucesin se construye sumando el sptimo y el octavo.
c) La sucesin es infinita.
As la sucesin de Fibonacci es:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,
17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229,...
Empezaremos con un problema simple. El trmino n-simo de la sucesin de
Fibonacci se puede definir como:
#include <iostream.h>
#include <stdlib.h>
double Fib(double N)
{
if (N<= 2)
{
return 1;
}
else
{
return Fib(N-1) + Fib(N - 2);
}
}
int main()
{
double i, N;
cout << "Teclea un entero positivo: ";
cin>> N << endl;
for (i=1; i<=N; i++)
{
cout << i<< " simo trmino de Fibonacci es: ";
cout << Fib(i)<< endl;
}
system("PAUSE");
return 0;
}
Analicemos ahora la ejecucin de este programa; cuando N = 6 vamos a hallar el
nmero de veces que se invoca la funcin Fib. Para hallar Fib(6), previamente tenemos
que hallar Fib(5) y Fib(4); para hallar Fib(4), tenemos que hallar Fib(3) y Fib(2); y as
sucesivamente. Las invocaciones de la funcin Fib se pueden ilustrar de la siguiente
forma:

ING JUAN ALBERTO VAZQUEZ G.


Pgina 52 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Como se puede observar en el diagrama anterior, para hallar F(6) tenemos que
llamar a la funcin Fib 15 veces. De esas 15 llamadas, tres tienen como argumento el 1,
cinco tienen como argumento el 2, tres tienen como argumento el 3, dos tienen el 4 como
argumento y con argumentos 5 y 6 slo hay dos llamadas. Esto significa que el primer
nmero de la serie de Fibonacci, se calcula tres veces, el segundo se calcula 5 veces,
etc. Este anlisis demuestra el por qu una funcin recursiva puede llegar a ser una
herramienta muy costosa para solucionar un problema ya que se debe hacer uso de gtan
cantidad de memoria.
Como usted vera se hace uso solo una vez de la recursin a esto se le llama
recursin simple.
simple Habr algoritmos que nos lleven a utilizar la recursin en ms de una
llamada a si misma esto se llamara recursin mltiple.
mltiple
Por ejemplo sea el siguiente caso:
Hacer un programa que escriba en pantalla los nmeros del 1 al 100.
#include <stdio.h>
void paso1 (int i);
void paso2 (int i); Vea aqu el cdigo nos la
main () pasamos a travs de varios ciclos
{ jugando con la funciones paso1 y
int i=0; paso2 le damos varias vueltas pero
paso1 (i); tambin hemos aprovechado para
return (i); separar los elementos pares e
} impares.
void paso1 (int i)
{
i++;
printf("I=%i
Impar\n",i);
paso2(i);
}
void paso2(int i)
{
i++;
printf("I=%i Par \n",i);
if (i < 100)

ING JUAN ALBERTO VAZQUEZ G.


Pgina 53 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

paso1 (i);
}

En este tipo de algoritmos se esta utilizando tambin la recursin solo que note que
una funcin manda a llamar a otra funcin y as sucesivamente resultando lo que se
llama recursin cruzada o indirecta.
Cabe aclarar que si usted realiza este ejercicio sustituyendo el 100 por el 10000 a la
hora de que se este ejecutando el programa existir un error esto se debe a que hemos
llenado la memoria de nuestra de programa, hemos agotado los recursos, INTENTELO!
Este es un diagrama de flujo que intenta explicar a grandes rasgos como funciona la
recursin directa e indirecta.

3.3. Diseo de algoritmos recursivos.


Una vez introducidas las caractersticas generales de un algoritmo recursivo, esta
seccin se centra en las cuestiones que tienen que ver con el diseo de algoritmos
recursivos en general y de definiciones recursivas.
Como criterio bsico se adoptara que los algoritmos recursivos no harn uso de
variables globales, por lo que, cada funcin o procedimiento solo conocer los
parmetros formales y las variables locales que defina.
Una accin con nombre recursiva se dice que es lineal, si cada llamada recursiva
genera como mucho otra llamada recursiva a si misma. En caso contrario se dice que la
funcin recursiva no es lineal o recursiva mltiple. Un ejemplo de funcin recursiva lineal
seria el del factorial.
El mtodo habitual de diseo para acciones con nombre recursivas es el que se
especifica a continuacin:
 Especificacin e identificacin de parmetros de la funcin o procedimiento.
Se escribir la declaracin de la funcin identificando todos los parmetros que
intervienen en la misma. Sera tambin recomendable identificar la precondicin y la
poscondicin de la accin.
 Anlisis por casos:
Se tratar de estudiar como se pueden descomponer de forma recursiva los datos
que representan el caso actual de forma que se pueda calcular fcilmente la solucin
pedida a partir de la solucin parcial obtenida por la propia funcin para el /los casos ms
sencillos considerados.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 54 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

3.4. Implementacin de la recursin utilizando pilas.


De materias anteriores sabemos que la memoria del ordenador se divide (de manera
lgica, no fsica) en varios segmentos (4):
Segmento de cdigo:
cdigo Parte de la memoria donde se guardan las instrucciones del
programa en cdigo mquina.
Segmento de datos:datos Parte de la memoria destinada a almacenar las variables
estticas.
Montculo:
Montculo Parte de la memoria destinada a las variables dinmicas.
Pila del programa:
programa Parte destinada a las variables locales y parmetros de la funcin
que est siendo ejecutada.
Llamada a una funcin:
 Se reserva espacio en la pila para los parmetros de la funcin y sus variables
locales.
 Se guarda en la pila la direccin de la lnea de cdigo desde donde se ha
llamado a la funcin.
 Se almacenan los parmetros de la funcin y sus valores en la pila.
 Al terminar la funcin, se libera la memoria asignada en la pila y se vuelve a la
instruccin actual.
Llamada a una funcin recursiva:
 En el caso recursivo, cada llamada genera un nuevo ejemplar de la funcin
con sus correspondientes objetos locales:
 La funcin se ejecutar normalmente hasta la llamada a s misma. En ese
momento se crean en la pila nuevos parmetros y variables locales.
 El nuevo ejemplar de funcin comienza a ejecutarse.
 Se crean ms copias hasta llegar a los casos bases, donde se resuelve
directamente el valor, y se va saliendo liberando memoria hasta llegar a la
primera llamada (ltima en cerrarse)
Tal vez resulte ms claro si se realiza un ejemplo, estamos en disposicin de trazar la
ejecucin del programa del factorial para el caso de N=3.
Para llevar a cabo la recursin, las computadoras usan pilas. Al comienzo de la
ejecucin de un procedimiento, la pila est vaca (Figura 1.a, en la siguiente pagina).
Cuando la ejecucin alcanza la sentencia:
cout << factorial(N);
se produce una llamada a la funcin Factorial con N = 3. Esto hace que se cree un
registro de activacin, y este registro se inserta en la pila (Figura 1b). Cuando se ejecuta
la parte ELSE de la funcin Factorial (cuando la sentencia IF no es TRUE), se produce
una nueva llamada a Factorial, pero esta vez el argumento es 3 -1 =2.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 55 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Esta invocacin se insertar en la cima de la pila (Figura 1.c). Esta vez, la direccin
de retorno es la A. Debido a esta nueva invocacin se tiene que volver a ejecutar el
programa Factorial. La condicin de la sentencia if an es FALSE, y por tanto se volver
a invocar a la parte ELSE, pero esta vez con 2-1 =1 como argumento. Se inserta en la
cima de la pila el registro de activacin de esta nueva invocacin (Figura 1.d). Una vez
ms se tiene que volver a ejecutar el procedimiento Factorial, en este caso el if tambin
es FALSE y al ejecutarse la parte else se volver a llamar a Factorial pero esta vez con
argumento 1-1=0 (Figura 1.e). En esta invocacin la condicin del if se evala a TRUE y
se devuelve un 1. Lo primero que se hace es almacenar este valor en el registro de la
funcin (RF), y usando la direccin de retorno del registro de activacin podremos volver
a la sentencia que hizo la llamada. En este instante, como se ha completado la ejecucin
del procedimiento Factorial(cuando N = 0), el computador no necesitar este ltimo
registro de activacin, as que se puede eliminar (Figura 1.f). La sentencia a la que
retornamos necesita el valor de la funcin Factorial(cuando N = 0), que se puede obtener
del registro de la funcin (RF). Este valor se multiplicar por el valor de N que es 1. El
resultado se copiar en el registro de la funcin y as concluir la ejecucin de
Factorial(cuando N = 1) , adems su registro de activacin ser borrado (Figura 1.g). Los
pasos anteriores se volvern a repetir dando lugar a un valor de 2 en el registro de la

ING JUAN ALBERTO VAZQUEZ G.


Pgina 56 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

funcin y a un solo registro de activacin en la pila (Figura 1.h). Esta vez, el valor
obtenido del registro de la funcin, que es 2, ser multiplicado por N, cuyo valor actual es
3; el resultado, 6, se copiar en el registro de la funcin, y se usar la direccin B, con lo
que retornaremos a la localizacin de la llamada original. Al final, la pila estar de nuevo
vaca (Figura 1.j).
Debido a la sobrecarga (overhead) que producen las operaciones sobre la pila, la
creacin y borrado de los registros de activacin, los procedimientos recursivos
consumen ms tiempo y memoria que los programas no recursivos. Pero, algunas veces,
debido a la estructura de datos usada en el problema o al planteamiento del mismo,
surge de forma natural, y evitar la recursin es bastante ms difcil que dar una solucin
recursiva al problema.
En conclusin el procedimiento de llamada a la
funcin recursiva es realmente una pila en la cual se
almacenan las llamadas que hace el programa o
algoritmos y conforme va terminando el programa va
retornando vaciando nuevamente la pila.
Actualmente los programas ya cuentan con una pila
especial para las llamadas a subrutinas en donde guarda
el registro de activacin.

ACTIVIDAD:

Construya un programa que utilizando recursin separe una lista de 100 nmeros en
pares e impares y comprelo con el trabajo de sus compaeros.

EVALUACION:

Qu es la recursin?
Qu diferencia existe entre la recursin directa e indirecta?
Qu diferencia existe entre programacin modular y la recursin?, donde se
separa una de la otra?
Por qu la memoria es ms empleada cuando se hace uso de la recursin?

ING JUAN ALBERTO VAZQUEZ G.


Pgina 57 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

Unidad

Arboles
4
4.1. Definicin.
4.2. Definicin de rbol binario.
4.3. Definicin de rbol binario de bsqueda.
4.4. Operaciones sobre rboles binarios de bsqueda.
4.4.1. Creacin.
4.4.2. Adicin de un nodo.
4.4.3. Bsqueda de un nodo.
4.4.4. Recorrido del rbol.
4.4.4.1. Preorden.
4.4.4.2. Inorden.
4.4.4.3. Postorden.
4.4.5. Implementacin.
4.5. Otros tipos de rbol.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 58 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

INTRODUCCION:

Hasta ahora las estructuras de datos que hemos estudiado eran de tipo lineal, o sea,
exista una relacin de anterior y siguiente entre los elementos que la componan (cada
elemento tendr uno anterior y otro posterior, salvo los casos de primero y ltimo).Pues
bien, aqu se va a estudiar una estructuracin de los datos ms compleja: los rboles.
Este tipo de estructura es usual incluso fuera del campo de la informtica. El lector
seguramente conoce casos como los rboles gramaticales para analizar oraciones, los
rboles genealgicos, representacin de jerarquas, etc. La estructuracin en rbol de los
elementos es fundamental dentro del campo de la informtica aplicndose en una amplia
variedad de problemas como veremos ms adelante.
Los arboles son muy utilizados en informtica para representar frmulas algebraicas
como un mtodo eficiente para bsquedas grandes y complejas, listas dinmicas y
aplicaciones diversas tales como inteligencia artificial o algoritmos de cifrado. Casi todos
los sistemas operativos almacenan sus archivos en rboles o estructuras similares a
rboles. Adems de las aplicaciones citadas, los rboles se utilizan en diseo de
compiladores, proceso de texto y algoritmos de bsqueda.

OBJETIVO:
Conoceremos las ventajas y desventajas de la recursin y haremos uso de ejemplos
en los cuales se hace uso de la ella.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 59 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

arboles

4.1. Definicin.
En ciencias de la informtica, 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 en
compuesta por un dato y varios rboles.
Estas son definiciones simples. Pero las caractersticas que implican no lo son tanto.
Un rbol es una estructura de datos ampliamente usada que emula la forma de un
rbol (un conjunto de nodos conectados). Un
nodo es la unidad sobre la que se construye
el rbol y puede tener cero o ms nodos hijos
conectados a l. Se dice que un nodo a es
padre de un nodo b si existe un enlace desde
a hasta b (en ese caso, tambin decimos que
b es hijo de a). Slo puede haber un nico
nodo sin padres, que llamaremos raz. Un
nodo que no tiene hijos se conoce como nodo
hoja. Los dems nodos (tienen padre y uno o
varios hijos) se les conoce como rama.
rama
Definiremos varios conceptos. En relacin con otros nodos:
Nodo hijo:
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:
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:
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:
hoja nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L', 'M', 'N'
y 'O'.
Nodo rama:
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.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 60 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

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:
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:
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:
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:
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, etc.

4.2. Definicin de rbol binario.


Un rbol binario esta caracterizado por ser de grado 2, y como hemos dicho
anteriormente todo nodo del rbol tiene un subrbol binario izquierdo y derecho
asociados.
rbol Binario Completo o Lleno:
Lleno Es un rbol binario en el que todos sus nodos,
excepto las hojas, tienen siempre dos hijos (el subrbol izquierdo y el derecho) no nulos.
El nmero de nodos de un rbol completo se calcula por la frmula: Nmero de nodos =
2h-1 (donde h es la altura)
rbol
rbol Binario Completo de Altura o Profundidad H:
H Es un rbol Binario Completo en
donde todas las hojas estn en el nivel H. Esta es una de las pocas estructuras de rbol
que se pueden representar eficientemente usando arreglos.
Hay dos formas tradicionales de representar un rbol binario en memoria:
Por medio de datos tipo punteros tambin conocidos como variables dinmicas o
listas. Esta es la forma ms utilizada, puesto que es la ms natural para tratar este tipo
de estructuras.
Por medio de arreglos, en este caso los nodos del rbol binario sern representados
como registros que contendrn como mnimo tres campos. En un campo se almacenar
la informacin del nodo. Los dos restantes se utilizarn para apuntar al subrbol
izquierdo y derecho del subrbol en cuestin.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 61 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

4.3. Definicin de rbol binario de bsqueda.


Un rbol de bsqueda binaria es una estructura apropiada para muchas de las
aplicaciones que se han discutido anteriormente con listas. La ventaja especial de utilizar
un rbol es que se facilita la
a bsqueda.
Un rbol binario de bsqueda es aquel en el que el hijo de la izquierda (si existe) de
cualquier nodo contiene un valor ms pequeo que el nodo padre, y el hijo de la derecha
(si existe) contiene un valor ms grande que el nodo padre.
Un ejemplolo de rbol binario de bsqueda es el siguiente:

Un rbol AVL es un rbol binario de bsqueda que cumple con la condicin de que la
diferencia entre las alturas de los subrboles de cada uno de sus nodos es, como mucho
1.
La denominacin de rbol AVL viene dada por los creadores de tal estructura
(Adelson-Velskii y Landis).
Un rbol binario de bsqueda es un rbol binario en el cual cada nodo cumple con
que todos los nodos de su subrbol izquierdo son menores que la raz y todos los nodos
del subrbol
rbol derecho son mayores que la raz.

4.4. Operaciones sobre rboles binarios de bsqueda.


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.
a. 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.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 62 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

4.4.1. Creacin.
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];
};
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;

4.4.2. Adicin de un nodo.


Al insertar elementos en un rbol ser necesario tener en cuenta lo siguiente.
En el rbol binario cada nodo puede tener hasta dos hijos cada uno con un valor de
clave. El valor de clave del subrbol izquierdo es menor o igual que los valores del rbol
derecho.
El procedimiento para insercin en un rbol de bsqueda queda resumido como
sigue:
 Debebe compararse la clave a insertar con la raz del rbol. Si es mayor, debe
avanzarse hacia el subrbol derecho. Si es menor, debe avanzarse haca el
subrbol izquierdo.
 Repetir sucesivamente el paso 1 hasta que se cumpla alguna de las siguientes
condiciones:
 El subrbol derecho es igual a vaco, o el subrbol izquierdo es igual a
vaco, en cuyo caso se procede a insertar el
elemento en el lugar que le corresponde.
 La clave que quiere insertarse es igual a la
raz del rbol, en cuyo caso no se realiza la
insercin.
Procurando tener a la izquierda de mi raz los elementos
de menor valor lo mismo suceder para el caso de lo nodos,
puede verlo en la figura.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 63 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

Ahora voy a intentar explicar en sencillos pasos el mtodo de borrado de nodos en


rboles binarios.
1. Buscoco el nodo a borrar.
2. Si el nodo es hoja basta con que su padre haga referencia a nodo vaco.
3. Si no es nodo hoja habr que sustituirlo por otro bajo las siguientes condiciones:
a. El nodo a borrar solo tiene un hijo y se sustituye por su hijo.
b. El nodo a borrar tiene dos hijos sustituirlo por:
i. El mayor de su subrbol izquierdo.
ii. El menor de su subrbol derecho.
4. Si el nodo a borrar es raz hay que eliminarlo segn el caso que corresponda de
acuerdo con el paso 3..
EJEMPLO: Borrar 8 en el rbol que se muestra en la primera figura.

En este caso se hace cualquiera de las dos opciones del punto 3b. Ya sea sustituir el
rbol izquierdo por su mayor. (Sustituyo 6 por 8) este caso se muestra en la segunda
figura Sustituir el rbol derecho (Sustituyo 12 x 8) y se muestra en la tercera figura.
figura

4.4.3. Bsqueda de un nodo.

Debido al orden intrnseco de un rbol de bsqueda


squeda binaria, es fcil implementar una
funcin
n que busque un determi
determinado valor entre los nodos del rbol y, en caso de
encontrarlo, proporcione un puntero a ese nodo. La ve versin recursiva de la funcin es
particularmente sencilla, todo
odo consiste en partir de la ra
raz y rastrear el rbol en busca del
nodo en cuestin, segn el siguiente diseo:
Si rbol es vacio entonces
Devolver
evolver fallo
En otro caso si rbol rbol-contenido
contenido = dato entonces
Devolver el puntero a la raz de rbol
En otro caso si rbol rbol-contenido
contenido > dato entonces
Buscar en el hijo izquierdo de rbol
En otro caso si rbol rbol-contenido
contenido < dato entonces
Buscar en el hijo dere derecho de rbol

ING JUAN ALBERTO VAZQUEZ G.


Pgina 64 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

4.4.4. Recorrido del rbol.


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 si
siempre
empre 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
RecorrerArbol,, aplicando recursividad, ser tan sencilla como invocar de
nuevo a la funcin RecorrerArbol para cada una de las ramas:
void RecorrerArbol(Arbol a)
{
if(a == NULL) return;
RecorrerArbol(a
RecorrerArbol(a->rama[0]);
RecorrerArbol(a
RecorrerArbol(a->rama[1]);
RecorrerArbol(a
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.

4.4.4.1. Pre-orde
orden.
En este tipo de recorrido,
rrido, el valor del nodo se procesa antes de recorrer las ramas:
void PreOrden(Arbol a)
{
if(a == NULL) return;
Procesar(dato);
RecorrerArbol(a
RecorrerArbol(a->rama[0]);
RecorrerArbol(a
RecorrerArbol(a->rama[1]);
RecorrerArbol(a
RecorrerArbol(a->rama[2]);
}
En conclusin la forma de hacer el recorrido Preorden es la siguiente:
Visita la raz
Subrbol izquierdo
Subrbol derecho
El rbol de la figura se recorrer en el siguiente orden: 34,
34, 10, 25, 56, 46, 82

4.4.4.2. In-orden
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,

ING JUAN ALBERTO VAZQUEZ G.


Pgina 65 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre
Cuatri

y tambin cuando existen ORDEN


ORDEN-1 1 datos, en cuyo caso procesaremos cada dato entre
en
el recorrido de cada dos ramas (este es el caso de los rboles
rboles-b):
void InOrden(Arbol a) {
if(a == NULL) return;
RecorrerArbol(a
RecorrerArbol(a->rama[0]);
Procesar(dato);
RecorrerArbol(a
RecorrerArbol(a->rama[1]);
RecorrerArbol(a
RecorrerArbol(a->rama[2]);
}
En conclusin la forma de hacer el recorrido Inorden es la siguiente:
Subrbol izquierdo
Visita la raz
Subrbol derecho
El rbol de la figura que se muestra en la seccin 4.4.4.1 se recorrer en el siguiente
orden: 10, 25, 34, 46, 56, 82

4.4.4.3. Postorden
Postorden.
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
RecorrerArbol(a->rama[0]);
RecorrerArbol(a
RecorrerArbol(a->rama[1]);
RecorrerArbol(a
RecorrerArbol(a->rama[2]);
Procesar(dato);
}
En conclusin la forma de hacer el recorrido Postorden es la siguiente:
Subrbol izquierdo
Subrbol derecho
Visita la raz
El rbol de la figura que se muestra en la seccin 4.4.4.1 se recorrer en el siguiente
orden: 10, 25, 34, 46, 56, 82

4.4.5. Implementacin.

En el programa que se muestra a continuacin se ha implementado un rbol


utilizando cada uno de los conceptos vistos anteriormente, no le ser difcil entender el
programa, no se ha hecho uso de cosas que usted no conozca, se ha considerado
considerad un
rbol de 200 elementos, pero usted ser quien finalmente decida cuantos elementos
quiere agregarle a su rbol.

/*PROGRAMA
PROGRAMA QUE CAPTURA UNA CADENA DE CARACTERES DE MAXIMO 200 ELEMENTOS Y CREA UN ARBOL
DE BUSQUEDA CON LOS CARACTERES DE LA CADENA Y REALIZA RECORRIDOS EN PREORDEN,ENTREORDEN
Y POSTORDEN.*/

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

ING JUAN ALBERTO VAZQUEZ G.


Pgina 66 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
struct nodoarbol
{ //ESTRUCTURA DEL ARBOL
struct nodoarbol *izqnodo;
int info;
struct nodoarbol *dernodo;
}; typedef struct nodoarbol NODO; //DEFINICION DE TIPO NODO
typedef NODO *ARBOL; //DECLARACION DE VARIABLE PUNTERO A NODO
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
void insertanodonuevo(ARBOL *,int); //DECLARACION DE FUNCIONES
void inorden(ARBOL);
void preorden(ARBOL);
void postorden(ARBOL);
void treefree(ARBOL);

/*-----------------------<FUNCION PRINCIPAL>---------------*/

main()
{
int i; //CONTADOR
char newnod, chain[200],elementos;
//DECLARACION DE CADENA, BANDERA Y VARIABLE QUE CONTIENE EL NUEVO
//VALOR A INSERTAR EN EL ARBOL
clrscr();
ARBOL raiz=NULL; //DECLARACION DE VARIABLE DE TIPO ARBOL
printf("\n\n\tIntroduzca una cadena de caracteres (max. 200 elementos):\n");
gets(chain);
elementos=strlen(chain);
//CHECA EL TAMAO DE LA CADENA Y ESTABLECE EL NUMERO DE NODOS DEL ARBOL
for(i=1;i<=elementos;i++)
{
newnod=chain[i-1];
insertanodonuevo(&raiz,newnod);
}
printf("\n\n preorden \t");
preorden(raiz); //LLAMADO A FUNCION DE RECORRIDO EN PREORDEN
printf("\n\n inorden \t");
inorden(raiz); //LLAMADO A FUNCION DE RECORRIDO EN INORDEN
printf("\n\n postorden \t");
postorden(raiz); //LLAMADO A FUNCION DE RECORRIDO EN POSTORDEN
getch();
treefree(raiz); //LIBERACION DE MEMORIA DEL ARBOL.
raiz=NULL; //ASIGNACION DE UN VALOR NULO A LA RAIZ.
return 0;
}

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/*-CREA UN NUEVO NODO Y COLOCA LOS VALORES DEL NUEVO ELEMENTO EN LA POSICION
CORRESPONDIENTE */
void insertanodonuevo(ARBOL *rarbol,int nuevo)
{
if(*rarbol==NULL)
{ //CREACION DE UN NUEVO NODO
*rarbol=(NODO *)malloc(sizeof(NODO));
if(*rarbol!=NULL)
{ //ASIGNACION DE VALORES NUEVOS EN EL NODO NUEVO
(*rarbol)->info=nuevo;
(*rarbol)->izqnodo =NULL;
(*rarbol)->dernodo=NULL;
}
else
{

ING JUAN ALBERTO VAZQUEZ G.


Pgina 67 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

printf("\n Memoria No Disponible !!!!\n");


}
}
else
if(nuevo<(*rarbol)->info)
//checa si el elemento nuevo es mayor que el elemento padre
insertanodonuevo(&((*rarbol)->izqnodo)
//coloca el elemento a la izquierda del padre o raz
else
if(nuevo>(*rarbol)->info)
//checa si el elemento nuevo es menor que el elemento padre
insertanodonuevo(&((*rarbol)->dernodo)
//coloca el elemento a la derecha del padre o raz
}

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/*FUNCION ITERATIVA LA CUAL RECORRE EL ARBOL IMPRIMIENDO SIEMPRE EL VALOR QUE CONTIENE
LA RAIZ,DESPUES LA RAMA IZQUIERDA,LUEGO LA RAMA DERECHA,SIEMPRE Y CUANDO LA RAIZ SEA
DIFERENTE DE UN VALOR NULO, SI ES NULO SALTA A LA SIGUIENTE INSTRUCCION.*/
void preorden(ARBOL rarbol)
{
if(rarbol!=NULL)
{
printf(" %c ",rarbol->info);
preorden(rarbol->izqnodo);
preorden(rarbol->dernodo);
}
}

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/*FUNCION ITERATIVA LA CUAL RECORRE EL ARBOL BUSCANDO EL NODO ms IZQUIERDO QUE CONTIENE
EL ARBOL O SEA HASTA QUE LA RAMA DEL ULTIMO NODO SEA NULO, LUEGO LA IMPRIME,DESPUES LA
RAIZ DEL SUB-ARBOL,Y LUEGO EL NODO DE LA DERECHA.*/
void inorden(ARBOL rarbol)
{
if(rarbol!=NULL)
{
inorden(rarbol->izqnodo);
printf(" %c ",rarbol->info);
inorden(rarbol->dernodo);
}
}

/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/*FUNCION ITERATIVA LA CUAL RECORRE EL ARBOL BUSCANDO EL NODO QUE ESTA ms A LA
IZQUIERDA, LUEGO EL NODO DE LA DERECHA Y LUEGO LA RAIZ DE ESE SUB-ARBOL*/
void postorden(ARBOL rarbol)
{
if(rarbol!=NULL)
{
postorden(rarbol->izqnodo);
postorden(rarbol->dernodo);
printf(" %c ",rarbol->info);
}
}

/**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
/*FUNCION ITERATIVA IDENTICA AL RECORRIDO EN POSTORDEN LA UNICA DIFERENCIA ES QUE EN VEZ
DE IMPRIMIR EN PANTALLA EL VALOR DE UN NODO ESTE ES ELIMINADO DEL ARBOL LIBERANDO LA
MEMORIA CON LA FUNCION free(), ELEGI ESTA FORMA YA QUE SE ELIMINA PRIMERO LOS NODOS HIJO
DE EL SUB-ARBOL Y LUEGO LA RAIZ YA QUE SI SE ELIMINA LA RAIZ PRIMERO, LOS DATOS DE LOS
HIJOS SE DESCONECTAN DEL ARBOL PERO LA MEMORIA QUE OCUPABAN SIGUE SIENDO UTILIZADA Y DE
ESTA FORMA SE ELIMINA EL ARBOL DE ABAJO HACIA ARRIBA (O SEA DE LOS HIJOS A LA RAIZ).*/

ING JUAN ALBERTO VAZQUEZ G.


Pgina 68 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

void treefree(ARBOL rarbol)


{
if(rarbol!=NULL)
{
treefree(rarbol->izqnodo);
treefree(rarbol->dernodo);
free(rarbol);
}
}

4.5. Otros tipos de rbol.


Hemos hecho uso de los arboles binarios pero debemos aclarar que existen cuatro
tipos de rbol binario:.
 Arbol Binario Distinto.
 Arbol Binario Similares.
 Arbol Binario Equivalentes.
 Arbol Binario Completos.
A continuacin se har una breve descripcin de los diferentes tipos de rbol binario
as como un ejemplo de cada uno de ellos.
 Arbol Binario Distinto
Se dice que dos rboles binarios son distintos cuando sus estructuras son diferentes.
Ejemplo:
 Arbol Binario Similar
Dos arboles binarios son similares cuando sus estructuras son idnticas, pero la
informacin que contienen sus nodos es diferente.
Ejemplo:
 Arbol Binario Equivalente
Son aquellos arboles que son similares y que adems los nodos contienen la misma
informacin. Ejemplo:
 Arbol Binario Completo
Completo
Son aquellos arboles en los que todos sus nodos excepto los del ultimo nivel, tiene
dos hijos; el subrbol izquierdo y el subrbol derecho.

Hemos visto hasta ahora a los arboles binarios, caracterizados por contar con dos
aristas una para el nodo derecho y otra para el nodo izquierdo, sin embargo no son los
nicos arboles que existen y por lo mismo utilizaremos esta seccin para mostrar ms
arboles y poder distinguirlos de acuerdo a su fisonoma.
ARBOLES N- N-ARIOS:
Este tipo de rbol se diferencia del binario porque
puede contener una gran cantidad de aristas, es
difcil su manipulacin ya que debido a esto su
estructura es muy compleja. Es poco til en el
almacenamiento y manejo de la informacin.
En la figura se muestra un rbol N-ario.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 69 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

ARBOLES ETIQUETADOS:
ETIQUETADOS:
Cuando en un rbol las aristas tienen
asignadas unas etiquetas se dice que es
un rbol etiquetado, un nodo no podr
tener una etiqueta, ya que su etiqueta es
el valor almacenado en el.
En la figura se muestra un rbol
etiquetado, en este rbol el nodo 2
contiene el signo + y sus hijos los estn
etiquetados con los valores a y
respectivamente. Por lo tanto n2
representa a+b.

ACTIVIDAD:

Disee arboles en los cuales tenga que insertar y eliminar las claves del rbol, y
cuando este seguro que ya lo esta haciendo bien realice entonces la evaluacin.

EVALUACION:

Ordene un rbol binario que cuenta con las siguientes claves 11, 5, 8, 14, 20, 12, 26,
2, 9, 1, 0 y posteriormente.
a) Ordene en Posorden.
b) Ordene en Inorden.
c) Ordene en Preorden.
d) Disee el rbol luego de eliminar la clave 20.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 70 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

GLOSARIO DE TERMINOS:

ARBOL GENEALOGICO: Es una representacin grfica que expone los datos


genealgicos de un individuo en una forma organizada y sistemtica, sea en forma de
rbol o tabla.
ARBOL GRAMATICAL: Un rbol gramatical en G es un rbol ordenado tal que los
vrtices de estn etiquetados con etiquetas en el alfabeto de la gramtica o con la
etiqueta vaca,
ARGUMENTO: Variable que puede ser recibida por una rutina. Una subrutina usa los
valores asignados a sus argumentos para alterar su comportamiento en tiempo de
ejecucin.
AUTORREFERENCIABLE: Que hace referencia a el mismo.
BOOLEANO: Gnero definido en una funcin parcial de tipo predefinida y tiene lo
valores verdadero y falso.
CIFRADO: Transformacin de un mensaje en otro, utilizando una clave para impedir
que el mensaje transformado pueda ser interpretado por aquellos que no conocen
la clave.
COMPACIDAD: En lgica matemtica, el teorema de compacidad establece que un
conjunto (posiblemente infinito) de sentencias de primer orden tiene un modelo, si
todos sus subconjuntos finitos tienen un modelo.
COMPILADOR: Programa informtico que traduce un programa escrito en un
lenguaje de programacin a otro lenguaje de programacin.
FACTORIAL: producto de una serie de nmeros enteros positivos que desciende de
un nmero dado, n, hasta 1.
FLEXIBLE: Se define la flexibilidad como la capacidad para adaptarse a diferentes
circunstancias.
INCLUSIVO: Se denomina as un tipo especial de nmero plural, que afecta a la
primera persona. Un ejemplo es considerar el nosotros como la suma del yo +
ustedes.
INTRISECO: Inherente, propio o esencial de una cosa. Inseparable de la cosa en s.
ITERACION: Se refiere a la accin de repetir una serie de pasos un cierto nmero de
veces.
JERARQUIZADO: La jerarqua es el orden de los elementos de una serie segn su
valor, Jerarqua hace referencia a jerarquizado.
LINKER: Es un programa que toma los ficheros de cdigo objeto generado en los
primeros pasos del proceso de compilacin, la informacin de todos los recursos
necesarios (biblioteca), quita aquellos recursos que no necesita, y enlaza el
cdigo objeto con su(s)biblioteca con lo que finalmente produce un fichero
ejecutable o una biblioteca.. En el caso de los programas enlazados
dinmicamente, el enlace entre el programa ejecutable y las bibliotecas se realiza
en tiempo de carga o ejecucin del programa.
LONG INT: Entero largo.
NULL: Termino utilizado para hacer referencia a la nada, o sin contenido.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 71 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

OBJETO: Es la unidad individual que en tiempo de ejecucin realiza las tareas de un


programa. Tambin podemos definirlo como un Componente o cdigo de
software, el cual contiene en s mismo tanto sus caractersticas (campos) como
sus comportamientos (mtodos), el cual se accede a travs de su interfaz o
signatura.
OPENGL: Especificacin estndar que define una Interfaz de Programacin de
Aplicaciones multilenguaje y multiplataforma para escribir aplicaciones que
produzcan grficos 2D y 3D.
PARMETRO: Informacin que determina el funcionamiento de un programa.
PROCEDIMIENTO: Trmino para describir una secuencia de rdenes que hacen una
tarea especfica de una aplicacin ms grande.
SIMIL: Comparacin explicita de una cosa con otra para dar una idea ms viva de una
de ellas.
SINTAXIS: Reglas que indican cmo debe teclear un comando o instruccin de
manera que el equipo lo reconozca.
SUBRUTINA: Conjunto de instrucciones que efectan una tarea especfica dentro de
un programa y al que es posible referirse.
TRIVIAL: Se refiere a soluciones que tienen una estructura muy simple, pero que por
completitud no pueden ser ignoradas.
VARIABLE: Son estructuras de datos que, como su nombre indica, pueden cambiar de
contenido a lo largo de la ejecucin de un programa.

ING JUAN ALBERTO VAZQUEZ G.


Pgina 72 de 73
CESVER Material Bibliogrfico de Apoyo Didctico
ING. SISTEMAS COMPUTACIONALES Alg. y Estruct. de Datos II 6 Cuatrimestre

BIBLIOGRAFA:

 Desarrollo de Algoritmos y Tcnicas de Programacin en Pascal.


Pareja- Ojeda y otros
ED. Rama.
 Estructuras de datos Especificacin, diseo e implementacin
Xavier Franch Gutirrez
Edicin UPC 1993.
 Estructura Dinmicas de Datos
Salvador Pozo Coronado
Edicin Digital.
 Notas para los cursos de Computacin y Programacin con el lenguaje Pascal.
Nestor Aguilera 2004
Facultad de Ing. Qumica
Universidad de Litoral
Departamento de matemticas.

REFERENCIAS:
 http://www.conclase.net/
 http://www.home.itchihuahua.edu.mx/~jrobles/docs/c/C_curso.doc
 http://studies.ac.upc.edu/EPSC/TCP/documentos/MemoriaDinamica.doc
 http://delfosis.uam.mx/~irma/www2/ALGORITMOS/NOTAS.doc
 www.lcc.uma.es/~afdez/apuntes/laboratorio/apuntes/apuntesrecursividad.pdf


www.cesver.edu.mx
Tel. 01-228-8182038 01-228-8182039
Serafn Olarte 43 Col. Mrtires de Chicago. Xalapa ver

ING JUAN ALBERTO VAZQUEZ G.


Pgina 73 de 73