Documente Academic
Documente Profesional
Documente Cultură
POPAYAN
Enero de 2012
INDICE DE CONTENIDO
LISTADO DE TABLAS
Tabla 1.30
Tabla 2.31
La versin uno del presente mdulo fue diseado en el ao 2004 por el Ing.
Ivn Arturo Lpez, docente de la UNAD, ubicado en el CEAD de Popayn, el Ing.
Lpez es Ingeniero de Sistemas, Especialista en Pedagoga Para el Desarrollo del
Aprendizaje Autnomo y Magister en Educacin y TICs, se ha desempeado
como Tutor y Docente de la UNAD desde el ao 2000.
La versin dos del presente mdulo fue desarrollada por el Ing. Hermes
Mosquera Angulo en el ao 2007, quien ha sido Tutor de la UNAD en el CEAD
Popayn, desde el ao 2006, se desempea actualmente como Director del cuso
a nivel nacional desde el ao 2007.
INTRODUCCIN
UNIDAD 1
Nombre de la Unidad
Introduccin
MEMORIA DINMICA
La memoria del computador es un recurso invaluable de
mucha importancia en el procesamiento de informacin,
que requiere darle un buen uso por parte de los
programadores con el fin de optimizar espacios en
memoria. Por esta razn, en esta, la primera unidad del
curso, se hace una introduccin a conceptos bsicos
como apuntadores, asignacin dinmica de memoria y
operadores como new y delete propios de C++ y
funciones como Malloc() y free(), propios de C.
Igualmente estn implcitas diferentes estrategias de
pensamiento de orden superior que el estudiante ir
descubriendo gracias al apoyo permanente del tutor,
quien en es el mediador del proceso de aprendizaje.
En el transcurso de la unidad, se desarrollan actividades
que buscan determinar el grado de apropiacin del
conocimiento, basados en los tres momentos:
reconocimiento, profundizacin y transferencia, sin dejar
al lado el desarrollo del componente prctico que tiene
como finalidad afianzar los conocimientos en pro de lograr
la competencia del curso.
Justificacin
Intencionalidades
Formativas
Captulo 1
Leccin 1
Leccin 2
Leccin 3
Leccin 4
Leccin 5
Captulo 2
Leccin 6
Leccin 7
Leccin 8
Leccin 9
Leccin 10
Captulo 3
Leccin 11
Leccin 12
Leccin 13
Leccin 14
Leccin 15
14
CAPITULO 1: APUNTADORES
Introduccin
En el presente capitulo se aborda la temtica de los apuntadores y la aplicabilidad
que tienen en el campo de la programacin estructurada. Los apuntadores son un
tipo especial de variables que guardan direcciones de otras variables. en los
lenguajes de programacin de C y C++. Proporcionan mucha utilidad al
programador ya que permiten accesar y manipular datos de tal manera que no es
posible realizarse en otros lenguajes llamados de alto nivel.
Tambien son utiles para pasarle parametros a las funciones de tal modo que les
permiten modificar y regresar valores a la rutina o funcin que hace el llamado.
Cuando se utilizan incorrectamente, pueden producir algunos problemas de
esrtabilidad en el sistema o tambin pueden presentar fallas en el programa en
ejecucin.
De igualmanera se llevarn a cabo aplicaciones pequeas de programas
codificados en C++ como aplicacin al uso de los apuntadores y a las operaciones
que se pueden llevar a cabo. Cada uno de estos programas presenta en una
figura la salida en pantalla, es decir todos estn previamente compilados y
depurados.
Leccin 1: Conceptos bsicos de apuntadores
Antes de definir qu es un puntero, veremos primero cmo se almacenan los
datos en un computador. La memoria de un computador est compuesta por
unidades bsicas llamadas bits. Cada bit slo puede tomar dos valores,
normalmente denominados alto y bajo, 1 y 0. Pero trabajar con bits no es
prctico, por eso se agrupan. Cada grupo de 8 bits forma un byte u octeto. En
realidad el microprocesador, y por lo tanto nuestro programa, slo puede manejar
directamente bytes o grupos de dos o cuatro bytes. Para acceder a los bits hay
que acceder antes a los bytes. Cada byte tiene una direccin, llamada
normalmente direccin de memoria.
Definicin de Apuntadores
Un apuntador es una variable, que almacena como contenido una direccin de
memoria, de otra variable a la que apunta, dicha direccin representa el lugar
donde se almacena un dato. Los apuntadores tienen un tipo de dato especfico y
solo pueden apuntar a espacios de memoria con datos del mismo tipo. Por
supuesto, a partir de esa direccin de memoria puede haber cualquier tipo de
15
objeto: un char, un int, un float, un array, una estructura, una funcin u otro
puntero. Sern los programadores los responsables de decidir ese contenido.
Con los apuntadores es posible manipular estructuras de datos o asignar
memoria dinmica. Los apuntadores son una de las herramientas ms poderosas
con que cuenta el Lenguaje C++. Desafortunadamente, muchos programadores
han creado el mito de que el estudio de los apuntadores es muy complicado, lo
cual ha desarrollado una fobia entre quienes se inician en el estudio de las
estructuras dinmicas en lenguaje C++.
Declaracin de apuntadores
Los apuntadores son variables automticas cuyos valores representan direcciones
de memoria correspondientes a otras variables del mismo tipo a las que apunta.
La sintaxis para la declaracin de una variable de tipo apuntador es la siguiente:
tipo * identificador ; Donde, tipo hace referencia al tipo de datos de C++ como
int, char, float, entre otros e identificador, hace referencia al nombre de la
variable apuntador.
Ejemplo: int *apunt; se declara el apuntador apunt de tipo entero. Se dice que:
"apunt va a apuntar a variables de tipo int" donde apunt es el nombre del
apuntador y (*) es el operador de indireccin que indica que apunt es un
apuntador.
En el ejemplo anterior, puede decirse que:
*apunt se refiere al objeto apuntado por apunt.
apunt es un apuntador a objetos de tipo int
Observe que el operador de indireccin utiliza el mismo smbolo que el operador
de multiplicacin. En este caso el asterisco le indica al sistema que se define una
variable apuntador.
Ejemplos:
int *x;
char *y;
double *r, *s;
16
17
Ms acerca de apuntadores
Un apuntador es una variable que solo puede contener un valor a la vez, por lo
que solo puede apuntar a un objeto al mismo tiempo.
Por otro lado, una variable cualquiera puede ser apuntada (referenciada) por
varios apuntadores, ya que su direccin de memoria puede ser almacenada en
distintas variables a la vez.
19
20
Arreglos de apuntadores
Los apuntadores pueden manejarse en un arreglo, de tal forma que:
char nombres[ ][5] = { "HUGO", "PACO", "LUIS" } ; es la declaracin de un arreglo
de cadenas, con asignacin de valores iniciales. Su equivalente en notacin de
apuntadores es:
char *nombres[ ] = { "HUGO", "PACO", "LUIS" } ;
En el que se declara un arreglo de apuntadores con tres valores asignados. El
programa completo para el manejo de este ejemplo se presenta en el Progra5.cpp.
Implementacin de arreglos de apuntadores
Progra5.cpp
#include <iostream.h>
#include <conio.h>
#include <string.h>
void main()
{
char *nombres[ ] = { "HUGO", "PACO", "LUIS" } ;
22
char invitado[11];
int bandera;
clrscr();
gotoxy(20,5);
cout << "CUAL ES SU NOMBRE ?: " ;
gotoxy(50,10);
cin>> invitado ;
gotoxy(20,7);
for( int x = 0 ; x <3 ; x++ )
if(strcmp(invitado, nombres[x])== 0)
bandera=0;
if(bandera== 0)
cout << "!! SIGA AMIGO ES BIENVENIDO " << invitado << " !!";
else cout << "!! USTED NO ES BIENVENIDO, " << invitado << " !!";
getch();
}
En la figura 5, se visualiza el resultado de la salida en pantalla de Progra5.cpp, en
el que se incluye la librera <string.h> necesaria para el manejo de cadena de
caracteres con las funciones de comparar cadena (strcmp); la cual compara el
nombre solicitado por teclado con los nombres asignados al arreglo previamente,
en caso de que coincida muestra el primer mensaje de bienvenida, de lo contrario
muestra el segundo mensaje.
24
Explicando la expresin que puede ser un tanto desconocida del listado anterior, la
expresin:
int(*cmpcad)(char*, char*).
Establece que cmpcad es un apuntador a una funcin, la cual devuelve un valor
de tipo entero.
27
q = &a;
p = q;
cout<<p;
29
Anlisis de Progra10.cpp
Tal como se observa en la imagen es la salida en pantalla del programa en el que
se aprecia la diferencia entre el valor de la variable a que devuelve un valor
numrico igual a 7; mientras que la variable ap devuelve la direccin de memoria
de a.
Figura 10 Salida en pantalla de progra10.cpp
30
BYTES REQUERIDOS
La letra X
El nmero 100
El nmero 125.12
La frase Aprenda usted mismo
Una pgina escrita completamente
1
2
4
21
3000 (Aproximadamente)
ESPACIO
MEMORIA
RANGO PERMITIDO
32
unsigned char
Char
short int
unsigned int
Int
unsigned long
Enum
Long
Float
Doubl
long doubl
Void
8 bits
8 bits
16 bits
32 bits
32 bits
32 bits
16 bits
32 bits
32 bits
64 bits
80 bits
sin valor
0 a 255
-128 a 127
-32,768 a 32,767
0 a 4,294,967,295
-2,147,483,648 a 2,147,483,647
0 a 4,294,967,295
-2,147,483,648 a 2,147,483,647
-2,147,483,648 a 2,147,483,647
3.4 x 10-38 a 3.4 x 10+38(6 dec)
1.7 x 10-308 a 1.7*10+308(15 dec)
3.4 x 10-4932 a 1.1 x 10+4932
Fuente: http://www.wikilearning.com/tutorial/tutorial_de_c++-tipos_de_datos/9773-4
33
34
36
b = &a ;
// 4
**b += *a ;
// 5
c = &b ;
// 6
***c += **b + *a ;
// 7
cout << " *a=" << *a << " \n" ;
cout << " **b=" << **b << " \n" ;
cout << "***c=" << ***c << " \n" ;
getch();
}
Anlisis de Progra13.cpp
En el listado del progra13.cpp se declaran tres variables de tipo apuntador que
apuntan a datos de tipo entero, ellas son, *a, **b y **c. El apuntador a almacena la
direccin de la variable x, luego a al apuntador a se le asigna el valor de 100, lo
que indica que x vale 100, mientras que **b precedida de dos asteriscos indica
que es una variable que apunta a un apuntador, para este caso b guarda la
direccin de el puntero a, y ***c es un apuntador a apuntador a apuntador, lo cual
puede simplificarse en que c guarda la direccin de b. El resultado del listado
Progra13.cpp se puede visualizar en la Figura 13.
Figura 13Salida en pantalla de progra13.cpp
memoria que no se usa por ningn programa es lo que se conoce como "heap" o
montn.
Cuando el programador use memoria dinmica, normalmente usar memoria del
montn, y no se llama as porque sea de peor calidad, sino porque suele haber
realmente un montn de memoria de este tipo disponible para ser usado en la
medida que se requiera.
Profundizando un poco en la asignacin dinmica, se encuentra el operador
sizeof, el cual determina el tamao en bytes que se requiere en la asignacin
dinmica de memoria, ya sea por medio de los operadores New y Delete, o por las
funciones Malloc y Free, de un arreglo o de cualquier otro tipo de datos,
Ejemplo utilizar el operador sizeof en una funcin con el propsito de determinar el
tamao en bytes de un parmetro.
Aplicacin del operador sizeof.
En el siguiente listado se evidencia la aplicacin y uso del operador sizeof en cada
variable el cual devuelve el nmero de bytes dependiendo del tipo de variable.
Implementacin del uso de sizeof
Progra14.cpp
#include <iostream.h>
#include <conio.h>
void main()
{
char P;
short R;
int I;
long L;
float F;
double D;
long double LD;
clrscr();
gotoxy(1,2);
cout<<"valores utilizando sizeof para cada una de la varibles \n\n";
cout<<" variable P = " <<sizeof P;
cout<<"\t tipo char = " <<sizeof (char);
cout<<"\n variable R = " <<sizeof R;
cout<<"\t tipo short = " <<sizeof (short);
cout<<"\n variable I = " <<sizeof I;
cout<<"\t tipo int = " <<sizeof (int);
cout<<"\n variable L = " <<sizeof L;
cout<<"\t tipo int = " <<sizeof (long);
38
Anlisis de Progra14.cpp
En la siguiente grfica se visualiza el resultado del progra13.cpp en laque se
puede apreciar el resultado almacenado en la variable y los bytes requeridos para
cada tipo de dato.
Figura 14 Salida en pantalla de progra14.cpp
39
Introduccin
En el presente captulo se trata la temtica relacionada con los operadores y las
funciones utilizadas para la gestin de memoria, en ese sentido se realizan
programas como aplicacin a los operadores new y delete propios de C++, al igual
que las funciones malloc(), free() y calloc() y realloc() propias de C.
Al igual que en cada uno de los captulos, se presentan programas de aplicacin
que dan respuesta a al temtica planteada, estos programas estn previamente
compilados y depurados para garantizar que el estudiante pueda editarlos
analizalos y plantear mejoras que contribuyan a su formacin y al adquisicin de la
competencia del curso desarrollada en cada uno de sus captulos.
Leccin 11: Operadores New y Delete
El lenguaje C++ cuenta con dos operadores preconstruidos, ellos son: New y
Delete, por esta razn no se requiere incluir ninguna librera o archivo de
cabecera para utilizarlos.
El operador New:
Realiza una labor parecida a la de la funcin malloc(),
asignando un bloque de memoria segn sea requerido.
El operador Delete: Libera un bloque de memoria asignada por New en tiempo
de ejecucin, de manera semejante a como lo hace la funcin free().
La sintaxis para el uso del operador new es:
Apuntador = new tipo_de_dato;
Este operador hace una peticin al sistema operativo para que se le asigne un
espacio en memoria, con el tamao acorde al tipo de datos (vale la pena recordar
la funcin sizeof), si este espacio est disponible, la operacin regresa la direccin
real que se otorga, en caso de no haber espacio regresa el valor de NULL (0),
La sintaxis para el uso del operador delete es:
delete apuntador;
40
La ejecucin de este operador provoca que se libere espacio, dejando como valor
indefinido, es decir el sistema operativo lo considera como memoria disponible.
Hay una regla de oro utilizada por algunos autores, se refiere a que cuando se usa
memoria dinmica, toda la memoria que se reserve durante el programa hay que
liberarla antes de salir del programa. No seguir esta regla es una actitud muy
irresponsable, y en la mayor parte de los casos tiene consecuencias desastrosas
que atentan con la estabilidad de su sistema. No es bueno fiarse de lo que diga el
compilador, de que estas variables se liberan solas al terminar la ejecucin del
programa, no siempre puede ser as.
Aplicacin de los operadores New y Delete
Se presenta un ejemplo como aplicacin de los operadores de C++, utilizados
para asignar y liberar memoria dinmicamente.
En el listado se declaran las variables index de tipo entero y los apuntadores
point1 y point2 ambos de tipo entero.
Progra15.cpp
# include <iostream.h>
# include <conio.h>
main()
{
clrscr();
int index, *point1, *point2;
point1 = &index;
*point1 = 77;
point2 = new int;
*point2 = 173;
cout <<"SALIDA DE LAS VARIABLES index, *point1 Y *point2\n\n";
cout <<"Los valores son " << index <<" " << *point1 << " "<< *point2 <<'\n';
point1 = new int;
point2 = point1;
*point1 = 999;
cout <<"Los valores son " << index <<" " << *point1 << " "<< *point2 <<'\n';
delete point1;
float *float_point1, *float_point2 = new float;
float_point1 = new float;
*float_point2 = 3.14159;
*float_point1 = 2.4 * (*float_point2);
delete float_point2;
delete float_point1;
char *c_point;
41
En las primeras lneas del programa, se hace uso de los punteros tal como
se hacen tambin en C.
42
43
Cuando se utiliza new para reservar memoria para un vector, el tamao del
vector se sita entre corchetes, siguiendo al tipo:
int *intvector;
intvector = new int [20];
y se libera:
delete [ ] intvector;
//10
44
Pero quin asegura que el espacio requerido por new est disponible?. Para
controlar esta situacin y evitar un mensaje de error por parte del sistema en
tiempo de ejecucin, en el listado siguiente se propone una nueva versin del
programa.
Implementacin de New para verificacin de memoria
Progra17.cpp
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
void main()
{
int *numero;
45
46
47
}
clrscr();
cout<<"LISTADO DE PERSONAS REGISTRADAS "<<"\n";
// El ciclo for usado para la impresin o visulizacin de los datos registrados
for(i=1;i<=n;i++)
{
cout<<" NOMBRE : "<<p[i].nombre<<"\n";
cout<<" EDAD : "<<p[i].edad<<"\n\n";
}
getch();
// La funcin free () libera la memoria asignada al apuntador p
free (p);
}
51
Adjudica espacio para un array de nmemb objetos, cada cual tiene como tamao
tamano. El espacio es inicializado a cero todos los bits.
La funcin calloc retorna o bien un puntero nulo o bien un puntero al espacio
adjudicado.
Progra20.cpp
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int main( void )
{
int *numPtr, i;
size_t tamano=0;
printf( "Introduzca el tamao de la lista: " );
scanf( "%d", &tamano );
puts( "Adjudicamos espacio a la lista (con calloc)." );
numPtr = (int *)calloc( tamano, sizeof(int) );
for( i=0; i<tamano-1; i++ )
printf( "%d, ", numPtr[i] = rand() % 100 + 1 );
printf( "%d\n", numPtr[i] = rand() % 100 + 1 );
numPtr = (int *)realloc( numPtr, tamanyo/=2 );
printf( "Recortamos la lista a la mitad: %d\n", tamano );
for( i=0; i<tamano-1; i++ )
printf( "%d, ", numPtr[i] );
printf( "%d\n", numPtr[i] );
puts( "Liberamos el espacio (con realloc)." );
realloc( numPtr, 0 );
getch();
return 0;
}
//Fin de la implementacin de la funcin Calloc3
52
Enunciado 2
Int punt;
punt = punt + 1;
punt = punt 2;
punt++;
punt--;
// 1
// 2
// 3
// 4
// 5
Enunciado 3
void main()
{
int m, *h, **s, ***q ;
clrscr();
h = &m ;
*h = 80 ;
s = &h ;
**s += *h ;
q = &s ;
***q += **s + *h ;
cout << " *h=" << *h << " \n" ;
cout << " **s=" << **s << " \n" ;
cout << "***q=" << ***q << " \n" ;
getch();
}
// 1
// 2
// 3
// 4
// 5
// 6
// 7
//8
//9
//10
54
55
56
UNIDAD 2
Nombre
Unidad
de
Introduccin
Justificacin
Captulo 4
Leccin 1
Leccin 2
Leccin 3
Leccin 4
Leccin 5
Captulo 5
Leccin 6
Leccin 7
Leccin 8
Leccin 9
Leccin 10
Captulo 6
Leccin 11
Leccin 12
Leccin 13
Leccin 14
Leccin 15
58
CAPITULO 4: PILAS
Introduccin
Las pilas son un tipo de estructura de datos de tipo lineal condicionadas donde las
inserciones y eleminaciones se realizan por un mismo extremo. Se tratan los
temas relacionados con los conceptos bsicos de las pilas, las operaciones que se
pueden realizar con las pilas, todo conjugado en programas de aplicacin,
implementados con apuntadores, al igual que en los anteriores captulos, cada uno
de los programas aqu presentados, estn previamente compilados y depurados
de tal manera que se mustra la salida en pantalla de cada uno. Lo anterior
garantiza al estudiante que puede guiarse en el cdigo fuente para hacerle
modificaciones y proponer soluciones a entornos reales.
Leccin 1: Conceptos bsicos de pilas
La pila se considera un grupo ordenado de elementos porque estos estn
clasificados de acuerdo al tiempo en que estn residiendo en la pila, el elemento
que se elimina de la cabeza es siempre el que lleve menos tiempo en ella. En
resumen una pila es una lista en la cual los elementos solo pueden ser insertados y
eliminados por un extremo de ella, este extremo es llamado la cima. De esta forma
los elementos son eliminados en forma contraria a como fueron insertados.
Definicin de una Pila
Una pila llamada stack (en ingls) se puede definir como un tipo especial de lista
lineal condicionada, en la que las inserciones y el borrado de nuevos elementos
se realizan slo por un extremo, que se denomina cima o tope top (en ingls).
La pila es una estructura con numerosas analogas en la vida real: pila de platos,
una pila de monedas, una pila de camisas, una pila de animales, etc. Como se
muestra en la figura siguiente.
59
Fuente: www.utpl.edu.ec/ecc/wiki/images/1/1e/Pilas.JPG
Una pila, a un nivel fsico puede representarse tal como se muestra en figura 21,
donde representa una pila de moneda o una pila de platos en un restaurante.
Cuando se habla de una pila a nivel lgico, es una estructura de datos lineal
compuesta de elementos del mismo tipo, en la cual cada uno de ellos solo puede
ser insertado y eliminado por su parte final, es decir por el extremo final.
La posicin final la llamamos cima o tambin cabeza de la pila; para darse una
mejor representacin (abstraccin) de ella, su representacin grfica en el papel la
se hace en forma vertical, con la cima en la parte de arriba. De esta forma cuando
se aade un nuevo elemento solo podr ser colocado en la parte superior, piense
en una pila de platos de cocina o en una pila de libros, los cuales se colocan en
orden uno encima de otro. Por lo anterior las pilas tambin son llamadas listas en
las cuales el ltimo elemento en entrar es el primero en salir, en ingls el acrnimo
LIFO(Last Input, First Out).
60
En principio, la pila est vaca y el puntero de la pila o CIMA debe estar en cero. Al
insertar un elemento en la pila, se incrementa el puntero en una unidad. Mientras
que al sacar un elemento de la pila se decrementa en una unidad el puntero,
teniendo aplicabilidad las operaciones que se realizan con punteros tratadas en la
Unidad uno. Siendo P el puntero (*P), al manipular una pila se deben realizar
algunas comprobaciones.
En una pila vaca no se pueden sacar datos, as que si (P = 0) no es posible
eliminar elementos de la pila.
En condiciones Ideales, una pila puede contener un nmero ilimitado de
elementos y no producir nunca desbordamiento. En la prctica, el espacio de
almacenamiento disponible es finito dependen de los recursos de memoria de la
mquina (los recursos computacionales son finitos). La codificacin de una pila
requiere un cierto equilibrio, ya que si la longitud mxima de la pila es demasiado
grande, se gasta mucha memoria, mientras que un valor pequeo producir
desbordamientos con mucha frecuencia.
61
struct pila
{
int numero;
struct pila *sig;
}*inicio=NULL, *c=NULL;
Para continuar con el programa se escoge la segunda alternativa, que tiene entre
sus miembros una variable llamada numero de tipo entero que guardar los
nmeros que sern ingresados, al igual que un puntero llamado sig del tipo struct
pila, del mismo tipo de la estructura usado para apuntar al siguiente nodo de la
pila. Finalmente se declaran como instancias, dos variables apuntador del mismo
tipo de la estructura llamadas inicio y c inicializadas a NULL como buena
costumbre.
Estas variables son llamadas instancias que son del mismo tipo de la estructura,
inicio usada para reservar memoria y c usada para recorrer la pila; una vista de lo
hecho hasta ahora es:
Figura 22 Declaracin de la estructura pila
{
textcolor(10);
int opc=0;
do
{
clrscr();
cout<<"
MANEJO DE UNA ESTRUCTURA TIPO PILA ";
cout<<"\n\n\n");
cout<<"1. Insertar\n");
cout<<"2. Extraer\n");
cout<<"3. Visualizar\n");
cout<<"4. Salir\n\n");
cout<<"Digite la opcion: ");
cin >>opc;
switch (opc)
{
case 1:
cout<<"inserter";
break;
case 2:
cout<<"extraer";
break;
case 3:
cout<<"visualizar";
break;
case 4:
exit(1);
}
getch();
}while (opc!=4)
}
65
El otro cambio que se har al cdigo inicial, es en el case 1 del swich cambiamos
el mensaje a desplegar cout<<insertar; por insertar(); usado por el programa
principal para llamar a la funcin insertar(). Se visualiza en figura 26.
66
67
69
71
break;
case 2:
extraer();
break;
case 3:
visualizar();
break;
case 4:
exit(1);
}
getch();
}while (opc!=4);
}
void insertar (void)
{
inicio=(struct pila *)malloc(sizeof(struct pila));
clrscr();
cout<<"Digite el dato de tipo ENTERO: ";
cin>>inicio->numero;
if (c==NULL)
{
c=inicio;
inicio->sig=NULL;
}
else
{
inicio->sig=c;
c=inicio;
}
}
void visualizar (void)
{
if (c==NULL)
{
clrscr();
cout<<"NO HAY ELEMENTOS A LISTAR";
}
73
else
{
clrscr();
inicio=c;
while (inicio!=NULL)
{
cout<<"Numero: "<<inicio->numero<<endl;
inicio=inicio->sig;
}
}
getch();
}
74
void insertar(void)
{
AUX=(struct pila *)malloc(sizeof(struct pila));
clrscr();
cout<<"INGRESAR DATOS DE LA PILA \n\n ";
cout<<"Nombre: ";
gets(AUX->nombre);
if (CAB==NULL)
{
CAB=AUX;
AUX->ant=NULL;
}
else
{
AUX->ant=CAB;
CAB=AUX;
}
}
//FUNCION DE ELINIMAR ELEMENTOS DE LA PILA
void extraer(void)
{
if (CAB==NULL)
return;
AUX=CAB;
CAB=CAB->ant;
free(AUX);
cout<<"\n Se elimino a " <<AUX->nombre <<" de la pila";
getch();
}
//FUNCION DE VISUALIZAR LA PILA
void visualizar(void)
{
if (CAB==NULL)
return;
clrscr();
77
AUX=CAB;
cout<<"DATOS DE LA PILA \n\n ";
while (AUX!=NULL)
{
cout<<"Nombre: "<<AUX->nombre <<endl;
AUX=AUX->ant;
}
getch( );
}
Progra23.cpp
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
/*************** DEFINICION DEL NODO (Estructura) **************/
struct nodo
{
char nombre[40];
// Datos del nodo Entero
int edad;
double salario;
struct nodo *sig; // Puntero a otro nodo
};
/****************************************************************/
struct nodo *tope; // tope de nuestra PILA
78
{
while(tope != NULL)
Pop();
printf("PILA VACIA");
getch();
break;
}
}
}while(d != 4); // mientras que la opcion no sea 4
return 0;
}
La salida en pantalla de progra23.cpp que se implementa con la sintaxis del
lenguaje C, se puede visualizar en la figura 31 como se muestra a continuacin.
81
CAPITULO 5: COLAS
Introduccin
Las colas al igual que las pilas, son una estructura de datos de tipo lineal
condicionadas donde las inserciones y eleminaciones se realizan por extremos
diferentes. Se abordan los temas relacionados con los conceptos bsicos de las
colas, las operaciones que se pueden realizar con las colas, todo conjugado en
programas de aplicacin, implementados con apuntadores.
Se hace uso de un men de opciones para cada programa y funciones para la
insercin, visualizacin, y eliminacin de nodos de la cola. Al igual que en los
anteriores captulos, cada uno de los programas aqu presentados, estn
previamente compilados y depurados de tal manera que se mustra la salida en
pantalla de cada uno. Lo anterior garantiza al estudiante que puede guiarse en el
cdigo fuente para hacerle modificaciones y proponer soluciones a entornos
reales.
Leccin 6: Conceptos bsicos de colas
Las colas son otro tipo de estructura de datos lineales, similar a las pilas,
diferencindose de ellas en el modo de insertar/eliminar elementos. As pues, la
diferencia con las pilas reside en el modo de entrada/salida de datos; en las colas
las inserciones se realizan al final de la lista, no al principio.
Por ello, las colas se usan para almacenar datos que necesitan ser procesados
segn el orden de llegada. Una aplicabilidad de las colas puede realizarse en un
sistema de computacional manejado a travs de una red de computadoras donde
se comparte una sola impresora para todos los equipos conectados a la red; de
tal manera que se imprimirn los documentos en el orden en que se hace la
peticin de impresin de cada usuario. Formando as una cola de impresin.
Definicin de una cola
Una cola es una estructura lineal de datos condicionada, en la que las
eliminaciones se realizan al principio de la lista, es decir, al frente, y las
inserciones se realizan en el extremo opuesto de la lista, es decir, al final. En las
colas el elemento que entr de primero sale tambin de primero; por ello se
conocen como listas FIFO, en ingles (first-in, first-out), primero en entrar, primero
en salir.
82
Una muy buena representacin grfica de las estructuras de datos tipo cola puede
visualizarse en la Figura 32, que se muestra a continuacin.
Fuente: http://www.utpl.edu.ec/ecc/wiki/index.php/Imagen:Cola.JPG
83
Una muy buena implementacin de las colas podra realizarse un programa para
manejar un planificador de citas en un consultorio mdico, de tal manera que cada
solicitud de una cita se va almacenando en la cola el nombre del paciente y la hora
de la cita, en el mismo orden de fecha y hora en que se solicit ser atendida.
En general en una cola, de la vida diaria, el primero que llega ser atendido
primero, pasando a continuacin el segundo de la cola al frente; y cada que llega
un nuevo elemento este se colocar al final de la cola. De aqu que el extremo por
donde se insertan los elementos se llamar "final" y por donde se retiran "frente".
Debido a esto ltimo las colas tambin son llamadas listas en las cuales el primer
elemento en entrar es el primero en salir.
Para las colas que se trabajarn se sobreentender, a menos de decir lo contrario,
que la regla es que siempre el primero se atiende primero.
Las operaciones en detalle que se pueden realizar con una cola son:
Acceder al primer elemento de la cola.
Aadir un elemento al final de la cola.
Eliminar el primer elemento de la cola.
Vaciar la cola.
Verificar el estado de la cola: vaca, llena.
84
clrscr();
Listar();
cout << "\nIMPLENTACION DE UNA COLA CON ARREGLOS \n";
cout << "\n\nInsertar Atender Salir \n";
switch (opcion=getch()){
case 'I':; case 'i': Insertar(); break;
case 'A':; case 'a': Atender(); break;
}
} while (opcion != 'S' && opcion != 's');
}
El resultado de la salida en pantalla del Listado Implementado con arreglos llamado
progra24.cpp se puede visualizar en la siguiente figura 34.
Figura 33 Salida en pantalla de progra24
3. Se guarda el contenido del nodo para devolverlo como retorno, hay que
recordar que la operacin de lectura en colas implican tambin borrar.
4. se libera la memoria asignada al primer nodo, el que se quiere eliminar.
Free (AUXILIAR);
La siguiente funcin resume el anterior anlisis realizado para la eliminacin de
nodos a la cola
void extraer(void)
{
if (CABEZA==NULL)
{
cout<<"No hay elementos en la cola";
getch();
}
else
{
AUXILIAR=CABEZA;
cout<<"El dato eliminado es: "<<AUXILIAR->nombre;
getch();
CABEZA=CABEZA->sig;
free(AUXILIAR);
}
}
Visualizar los elementos de una cola
Se har uso del puntero llamado CABEZA que apunta a la cabeza de la cola. Si la
cola est vaca si CABEZA==NULL retorna al programa principal desplegando el
mensaje que indica el estado de la cola.
En caso contrario, que la cola tenga elementos
1. Se hace que AUXILIAR apunte al primer elemento de la cola, es decir a la
CABEZA.
2. inicia el recorrido por todos los elementos de la cola, por medio del apuntador
AUXILIAR, AUXILIAR->nombre, posteriormente a AUXILIAR se le asigna el valor
del siguiente nodo, AUXILIAR=AUXILIAR->sig el proceso se repite hasta que este
sea igual a NULL.
La siguiente funcin representa el cdigo que permite la visualizacin de los datos
de la cola.
void visualizar(void)
{
if (CABEZA==NULL)
89
{
cout<<"NO HAY ELEMENTOS EN LA COLA";
getch();
}
else
{
clrscr();
AUXILIAR=CABEZA;
while (AUXILIAR!=NULL)
{
cout<<"Nombre:" <<AUXILIAR->nombre <<"\n";
AUXILIAR=AUXILIAR->sig;
}
getch();
}
clrscr();
gotoxy(30,8);
cout<<"1.- Insertar";
gotoxy(30,10);
cout<<"2.- Extraer";
gotoxy(30,12);
cout<<"3.- Visualizar la cola";
gotoxy(30,14);
cout<<"4.- Salir";
gotoxy(25,16);
cout<<"Ingrese la opcion :";
opc=getch( );
switch(opc)
{
case '1':
insertar( );
break;
case '2':
extraer( );
break;
case '3':
visualizar( );
}
}while (opc!='4');
return 0;
}
void insertar(void)
{
AUXILIAR=(struct cola *)malloc(sizeof(struct cola));
clrscr();
cout<<"Nombre: ";
gets(AUXILIAR->nombre);
AUXILIAR->sig=NULL;
if (FINAL==NULL)
FINAL=CABEZA=AUXILIAR;
else
{
FINAL->sig=AUXILIAR;
FINAL=AUXILIAR;
}
}
91
void extraer(void)
{
if (CABEZA==NULL)
{
cout<<"No hay elementos en la cola";
getch();
}
else
{
AUXILIAR=CABEZA;
cout<<"El dato eliminado es: "<<AUXILIAR->nombre;
getch();
CABEZA=CABEZA->sig;
free(AUXILIAR);
}
}
void visualizar(void)
{
if (CABEZA==NULL)
{
cout<<"NO HAY ELEMENTOS EN LA COLA";
getch();
}
else
{
clrscr();
cout<<"ELEMENTOS DE LA COLA \n\n";
AUXILIAR=CABEZA;
while (AUXILIAR!=NULL)
{
cout<<"Nombre:" <<AUXILIAR->nombre <<"\n";
AUXILIAR=AUXILIAR->sig;
}
getch();
}
}
La salida en pantalla de Progra25.cpp se puede visualizar en la figura 35 que se
muestra a continuacin.
92
register int t;
for(t=0;t<MAX; ++t) p[t] = NULL; //Inicializa el arreglo
for(;;)
{
cout<<"\n\nOPCIONES DE ITERACION DE LA COLA\n\n";
cout<<"I. Introducir\n";
cout<<"R. Revisar\n";
cout<<"E. Eliminar\n";
cout<<"S. Salir\n\n";
cout<<"Seleccione la opcin : ";
gets(s);
*s = toupper(*s);
switch(*s)
{
case 'I':
intro();
break;
case 'R':
revisar();
break;
case 'E':
eliminar();
break;
case 'S':
exit(0);
}
}
}
//INTRODUCIR CITAS EN LA COLA
void intro(void)
{
char s[256], *p;
do
{
cout<<"Introduce la cita " <<spos+1 <<" : ";
gets(s);
if(*s==0) break; //no hay entradas
p = (char *)malloc(strlen(s)+1);
94
if(!p)
{
cout<<"No hay memoria \n";
return;
}
strcpy(p, s);
if(*s)calmac(p);
}while(*s);
clrscr();
}
}
//Recuperar una cita
char *crecup(void)
{
if(rpos==spos)
{
cout<<"No hay mas citas \n";
return NULL;
}
rpos++;
return p[rpos-1];
}
El resultado despus de haber compilado, depurado y ejecutado el listado
Progra26.cpp se puede visualizar en la figura 36, que se muestra a continuacin.
Figura 35 Salida en pantalla de progra26.cpp
96
CAPITULO 6: LISTAS
Introduccin
Las listas al igual que las pilas y las colas, son una estructura de datos de tipo
lineal diferencindose de las anteriores en el hecho de que pueden las
inserciones y eleminaciones se en cualquier parte de la lista. Esto hace que
tengan mayor aplicabilidad en el entorno real. Se abordan los temas relacionados
con los conceptos bsicos de las listas, as como tipos de listas y las operaciones
que se pueden realizar con las listas, todo conjugado en programas de aplicacin,
implementados con apuntadores.
Se hace uso de un men de opciones para cada programa y funciones para la
insercin, visualizacin, eliminacin y bsqueda de nodos en la lista. Al igual que
en los anteriores captulos, cada uno de los programas aqu presentados, estn
previamente compilados y depurados de tal manera que se mustra la salida en
pantalla de cada uno. Lo anterior garantiza al estudiante que puede guiarse en el
cdigo fuente para hacerle modificaciones y proponer soluciones a entornos
reales.
Leccin 11: Concepto bsicos de Listas
Una lista enlazada es una coleccin o secuencia de elementos del mismo tipo
dispuestos uno detrs de otro, en el que cada elemento se liga al siguiente
elemento por un enlace que no es ms que un puntero previamente definido.
Las listas segn su estructura se han dividido en cuatro grandes categoras:
1.- Listas Simplemente enlazadas
2.- Listas Doblemente enlazadas
3.- Listas Circular simplemente enlazada
4.- Lista circular doblemente enlazada
Lista simplemente enlazada
Entre las listas simplemente enlazadas se encuentra un tipo de lista llamada Lista
contigua: La cual se compone de un conjunto de elementos de un tipo dado que
se encuentran ordenados y pueden variar en nmero. Esta es una definicin
general, que incluye los ficheros y vectores.
97
Las entradas de una gua o directorio telefnico, por ejemplo, estn en lneas
sucesivas, excepto en las partes superior e inferior de cada columna. Una lista
lineal se almacena en la memoria principal de una computadora en posiciones
sucesivas de memoria; cuando se almacenan en cinta magntica, los elementos
sucesivos se presentan en sucesin en la cinta. Esta asignacin de memoria se
denomina almacenamiento secuencial. Posteriormente, se ver que existe otro
tipo de almacenamiento denominado encadenado o enlazado.
98
Una lista enlazada sin ningn elemento se llama lista vaca. Su puntero inicial o
de cabecera tiene el valor nulo, es decir apunta a NULL.
*puntero NULL;
Una lista enlazada se define por:
99
auxiliar->dato = dato;
anterior = NULL;
puntero = *entero; //puntero es el puntero auxiliar que recorre la lista
while((puntero != NULL) && (puntero->dato < dato))
{
anterior = puntero;
puntero = puntero->sig;
}
if(anterior == NULL)
{
auxiliar->sig = *entero;
*entero = auxiliar;
}
else
{
anterior->sig = auxiliar;
auxiliar->sig = puntero;
}
}
void eliminar(struct lista **entero, int dato)
{
struct lista *puntero, *anterior;
puntero = *entero;
anterior = NULL;
while((puntero != NULL) && (puntero->dato < dato))
{
anterior = puntero;
puntero = puntero->sig;
}
if(puntero->dato != dato)
cout<<"El numero no existe "<<endl;
else
{
if(anterior == NULL) //1er lista
*entero = (*entero)->sig;
else
103
anterior->sig = puntero->sig;
delete puntero;
}
}
void recorrer(struct lista **entero)
{
struct lista *puntero;
puntero = *entero;
while(puntero != NULL)
{
cout<<puntero->dato<< " ";
puntero = puntero->sig;
}
}
int buscar(struct lista **entero, int dato)
{
struct lista *puntero;
puntero = *entero;
while((puntero != NULL) && (puntero->dato < dato)) puntero = puntero->sig;
if(puntero->dato == dato)
return 1;
else
return 0;
}
El resultado de la salida en pantalla del listado anterior se puede observar en la
siguiente figura 38. Analice el cdigo y plantee modificaciones al programa, en
busca de mejoras.
104
Anlisis de Progra28.cpp
Al analizar un poco el cdigo de progra28.cpp se tiene definida una estructura
llamada lista, que tiene como miembros a un puntero llamado *nuevo y a *sig que
es el enlace al siguiente elemento de la lista y es del tipo de la estructura, al igual
que los punteros *L y *P, utilizados para gestionar la lista. Se define la variable i
que es de tipo entero utilizada para el recorrido del ciclo for. El cual est
predefinido para que repita el proceso de insertar elementos 5 veces al estar
definido as: for(i=1;i<=6;i++).
106
Progra29.cpp
#include <stdlib.h>
#include <iostream.h>
#include <conio.h>
struct nodo
{
int dato;
struct nodo *sig;
}*l=NULL,*primero=NULL;
int main()
{
clrscr();
int acumulador=0;
int i=0, vector[6];
cout<<"IMPLEMENTACION DE UNA LISTA ENLAZADA\n\n";
cout<<"Ingrese 6 numeros\n";
for(i;i<6;i++)
{
cin>> vector[i];
acumulador = acumulador + vector[i];
107
}
for(i;i<6;i++)
{
primero=(struct nodo *)malloc(sizeof(struct nodo));
primero->dato=vector[i-1];
primero->sig = l;
l = primero;
}
cout<<"\nLista creada. Preseione una tecla ";
getch();
cout<<"\nLa sumatoria de la lista es : " <<acumulador;
cout<<" \n";
while(l!=NULL)
{
cout<< l->dato;
l=l->sig;
}
free(primero);
getch();
return 0;
}
El resultado despus de haber compilado y depurado el cdigo es el que se
visualiza en la figura 40,
108
109
Progra30.cpp
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>
struct direc
{
char nombre[30];
char ciudad[20];
char codigo[10];
struct direc *sig; //PUNTERO A LA SIGUIENTE ENTRADA
5
110
int main(void)
{
clrscr();
ppio = final = NULL; //INICIALIZA LOS PUNTEROS
for(;;)
{
switch(menu())
{
case 1: intro(); //INTRODUCIR UNA DIRECCION
break;
case 2: eliminar(&ppio, &final); //ELIMINA UNA DIRECCION
break;
case 3: listar();//MOSTRAR LA LISTA
break;
case 4: buscar();//ENCONTRAR UNA DIRECCION
break;
case 5: exit(0);
}
}
}
char s[80];
int c;
cout<<"\nLISTA DOBLEMENTE ENLAZADA\n\n";
cout<<"1. Introducir una direccion" <<endl;
cout<<"2. Eliminar una direccin" <<endl;
cout<<"3. Listar el archivo" <<endl;
cout<<"4. Buscar" <<endl;
cout<<"5. Salir" <<endl;
do
{
cout<<"\nIntroduce una opcion: ";
gets(s);
c = atoi(s);
}while(c<0 || c>5);
clrscr();
return c;
}
//Introducir nombres y direcciones
void intro(void)
{
struct direc *info;
for(;;)
{
info = (struct direc *)malloc(sizeof(struct direc));
if(!info)
{
cout<<endl <<"no hay memoria";
return;
}
leecad("\nIntroduce el nombre: ", info->nombre, 30);
if(!info->nombre[0]) break; //parar el proceso
leecad("Introduce la ciudad: ", info->ciudad, 20);
leecad("Introduce el codigo: ", info->codigo, 10);
dl_insert(info, &ppio, &final);
}
clrscr();
}
112
ant = p;
p = p->sig;
}
else
{
if(p->ant)
{
p->ant->sig = i;
i->sig = p;
i->ant = p->ant;
p->ant = i;
*ppio = i;
return;
}
i->sig = p; //nuevo primer elemento
i->ant = NULL;
p->ant = i;
*ppio = i;
return;
}
}
ant->sig = i; //ponerlo en el final
i->sig = NULL;
i->ant = ant;
*final = i;
}
//eliminar un elemento de la lista
void eliminar(struct direc **ppio, struct direc **final)
{
struct direc *info;
char s[80];
leecad("Introduce el nombre: ", s, 30);
info = buscar(s);
if(info)
{
if(*ppio==info)
{
*ppio=info->sig;
if(*ppio) (*ppio)->ant =NULL;
else *final = NULL;
}
else
114
{
info->ant->sig = info->sig;
if(info != *final)
info->sig->ant = info->ant;
else
*final = info->ant;
}
free(info); //devolver la memoria al sistema
}
clrscr();
}
//buscar una direccion
struct direc *buscar(char *nombre)
{
struct direc *info;
info = ppio;
while(info)
{
if(!strcmp(nombre, info->nombre))
return info;
info = info->sig; //obtener siguiente direccion
}
cout<<"nombre no encontrado" <<endl;
return NULL; //no encontrado
}
cout<<endl <<endl;
}
// esta funcion imprime realmente los campos de cada direccion
void mostrar(struct direc *info)
{
cout<<info->nombre<<"-";
cout<<info->ciudad<<"-";
cout<<info->codigo<<"-";
cout<<endl <<endl;
}
//buscar un nombre en la lista
void buscar(void)
{
char nombre[40];
struct direc *info;
cout<<"Introduce el nombre a encontrar: ";
gets(nombre);
info = buscar(nombre);
if(!info)
cout<<"no encontrado";
else mostrar(info);
getch();
clrscr();
}
116
Cada nodo de una lista circular es accesible desde cualquier otro nodo de ella.
Es decir, dado un nodo se puede recorrer toda la lista completa. En una lista
enlazada de forma simple slo es posible recorrerla por completo si se parte de
su primer nodo.
Las operaciones de concatenacin o unin y divisin de listas son ms
eficaces con listas circulares.
Se pueden producir lazos o bucles infinitos. Una forma de evitar estos bucles
infinitos es disponer de un nodo especial que se encuentre permanentemente
asociado a la existencia de la lista circular. Este nodo se denomina cabecera
de la lista.
117
El nodo cabecera puede diferenciarse de otros nodos en una de las dos formas
siguientes:
Puede tener un valor especial en su campo INFO que no es vlido como datos
de otros elementos.
Puede tener un indicador o bandera que seale cundo es nodo cabecera.
118
----------
NULL
119
120
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) {
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) {
122
123
124
siguientes
operaciones
Una funcin que elimine los ltimos n elementos apilados en una pila p si
los hay.
Una funcin que imprima la inversa de una pila p, es decir que el ltimo
dato ingresado sea el primero en la lista de impresin.
Una funcin llamada fondo que calcule el elemento del fondo de una pila p.
es decir el primer elemento insertado.
Ejercicio 2. Implemente una pila usando memoria dinmica con listas enlazadas.
Para realizar operaciones de push y pop.
Ejercicio 3. Implemente un programa para gestionar la entrega de regalos a los
nios que fueron invitados a la fiesta. Los regalos se entregarn teniendo en
cuenta el orden de llegada, el primero que llegue ser el primero en recibir su
regalo, es importante conocer el nombre y la edad de los nios que recibieron
regalos.
Ejercicio 4. Implementar funciones para una estructura tipo colas as:
Ejercicio 5. Una cola medieval se comporta como una cola ordinaria, con la nica
diferencia de que los elementos almacenados en ella se dividen en dos
estamentos: nobles y plebeyos. Dentro de cada estamento, los elementos deben
ser atendidos en orden de llegada; pero siempre que haya nobles en la cola, stos
deben ser atendidos antes que los plebeyos. Se pide:
Implementar las colas medievales utilizando memoria dinmica para.
Ejercicio 6. Implemente una lista lineal de datos de tipo numrico, con opciones de
ordenar la lista en los dos sentidos, ascendente y descendente, e imprima el
resultado.
Ejercicio 7. Escribir un programa para el mantenimiento de notas de un grupo de
alumnos usando listas. Se debe registrar el nombre del alumno y la respectiva
nota y calcular el promedio del grupo, la estructura a implementar es la siguiente.
struct nodo {
int nota;
char nombre[15];
struct nodo *siguiente;
} cabeza;
Ejercicio 8. Desarrolle un programa para buscar un elemento en la lista (de
nmeros enteros) y borrar todas las ocurrencias de cada elemento encontrado use
un men de opciones.
126
128
UNIDAD 3
Nombre de la Unidad
Introduccin
Es importante resaltar que en esta unidad se hace una
recopilacin de informacin desarrollada por varios
autores que se relacionan en la bibliografa, con el
propsito de ampliar la temtica y brindar al estudiante
mayor soporte conceptual.
Al final de la unidad, se plantean una serie de actividades
que buscan determinar el grado de apropiacin del
conocimiento, basados en los tres momentos:
Reconocimiento, Profundizacin y transferencia, que en
su conjunto garantizan el aprendizaje y por ende la
adquisicin de la competencia esperada en el curso.
Justificacin
Intencionalidades
Formativas
Captulo 1
Leccin 1
Leccin 2
Leccin 3
Leccin 4
Leccin 5
Captulo 2
Leccin 6
Leccin 7
Leccin 8
Leccin 9
Leccin 10
Captulo 3
Leccin 11
Leccin 12
Leccin 13
Leccin 14
Leccin 15
RBOLES
Teora general de rboles
Otros conceptos de la teora general de rboles
rbol completo
Estructura para la creacin de un rbol de orden tres
Introduccin al Modo Grfico de C++
RBOLES BINARIOS
Conceptualizacin de rboles binarios
Clasificacin de los rboles binarios
Formas de Recorrer un rbol Binario
bol binario de bsqueda (ABB)
Operaciones en ABB
GRAFOS
Conceptos bsicos de grafos
Grafo no dirigido
Representacin de los grafos
Representacin mediante listas de Adyacencia
Exploracin de grafos
130
CAPITULO 7: RBOLES
Introduccin
Los rboles a diferencia de las listas son una estructura de datos de no lineal,
atendiendo ms a una estructura de tipo jerrquico. Se abordan los temas
relacionados con los conceptos bsicos de rboles, incluyendo la teora general de
rboles e identificando los diferentes tipos de rboles.
Se presenta un apartado ampliamente desarrollado a cerca del mdo grfico de
C++, donde se ilustra a travs de imgenes la configuracin del editor, las libreras
grficas y el directorio donde se encuentra la interfaz grafica es decir BGI.
Finalizando con un programa de aplicacin del modo grfico que muestra figuras
geomtricas y texto manejando colores y rellenos.
Leccin 1: Teora general de rboles
Los rboles son, sin duda, una de las estructuras de datos no lineales, empleadas
en informtica, tanto para resolver problemas de hardware como de software. Los
rboles de directorios son organizaciones bastante empleadas por cualquier
usuario o programador de una computadora. De igual manera cumplen un buen
papel en la toma de decisiones, valido como rbol de decisiones.
Los rboles genealgicos y los organigramas son ejemplos comunes. Entre otras
aplicaciones, los rboles se emplean para analizar circuitos elctricos y para
representar la estructura de frmulas matemticas, as como para organizar la
informacin de bases de datos, para representar la estructura sintctica de un
programa fuente en compiladores y para la toma de decisiones.
no tienen una estructura lgica de tipo lineal o secuencial como aquellas, sino
ramificada. Tienen aspecto de rbol, de ah su nombre.
Su estudio desde el punto de vista matemtico pertenece a la teora de
grafos; desde el punto de vista informtico son estructuras de datos, lo que
significa que cada elemento, denominado nodo u hoja, contiene un valor. Su
estudio corresponde a la teora de bases de datos, y en esta terminologa, los
nodos que dependen de otros se denominan hijos. Cada hoja puede tener un
mximo de hijos, si no tiene ninguno se dice que es un nodo terminal.
Un rbol es una estructura de datos no lineal en la que cada nodo puede
apuntar a uno o varios nodos. Tambin se suele dar una definicin recursiva: un
rbol es una estructura compuesta por un dato y varios rboles. Esto son
definiciones simples. Una representacin grfica de los rboles se puede
visualizar en la figura 50 presente a continuacin.
Fuente: http://www.conclase.net/c/edd/index.php?cap=006b
132
Nodo hijo: cualquiera de los nodos apuntados por uno de los nodos del rbol. En
el ejemplo, 'L' y 'M' son hijos de 'G'.
Nodo padre: nodo que contiene un puntero al nodo actual. En el ejemplo, el nodo
'A' es padre de 'B', 'C' y 'D'.
Los rboles con los que trabajar tienen otra caracterstica importante: cada
nodo slo puede ser apuntado por otro nodo, es decir, cada nodo slo tendr un
padre. Esto hace que estos rboles estn fuertemente jerarquizados, y es lo que
en realidad les da la apariencia de rboles.
En cuanto a la posicin dentro del rbol:
Nodo raz: nodo que no tiene padre. Este es el nodo que usaremos para
referirnos al rbol. En el ejemplo, ese nodo es el 'A'.
Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L',
'M', 'N' y 'O'.
Nodo rama: aunque esta definicin apenas la usaremos, estos son los nodos que
no pertenecen a ninguna de las dos categoras anteriores. En el ejemplo: 'B', 'C',
'D', 'E', 'G' y 'J'.
sucesivamente. En el ejemplo de la figura 50, el nodo 'D' tiene nivel 1, el nodo 'G'
tiene nivel 2, y el nodo 'N', nivel 3.
Altura: la altura de un rbol se define como el nivel del nodo de mayor nivel.
Como cada nodo de un rbol puede considerarse a su vez como la raz de un
rbol, tambin se puede hablar de altura de ramas. El rbol del ejemplo de la
figura 50, tiene altura 3, la rama 'B' tiene altura 2, la rama 'G' tiene altura 1, la 'H'
cero. Los rboles de orden dos son bastante especiales, de hecho se ampliar un
poco la informacin en el siguiente captulo. Estos rboles se conocen tambin
como rboles binarios.
Frecuentemente, aunque tampoco es estrictamente necesario, para hacer ms
fcil moverse a travs del rbol, se aade un puntero a cada nodo que apunte al
nodo padre. De este modo se podr avanzar en direccin a la raz, y no slo
hacia las hojas.
Es importante conservar siempre el nodo Raz ya que es el nodo a partir del
cual se desarrolla el rbol, si se pierde este nodo, se perder el acceso a todo
el rbol.
Leccin 4: Estructura para la creacin de un rbol de orden tres
El nodo tpico de un rbol difiere de los nodos que se vieron en la unidad dos
para el manejo de las listas, aunque slo en el nmero de nodos. A continuacin
se presenta un ejemplo de nodo para crear rboles de orden tres:
struct Arbol {
int dato;
struct Arbol *rama1;
struct Arbol *rama2;
struct Arbol *rama3;
};
Generalizando ms se puede declarar un a constantes llamada orden que se
le asigna el valor de 5:
#define ORDEN 5
struct Arbol {
int dato;
struct Arbol *rama[ORDEN];
};
134
Los algoritmos de insercin y borrado dependen en gran medida del tipo de rbol
que se est implementando, de modo que por ahora se dejarn a un lado y se
centrar la atencin en el modo de recorrer los rboles.
rboles ordenados
Los rboles ordenados son los que tienen ms inters desde el punto de vista
de los tipos de datos abstractos (TAD), y los que tienen ms aplicaciones
genricas.
Un rbol ordenado, en general, es aquel que a partir del cual se puede obtener
una secuencia ordenada siguiendo uno de los recorridos posibles del rbol, es
decir en inorden, preorden o posorden.
En estos rboles es importante que la secuencia se mantenga ordenada aunque
se aadan o se eliminen nodos.
135
rboles 2-3: son rboles de orden 3, que contienen dos claves en cada nodo y
que estn tambin equilibrados. Tambin generan secuencias ordenadas al
recorrerlos en inorden.
rboles-B: caso general de rboles 2-3, que para un orden M, contienen M-1
claves7.
136
entre tantas versiones que hay disponibles y son de fcil manejo y algo adicional
que es de libre uso y ya viene configurado siempre y cuando la descarga la realice
del sitio https://sites.google.com/site/hhmosquera/file-cabinet.
A continuacin se muestra la interfaz grfica del compilador Borland C++ 5.5. el
cual recomiendo su uso para plataforma Windows Vista y Windows 7 pues no
requiere de ningn tipo de configuracin adicional ya tiene las libreras grficas.
Figura 51. Interfaz grfica del compilador Borland C++ 5.5.
#include <stdio.h>
void main(void)
{
int monitor=DETECT, modo;
initgraph(&monitor,&modo,"");
setcolor(YELLOW);
line(10,50,50,100);
setcolor(WHITE);
circle(100,200,30);
//setfillstyle(LINE_FILL,RED);
floodfill(100,200,WHITE);
rectangle(200,100,300,200);
setfillstyle(HATCH_FILL,BLUE);
floodfill(250,150,WHITE);
setcolor(GREEN);
settextstyle(GOTHIC_FONT,HORIZ_DIR,3);
outtextxy(20,10,"Modo Grfico de C++");
outtextxy(20,250,"Hola Ingeniero esto es:");
setcolor(CYAN);
outtextxy(20,300,"Estructura de datos");
getch();
closegraph();
return;
}
Otra alternativa para trabajar en modo grfico es el compilador de Turbo C++ 3.0,
el cual requiere una configuracin bsica que se describe a continuacin.
Para configurar la versin de Borland C++ 3.0 en plataforma Windows XP se
procede de la siguiente manera. Se parte del hecho de que ya se tiene instalado el
compilador en la ruta que se define por defecto, es decir C:\TC\BIN. Para iniciar la
configuracin se debe abrir el editor creando un nuevo programa, Se debe habilitar
las libreras grficas, tal como se visualiza en la figura 52. Presente a
continuacin.
Figura 52 Opcin para Habilitar las libreras grficas de C++.
138
En la primera lnea solo tiene que incluir la siguiente ruta tal como se ve en la
siguiente grfica; C:\TC\BGI
139
As se ver una vez haya incluido la ruta C:\TC\BGI solo debe presionar OK y listo
ya tiene configurado el compilador para trabajar en modo grfico sin problemas.
Solo resta probar la configuracin del editor para modo grfico con un Hola mundo
sencillo, que Grafica Figuras Geomtricas, lneas, texto, colores y rellenos. El
programa incluye comentarios explicativos en cada lnea de cdigo, se sugiere
que estos comentarios los elimine para evitar que pueda generarle algn tipo de
error de compilacin.
Progra32.cpp
#include <graphics.h> // Encabezado con declaraciones de graficos
#include <conio.h>
#include <stdio.h>
void main(void)
{
int monitor=DETECT, modo; // Declaracion de tipo de monitor y modo
initgraph(&monitor,&modo,"C:\\tc\\bgi");
// Inicializa el modo grafico indicando el monitor y modo utilizado
// El subdirectorio C:\\tc\\bgi indica la ruta de localizacion de los
// archivos *.BGI (monitores) y *.CHR (tipos de letras)
gotoxy(1,23);printf("getmaxx()=%d",getmaxx());
gotoxy(1,24);printf("getmaxy()=%d",getmaxy());
setcolor(YELLOW); // Establece el color amarillo para los trazos
line(0,0,50,50); // Dibuja una linea desde 0,0 hasta 50,50
setcolor(WHITE); //Establece el color blanco
circle(100,200,30); // Dibuja un circulo el centro est en 100,200 y de
// radio=30 pixeles
140
141
Introduccin
Los rboles binarios son estructuras de datos de no lineales, atendiendo ms a
una estructura de tipo jerrquico. En el presente captulo se abordan los temas
relacionados con los conceptos bsicos de rboles binarios, incluyendo la teora
general de rboles binarios e identificando la forma de recorrerlos. As como
tambin la documentacin de los rboles binarios de bsqueda y la forma de ir
insertando los datos en el rbol.
Se presenta un apartado amplio con el desarrollo de programas como aplicacin
en mdo grfico de C++. Finalizando con un programa de aplicacin del modo
grfico que muestra la creacin del rbol y la visualizacin de los recorridos.
La raz de este rbol es A y el rbol izquierdo est conformado por dos rboles.
Uno de raz B tal como se muestra en la figura 59. Y el otro de raz I tal como se
muestra en la figura 60.
Los dos subrboles tienen a su vez dos subrboles cada uno, donde C y F son la
races de los arboles del sub rbol izquierdo. Mientras que las races de los
subrboles del subrbol derecho son J y M respectivamente, tal como se visualiza
en la figura 60.
143
El nodo C es una hoja mientras que el nodo B no se puede considerar como hoja
porque tiene una ramificacin por la derecha. El nodo D tambin es una hoja.
Nodo no terminal: Un nodo no terminal es aquel que posee por lo menos una
ramificacin. En el ejemplo anterior, el nodo A o el nodo B son nodos no
terminales, mientras el nodo D o el nodo C son nodos terminales.
Camino: Un rbol siempre se examina de arriba hacia abajo. Por Ejemplo:
Figura 63 Camino del rbol
146
147
Obsrvese que todos los nodos no terminales tienen sus dos hijos. El mximo
nmero de nodos que puede tener un rbol de nivel n puede representarse con la
siguiente ecuacin matemtica:
2+2+2+2...+2n
Si n es 3 entonces:
2+2+2+2 = 15
El rbol de la figura 66, es un rbol binario completo de nivel 3, donde el nmero
mximo de nodos es 15 tal como lo indica la frmula matemtica.
rbol binario Igual: Dos rboles son iguales si los dos son vacos. Existe otro caso
en el cual dos rboles son iguales:
Estos rboles son iguales porque sus races son iguales y tambin lo son su
respectivo rbol izquierdo y derecho. Para que un rbol sea igual a otro, es
necesario que el contenido de cada uno de sus respectivos nodos sea el mismo y
que tengan las mismas relaciones de parentesco.
rbol Binario Semejante: Dos rboles binarios son semejantes si tienen el
mismo nmero de nodos y los valores de los nodos del primer rbol son los
mismos que los valores de los nodos del segundo, sin importar la relacin de
parentesco entre ellos. Por ejemplo:
148
Estos rboles son semejantes. Contienen los mismos valores en cada uno de sus
nodos.
rbol Binario Isomorfo: Dos rboles binarios son isomorfos si tienen la misma
estructura aunque el contenido de cada uno de sus nodos sea diferente. Por
ejemplo los siguientes rboles son isomorfos.
Otro ejemplo de recorrido en preorden, donde sus nodos son de tipo numrico
para el siguiente rbol binario de la figura 71.
Figura 71 Resultado del recorrido en preorden del rbol
150
El resultado completo del recorrido en Inorden para el rbol de la figura 72 es: 3 5 - 7 - 10 - 11 - 12 15 Tal como se muestra en la figura.
151
Por ltimo solo queda describir la tercera forma de recorrer un rbol binario.
Recorrido en Postorden
Recorrer un rbol en Postorden consiste en primer lugar en recorrer el subrbol
izquierdo en Postorden, luego se recorre el subrbol derecho en Postorden y
finalmente se visita el nodo raz. Esto significa que para cada subrbol se debe
conservar el recorrido en Postorden, es decir, primero se visita la parte izquierda,
luego la parte derecha y por ltimo la raz.
He aqu la aplicacin con un ejemplo basado en el rbol de la figura 72:
Manos a la obra
El recorrido inicia con el subrbol izquierdo, el primer nodo a visitar es el 3 luego
se visita el 7 y posteriormente el 5 que es la raz, con esto se garantiza que el
recorrido del subrbol izquierdo se hizo en Postorden.
152
153
/
2
3
/ \
2
7
4
Sexto nmero: 8 (8 es mayor que 5 y mayor que 7) en este caso se ingresa al lado
derecho de 7.
155
5
/
3
/
7
\
\
4
3
/
2
7
\
\
4
8
\
9
Fuente: http://www.conclase.net/c/edd/index.php?cap=007
Borrar un nodo rama con intercambio de un nodo rama
Para este ejemplo se tiene otro rbol. En ste se borrar el elemento 6.
157
Fuente: http://www.conclase.net/c/edd/index.php?cap=007
1. Se localiza el nodo a borrar ('raz').
2. Se busca el nodo ms a la izquierda del rbol derecho de 'raz', en este
caso el 12, ya que el rbol derecho no tiene nodos a su izquierda, si se
opta por la rama izquierda, se estar en un caso anlogo. Al mismo
tiempo que se mantiene un puntero a 'Padre' a 'nodo'.
3. Se intercambia los elementos 6 y 12.
4. Ahora se tiene que repetir el bucle para el nodo 6 de nuevo, ya que no
es posible eliminarlo.
Figura 77 Borrado de un nodo rama con intercambio de nodo rama
Fuente: http://www.conclase.net/c/edd/index.php?cap=007
Fuente: http://www.conclase.net/c/edd/index.php?cap=007
Este modo de actuar asegura que el rbol sigue siendo ABB8.
Implementacin de un rbol binario con Punteros
Progra34.cpp
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>
#include <iostream.h>
struct arbol
{
int dato;
struct arbol *izq;
struct arbol *der;
}*raiz;
enum{ FALSO=0, VERDADERO };
/*PROTOTIPOS*/
8
159
/*Recorridos*/
void preorden( struct arbol *hoja )
{
if( !hoja ) return;
cout << hoja->dato ;
preorden( hoja->izq );
preorden( hoja->der );
}
void inorden( struct arbol *hoja )
{
if( !hoja ) return;
inorden( hoja->izq );
cout <<hoja->dato ;
inorden( hoja->der );
}
void posorden( struct arbol *hoja )
{
if( !hoja ) return;
posorden( hoja->izq );
posorden( hoja->der );
cout <<hoja->dato ;
}
/*Menus del Arbol*/
void menu_recorridos( void )
{
char _op='S';
while( _op!='4' )
{
clrscr();
cout << "1. PreOrden." ;
cout << "\n2. InOrden." ;
cout << "\n3. PosOrden." ;
cout << "\n4. Salir." ;
cout << "\n\n:: " ;
_op= getch();
switch( _op )
{
case '1':
163
preorden( raiz );
getch();
break;
case '2':
inorden( raiz );
getch();
break;
case '3':
posorden( raiz );
getch();
break;
}
}
return;
}
void menu_busquedas( void )
{
int val;
cout << "\n\nNumero: " ;
cin>> val ;
if( busqueda( raiz, val ) )
cout << "\n\nEncontrado.." ;
else cout << "\n\nError, No se encuentra." ;
getch();
}
{
cout << "\n\nEste numero ya ha sido insertado." ;
getch();
break;
}
raiz= insertar( raiz, raiz, val );
break;
case 'R':
if( vacio( raiz ) )
{
cout << "\n\nEl Arbol Aun esta Vacio." ;
getch();
break;
}
menu_recorridos();
break;
case 'B':
if( vacio( raiz ) )
{
cout << "\n\nEl Arbol Aun esta Vacio." ;
getch();
break;
}
menu_busquedas();
break;
case 'A':
if( vacio( raiz ) )
{
cout << "\n\nEl Arbol Aun esta Vacio." ;
getch();
break;
}
case 'N':
if( vacio( raiz ) )
{
cout << "\n\nEl Arbol Aun esta Vacio." ;
getch();
break;
}
menu_nodos();
break;
case 'P':
if( vacio( raiz ) )
{
cout << "\n\nEl Arbol Aun esta Vacio." ;
166
getch();
break;
}
menu_podar();
break;
}
}
cout << "\n\nPulsa para salir..." ;
getchar();
return 0;
}
El resultado despus de la compilacin y ejecucin del listado, se puede
visualizar en la figura 79 que se muestra a continuacin.
Figura 79 Salida en pantalla de progra34
#include <dos.h>
#include <conio.h>
#include <stdlib.h>
void cajadetexto_a(int x,int y,int ancho,int altura);
int iniciagrafica();
int linea_iz(int tx, int px1, int py1, int ty, int px2, int py2);
int linea_der(int tx, int px1, int py1, int ty, int px2, int py2);
int presentacion();
int ordenar();
int texto(); //para textos
int verificar(int z); //analiza cuando hijos pueden haber
main()
{
// int z;
iniciagrafica();
setbkcolor(DARKGRAY); //color de fondo de pantalla
setfillstyle(SOLID_FILL,LIGHTGRAY); //fondo de la ventana grande
bar3d(620,470,5,20,10,30);//x/y/px1/py1/an //ventana grande
presentacion();
cajadetexto_a(280,30,30,30);//px,py,largo,ancho A
outtextxy(292,42,"A");
ordenar();
getch();
}
int iniciagrafica()
{
int gdriver = DETECT, gmode, errorcode;
initgraph(&gdriver, &gmode, "c:\\tc\\bgi");
}
int ordenar()
{
int A,B,D,G,C,M,P,x;
texto(); //llama la caja de texto
outtextxy(55,388,"Cuandos hijos tiene A ");
gotoxy(31,25);
168
cin>>x;
texto();// llama caja de texto para no spbrescribir
A=verificar(x);
if(A==1 || A==2) //B
{ //comienza lado izquierdo
setcolor(5);
linea_iz(125,276,40, 55,150,39);//izquierdo entre b y a
cajadetexto_a(137,100,30,30);//px,py,largo,ancho isz 5.1 B
outtextxy(150,110,"B");
//b
if(A==2)
{
setcolor(13);
linea_der(145,307,40, 55,452,39);//izquierdo entre c y a
cajadetexto_a(439,100,30,30);//px,py,largo,ancho derecha 5.3 C
outtextxy(452,110,"C");
}
outtextxy(55,388,"Cuandos hijos tiene B ");
gotoxy(31,25);
cin>>x;
texto();// llama caja de texto para no spbrescribir
B=verificar(x);
if(B==1);
{
setcolor(5);
linea_iz(60,133,110, 75,72,109); //izquierda entre d y b
cajadetexto_a(60,190,30,30);//px,py,largo,ancho iszquierda 1 D
outtextxy(73,200,"D"); //D
}
if(B==2) //D y G
{
setcolor(5);
linea_iz(60,133,110, 75,72,109); //izquierda entre d y b
cajadetexto_a(60,190,30,30);//px,py,largo,ancho iszquierda 1 D
outtextxy(73,200,"D"); // D
setcolor(5);
linea_der(57,164,110, 75,220,109);//izquierdo entre g y b
cajadetexto_a(207,190,30,30);//px,py,largo,ancho iszquierda 2 G
169
outtextxy(220,200,"G"); //G
}
outtextxy(55,388,"Cuandos hijos tiene D ");
gotoxy(31,25);
cin>>x;
texto();// llama caja de texto para no sobrescribir
D=verificar(x);
if(D==1)//D
{
setcolor(5);
linea_iz(34,55,198, 55,22,198); //izquierda entre e y d
cajadetexto_a(10,250,30,30);//px,py,largo,ancho iszquierda 1.1 E
outtextxy(23,263,"E");
}
if(D==2) //E Y F
{
setcolor(5);
linea_iz(34,55,198, 55,22,198); //izquierda entre e y d
cajadetexto_a(10,250,30,30);//px,py,largo,ancho iszquierda 1.1 E
outtextxy(23,263,"E");
setcolor(5);
linea_der(28,87,198, 55,114,197);//izquierdo entre f y d
cajadetexto_a(100,250,30,30);//px,py,largo,ancho iszquierda 1.2 F
outtextxy(113,263,"F");
}
if(B==2)
{
outtextxy(55,388,"Cuandos hijos tiene G ");
gotoxy(31,25);
cin>>x;
texto();// llama caja de texto para no sobrescribir
G=verificar(x);
if(G==1) //H
{
setcolor(5);
linea_iz(30,203,199, 45,173,199); //izquierda entre h y g
cajadetexto_a(160,250,30,30);//px,py,largo,ancho iszquierda 2.1 H
outtextxy(173,263,"H");
setcolor(5);
170
}
if(G==2) // H y I
{
setcolor(5);
linea_iz(30,203,199, 45,173,199); //izquierda entre h y g
cajadetexto_a(160,250,30,30);//px,py,largo,ancho iszquierda 2.1 H
outtextxy(173,263,"H");
setcolor(5);
linea_der(28,234,199, 47,261,198);//izquierdo entre i y g
cajadetexto_a(250,250,30,30);//px,py,largo,ancho iszquierda 2.2 I
outtextxy(263,263,"I");
}
}
} //termina lado izquierdo
if(A==2)
{
outtextxy(55,388,"Cuandos hijos tiene C ");
gotoxy(31,25);
cin>>x;
texto();// llama caja de texto para no sobrescribir
C=verificar(x);
if(C==1)
{
setcolor(13);
linea_der(55,466,110, 75,520,109);//izquierdo entre c y p
setcolor(13);
cajadetexto_a(510,190,30,30);//px,py,largo,ancho derecha 4 P
outtextxy(522,200,"P");
}
if(C==2)
{
setcolor(13);
linea_iz(57,435,110, 75,378,109); //izquierda entre m y c
setcolor(13);
cajadetexto_a(367,190,30,30);//px,py,largo,ancho dercha 3 M
outtextxy(379,200,"M");
setcolor(13);
linea_der(55,466,110, 75,520,109);//izquierdo entre c y p
171
setcolor(13);
cajadetexto_a(510,190,30,30);//px,py,largo,ancho derecha 4 P
outtextxy(522,200,"P");
}
outtextxy(55,388,"Cuandos hijos tiene P ");
gotoxy(31,25);
cin>>x;
texto();// llama caja de texto para no sobrescribir
P=verificar(x);
if(P==1)
{
setcolor(13);
linea_der(28,537,199, 47,564,198);//izquierdo entre z y p
cajadetexto_a(550,250,30,30);//px,py,largo,ancho derecha 4.2 Z
outtextxy(563,263,"Z");
}
if(P==2)
{
setcolor(13);
linea_iz(25,506,199, 45,482,199); //izquierda entre q y p
cajadetexto_a(470,250,30,30);//px,py,largo,ancho derecha 4.1 Q
outtextxy(482,263,"Q");
setcolor(13);
linea_der(28,537,199, 47,564,198);//izquierdo entre z y p
cajadetexto_a(550,250,30,30);//px,py,largo,ancho derecha 4.2 Z
outtextxy(563,263,"Z");
}
if(C==2)
{
outtextxy(55,388,"Cuandos hijos tiene M ");
gotoxy(31,25);
cin>>x;
texto();// llama caja de texto para no sobrescribir
M=verificar(x);
if(M==1)
{
setcolor(13);
linea_iz(33,364,199, 45,332,199); //izquierda entre n y m
cajadetexto_a(320,250,30,30);//px,py,largo,ancho derecha 3.1 N
172
outtextxy(332,263,"N");
}
if(M==2)
{
setcolor(13);
linea_iz(33,364,199, 45,332,199); //izquierda entre n y m
cajadetexto_a(320,250,30,30);//px,py,largo,ancho derecha 3.1 N
outtextxy(332,263,"N");
setcolor(13);
linea_der(28,394,199, 47,422,198);//izquierdo entre o y m
cajadetexto_a(410,250,30,30);//px,py,largo,ancho derecha 3.2 O
outtextxy(422,263,"O");
}
}
} //termina A=2
}//termina funcion ordenar
void cajadetexto_a(int x,int y,int ancho,int altura)
{
setcolor(DARKGRAY);
line(x,y,x+ancho-1,y); //linea superior gris oscuro
line(x,y,x,y+altura-1);//linea inferior derecha gris oscuro
setcolor(LIGHTGRAY);
line(x+1,y+altura-1,x+ancho-1,y+altura-1); //linea inferior gris
line(x+ancho-1,y+1,x+ancho-1,y+altura-1); //linea derecha gris
setcolor(WHITE);
line(x,y+altura,x+ancho,y+altura); //linea inferior blanco externo
line(x+ancho,y,x+ancho,y+altura); //linea derescha blanco externo
setfillstyle(SOLID_FILL,9);
bar(x+1,y+1,x+ancho-2,y+altura-2); //pinta el cuadro de blanco
}
int linea_iz(int tx, int px1, int py1, int ty, int px2, int py2)
{
for(int i=1; i<tx; i++)
{
outtextxy(px1-i,py1,".");
delay(15);
}
173
cajadetexto_a(50,375,180,30);//px,py,largo,ancho A
cajadetexto_a(230,375,30,30);//px,py,largo,ancho A
}
int verificar(int z)
{
int n,d;
n=z;
while(n<=0 || n>=3)
{
outtextxy(60,386,"Dato errado, ingrese ");
outtextxy(64,393,"otro dato ");
gotoxy(31,25);
cin>>n;
texto();// llama caja de texto para no sobrescribir
}
if(n==1 || n==2)
{
return n;
}
return n;
}
Actividad de verificacin
Como actividad de verificacin, se propone que cada estudiante de forma
individual, analice el cdigo que se presenta en el anterior programa en el listado
llamado progra35, con el fin de que lo edite y lo lleve al compilador para ver la
salida en pantalla, el cual pone en prctica los conocimientos adquiridos en la
temtica de rboles binarios, en la ejecucin del programa.
175
CAPITULO 3: GRAFOS
Introduccin
Los grafos al igual que los rboles son estructuras de datos de no lineales,
semejada a una estructura de tipo jerrquico. En el presente captulo se abordan
los temas relacionados con los conceptos bsicos de grafos, incluyendo la teora
general de grafos e identificando la forma de recorrerlos. As como tambin la
documentacin de los tipos de grafos y la representacin a travs de matriz de
adyacencia y de listas de adyacencia especialmente.
Al final del captulo se propone como actividad de veririficacin un programa de
aplicacin al modo grfico de C++. Donde se evidencie la creacin del grafo, la
interaccin de los recorridos y la visualizacin del rbol en pantalla.
Leccin 11: Conceptos bsicos de grafos
Los grafos son una de las herramientas ms empleadas en matemticas,
estadstica, investigacin operativa y en numerosos campos cientficos. El estudio
de la teora de grafos se realiza fundamentalmente como elemento de Matemtica
discreta o Matemtica aplicada. El conocimiento profundo de la teora de grafos
junto con los algoritmos de implementacin es fundamental para conseguir el
mayor rendimiento de las operaciones con datos, sobre todo si stos son
complejos en su organizacin. Un programador de alto nivel no puede dejar de
conocer en toda su profundidad la teora de grafos y sus operaciones, que adems
le servir de bse para enfrentase a los cursos de investigacin de operaciones,
donde se conceptualizar de una manera matematica lo referente e este tema
La teora de grafos es una rama de la matemtica combinatoria muy til en la
solucin de muchos problemas prcticos que se formulan de manera natural por
medio de objetos y sus conexiones entre ellos (determinar el camino ms corto
entre dos ciudades, anlisis de circuitos elctricos, ordenacin de tareas).
En este captulo se hace la implementacin de los grafos como representacin
grfica como aplicacin a la fundamentacin terica. Se recomienda que se realice
por medio del entorno grfico que nos presenta el compilador de C++, de esta
manera se hace un acercamiento a la programacin orientada a objetos.
Definicin grafos
Un grafo es un objeto matemtico conformado por una coleccin de vrtices (o
nodos) y aristas que se encargan de conectar o unir los. Los vrtices son objetos
176
177
Fuente: http://www.slideshare.net/pilypardo/grafos-1407276
Fuente: http://www.slideshare.net/pilypardo/grafos-1407276
Costos: Los enlaces tanto para los grafos dirigidos como para los grafos no
dirigidos tienen un peso, costo o valor, por lo que se conocen como grafos
178
etiquetados. Para ampliar este concepto se puede visualizar la figura 83. Que se
muestra a continuacin.
Figura 83 Representacin grfica de grafos etiquetados
Fuente: http://www.slideshare.net/pilypardo/grafos-1407276
Matriz de adyacencia
Lista de adyacencia
Arreglos para listas de adyacencias
180
http://www.slideshare.net/pilypardo/grafos-1407276
Representacin por Matriz de Adyacencia
La forma ms fcil de guardar la informacin de los nodos es mediante la
utilizacin de un vector que indexe los nodos, de manera que los arcos entre los
nodos se pueden ver como relaciones entre los ndices. Esta relacin entre ndices
se puede guardar en una matriz, que llamaremos de adyacencia.
La matriz de adyacencia A de un grafo G=(V,E) tiene V*V elementos la cual se
define matemticamente como :
A[ i , j ] = {1 si (i , j) E y 0 en cualquier otro caso}
Figura 86 Representacin grfica de la matriz de adyacencia
Fuente: http://www.slideshare.net/pilypardo/grafos-1407276
Cuando se trata de grafos ponderados en lugar de 1 el valor que tomar ser el
peso de la arista. Si el grafo es no dirigido hay que asegurarse de que se marca
con un 1 (o con el
181
peso) tanto la entrada a[i][j] como la entrada a[j][i], puesto que se puede recorrer
en ambos sentidos.
int V,A;
int a[maxV][maxV];
void inicializar()
{
int i,x,y,p;
char v1,v2;
// Leer V y A
memset(a,0,sizeof(a));
for (i=1; i<=A; i++)
{
Cout <<"\n" <<v1 <<v2 <<p;
x=v1-'A'; y=v2-'A';
a[x][y]=p; a[y][x]=p;
}
}
En esta implementacin se ha supuesto que los vrtices se nombran con una letra
mayscula y no hay errores en la entrada. Evidentemente, cada problema tendr
una forma de entrada distinta y la inicializacin ser conveniente adaptarla a cada
situacin. En todo caso, esta operacin es sencilla si el nmero de nodos es
pequeo. Si, por el contrario, la entrada fuese muy grande se pueden almacenar
los nombres de nodos en un rbol binario de bsqueda o utilizar una tabla de
dispersin, asignando un entero a cada nodo, que ser el utilizado en la matriz de
adyacencia.
Como se puede apreciar, la matriz de adyacencia siempre ocupa un espacio de
V*V, es decir, depende solamente del nmero de nodos y no del de aristas, por lo
que ser til para representar grafos densos9.
182
Es fcil determinar si existe un ciclo en el grafo, solo basta con multiplicar la matriz
por ella mismo n veces hasta obtener la matriz nula (no hat ciclos) o bien una
sucesin periodica de matrices (hay ciclo).
Desventajas de la matriz de adyacencia
Se requiere un almacenamiento |v|*|v|. Es decir O(n2).
Solo al leer o examinar la matriz puede llevar un tiempo de O(n2).
Fuente: http://www.slideshare.net/pilypardo/grafos-1407276
En las listas de adyacencia lo que se haga ser guardado por cada nodo, adems
de la informacin que pueda contener el propio nodo, una lista dinmica con los
nodos a los que se puede acceder desde l. La informacin de los nodos se puede
guardar en un vector, al igual que antes, o en otra lista dinmica.
Las listas de adyacencia sern estructuras que contendrn un valor entero (el
nmero que identifica al nodo destino), as como otro entero que indica el coste en
el caso de que el grafo sea ponderado. En el ejemplo siguiente se ha utilizado una
estructura con un nodo z ficticio en la cola.
struct nodo
{
int v;
183
int p;
nodo *sig;
};
int V,A; // vrtices y aristas del grafo
struct nodo *a[maxV], *z;
void inicializar()
{
int i,x,y,peso;
char v1,v2;
struct nodo *t;
z=(struct nodo *)malloc(sizeof(struct nodo));
z->sig=z;
for (i=0; i<V; i++)
a[i]=z;
for (i=0; i<A; i++)
{
cout <<\n" <<v1<<v2<<peso;
x=v1-'A'; y=v2-'A';
t=(struct nodo *)malloc(sizeof(struct nodo));
t->v=y; t->p=peso; t->sig=a[x]; a[x]=t;
t=(struct nodo *)malloc(sizeof(struct nodo));
t->v=x; t->p=peso; t->sig=a[y]; a[y]=t;
}
}
En este caso el espacio ocupado es O(V + A), muy distinto del necesario en la
matriz de adyacencia, que era de O(V2). La representacin por listas de
adyacencia, por tanto, ser ms adecuada para grafos dispersos.
Hay que tener en cuenta un aspecto importante y es que la implementacin con
listas enlazadas determina fuertemente el tratamiento del grafo posterior. Como se
puede ver en el cdigo, los nodos se van aadiendo a las listas segn se leen las
aristas, por lo que nos encontramos que un mismo grafo con un orden distinto de
las aristas en la entrada producir listas de adyacencia diferentes y por ello el
orden en que los nodos se procesen variar.
184
insertarlo en una posicin adecuada), de manera que el algoritmo mismo diera las
soluciones ya ordenadas10.
Al igual que la matriz de adyacencia, las listas de adyacencias tambin presentan
algunas ventajas y desventajas.
Ventajas de las listas de adyacencia
La lista de adyacencia requiere un espacio proporcional a la suma del nmero de
vrtices, ms el nmero de enlaces (arcos).
Por otro lado hace buen uso de la memoria.
Se utiliza bastante cuando el nmero de enlaces es mucho menor que O(n 2).
Desventaja de las listas de adyacencia
La representacin con listas de adyacencia es que pueden llevar un tiempo O(n)
determinar si existe un arco del vrtice i al vrtice j, ya que pueden haber O(n)
vrtices en la lista de adyacencia. Para el vrtice i.
Leccin 15: Exploracin de grafos
A la hora de explorar un grafo, nos encontramos con dos mtodos distintos.
Ambos conducen al mismo destino (la exploracin de todos los vrtices o hasta
que se encuentra uno determinado), si bien el orden en que stos son "visitados"
decide radicalmente el tiempo de ejecucin de un algoritmo, como se ver
posteriormente.
En primer lugar, una forma sencilla de recorrer los vrtices es mediante una
funcin recursiva, lo que se denomina bsqueda en profundidad. La sustitucin
de la recursin (cuya base es la estructura de datos pila) mientras que el segundo
mtodo de bsqueda o recorrido, la bsqueda en amplitud o anchura lo
proporciona una cola.
10
185
Fuente: http://www.algoritmia.net/articles.php?id=18
Suponiendo que el orden en que estn almacenados los nodos en la estructura de
datos correspondiente es A-B-C-D-E-F... (el orden alfabtico), se tiene que el
orden que seguira el es destacable que el nodo D es el ltimo en explorarse en la
bsqueda en profundidad pese a ser adyacente al nodo de origen, es decir el nodo
A. Esto es debido a que primero se explora la rama del nodo C, que tambin
conduce al nodo D.
En este ejemplo hay que tener en cuenta que es fundamental el orden en que los
nodos estn almacenados en las estructuras de datos. Si, por ejemplo, el nodo D
estuviera antes que el C, en la bsqueda en profundidad se tomara primero la
rama del D (con lo que el ltimo en visitarse sera el C), y en la bsqueda en
anchura se explorara antes el H que el G.
El recorrido en profundidad sera el siguiente:
A-B-E-I-F-C-G-J-K-H-D
En un recorrido en anchura el orden sera, por contra:
A-B-C-D-E-G-H-I-J-K-F
Bsqueda en profundidad
Se implementa de forma recursiva, aunque tambin puede realizarse con una pila.
Se utiliza un array val para almacenar el orden en que fueron explorados los
vrtices. Para ello se incrementa una variable global id (inicializada a 0) cada vez
que se visita un nuevo vrtice y se almacena id en la entrada del array val
correspondiente al vrtice que se est explorando.
La siguiente funcin realiza un mximo de V (el nmero total de vrtices) llamadas
a la funcin visitar, que implementamos aqu en sus dos variantes: representacin
por matriz de adyacencia y por listas de adyacencia.
186
int id=0;
int val[V];
void buscar()
{
int k;
for (k=1; k<=V; k++)
val[k]=0;
for (k=1; k<=V; k++)
if (val[k]==0) visitar(k);
}
void visitar(int k) // matriz de adyacencia
{
int t;
val[k]=++id;
for (t=1; t<=V; t++)
if (a[k][t] && val[t]==0) visitar(t);
}
void visitar(int k) // listas de adyacencia
{
struct nodo *t;
val[k]=++id;
for (t=a[k]; t!=z; t=t->sig)
if (val[t->v]==0) visitar(t->v);
}
El resultado es que el array val contendr en su i-sima entrada el orden en el que
el vrtice i-simo fue explorado. Es decir, si tenemos un grafo con cuatro nodos y
fueron explorados en el orden 3-1-2-4, el array val quedar como sigue:
val[1]=2; // el primer nodo fue visto en segundo lugar
val[2]=3; // el segundo nodo fue visto en tercer lugar
val[3]=1; // etc.
val[4]=4;
Una modificacin que puede resultar especialmente til es la creacin de un array
"inverso" al array val que contenga los datos anteriores "al revs". Esto es, un
array en el que la entrada i-sima contiene el vrtice que se explor en isimo
lugar. Basta modificar la lnea
val[k]=++id; // sustituyndola por
val[++id]=k;
Para el orden de exploracin de ejemplo anterior los valores seran los siguientes:
val[1]=3;
val[2]=1;
187
val[3]=2;
val[4]=4;
Bsqueda en amplitud o anchura
La diferencia fundamental respecto a la bsqueda en profundidad es el cambio de
estructura de datos: una cola en lugar de una pila. En esta implementacin, la
funcin del array val y la variable id es la misma que en el mtodo anterior.
struct tcola *cola;
void visitar(int k) // listas de adyacencia
{
struct nodo *t;
encolar(&cola,k);
while (!vacia(cola))
{
desencolar(&cola,&k);
val[k]=++id;
for (t=a[k]; t!=z; t=t->sig)
{
if (val[t->v]==0)
{
encolar(&cola,t->v);
val[t->v]=-1;
}
}
}
}
Fin del programa11
Aunque las estructuras de datos no lineales tambin se pueden implementar por
medio de apuntadores, el cdigo que se presenta
corresponde a la
implementacin por medi de arreglos.
11
188
189
190
191