UNIVERSIDAD NACIONAL ABIERTA Y A DISTANCIA UNAD ESCUELA DE CIENCIAS BSICAS TECNOLOGIA E INGENIERA PROGRAMA INGENIERIA DE SISTEMAS BOGOT D.C. 2007
ISBN
TABLA DE CONTENIDO
INTRODUCCION UNIDAD 1. MEMORIA DINMICA...................................................................... 1 INTENCIONALIDADES FORMATIVAS:.............................................................. 1 PROPSITOS DE LA UNIDAD ............................................................................................ 1 OBJETIVOS DE LA UNIDAD ................................................................................................ 1 COMPETENCIAS DE LA UNIDAD: ..................................................................................... 1 METAS DE APRENDIZAJE ................................................................................................... 1 CAPTULO 1. APUNTADORES..2 1.1. CONCEPTOS BSICOS .............................................................................. 2 1.2. DECLARACIN DE APUNTADORES .......................................................... 2 1.3.VARIABLES AUTOMTICAS Y APUNTADORES......................................... 4 1.4. APUNTADORES Y CADENAS ..................................................................... 6 1.5. ARREGLOS DE APUNTADORES................................................................ 6 1.6. PASO DE ARREGLOS COMO PARMETROS ........................................... 7 1.7 PASO DE FUNCIONES COMO PARMETROS ........................................... 9 1.8. APUNTADORES A APUNTADORES ......................................................... 10 1.9. APUNTADORES Y ARREGLOS................................................................ 12 1.10. OPERACIONES CON APUNTADORES. ............................................................ 16
CAPITULO 2. GESTIN DINMICA DE MEMORIA.....18 2.1. VARIABLES ESTTICAS.19 2.2. VARIABLES DINMICAS....19
CAPTULO 3. OPERADORES NEW , DELETE Y FUNCIONES MALLOC, FREE......22 3.1 OPERADORES NEW Y DELETE....22
UNIDAD 2. ESTRUCTURAS DINMICAS LINEALES..30 OBJETIVO ............................................................................................................................... 30 COMPETENCIAS DE LA UNIDAD: .................................................................................. 30 METAS DE APRENDIZAJE ................................................................................................ 30 CAPTULO 4. PILAS...30 4.1. CONCEPTOS BSICOS.30 4.2. OPERACIONES BSICAS CON PILAS...33 4.3. IMPLEMENTACIN DE LAS ESTRUCTURAS LINEALES TIPO PILAS35 4.4 APLICACIN DE LAS ESTRUCTURAS LINEALES TIPO PILAS.45 4.5 CODIGOS DE EJEMPLOS DEL FUNCIONAMIENTO DE UNA PILA.52 4.6. ACTIVIDADES FORMATIVAS ................................................................... 58
CAPTULO 5. COLAS.59 5.1. CONCEPTOS BSICOS.59 5.2 APLICACIN DE LAS ESTRUCTURAS LINEALES TIPO COLAS...59 5.3. OPERACIONES BSICAS CON COLAS.60 5.4. IMPLEMENTACIN DE LAS COLAS POR MEDIO DE ARREGLOS..62 5.5. IMPLEMENTACIN DE LAS COLAS POR MEDIO DE PUNTEROS.71 5.5.1 REPRESENTACIN DE LAS COLAS71 5.6 CODIGOS DE EJEMPLOS DEL FUNCIONAMIENTO DE UNA PILA.76 5.7. ACTIVIDADES FORMATIVAS....80 CAPTULO 6. LISTAS.....82 6.1 CONCEPTO DE LISTAS ............................................................................. 82 6.2. LISTA SIMPLEMENTE ENLAZADA..82 6.3. OPERACIONES CON LAS LISTAS SIMPLEMENTE ENLAZADAS83 6.4.1. IMPLEMENTACIN DE LISTAS ENLAZADAS ............................................... 84 6.5. LISTAS DOBLEMENTE ENLAZADAS .................................................................... 94 6.5.1. OPERACIONES BSICAS CON LISTAS DOBLEMENTE ENLAZADAS..95 6.6. LISTAS CIRCULARES...113 6.6.1. AADIR ELEMENTO EN UNA LISTA CIRCULAR VACA114 6.6.2. AADIR ELEMENTO EN UNA LISTA CIRCULAR NO VACA.114 6.6.3. AADIR ELEMENTO EN UNA LISTA CIRCULAR, CASO GENERAL..115 6.7 ACTIVIDADES DE FORMATIVAS....115
UNIDAD 3. ESTRUCTURAS NO LINEALES. ................................................. 117 CAPTULO 7. RBOLES.....118 7.1. TEORA GENERAL DE RBOLES.........118 7.2. OPERACIONES BSICAS CON RBOLES.121 7.3. RBOLES ORDENADOS.....121 CAPTULO 8. RBOLES BINARIOS DE BSQUEDA........123 8.1. ARBOLES BINARIOS.....123 8.2. FORMA DE RECORRER UN ARBOL BINARIO....130 8.3. BOL BINARIO DE BUSQUEDA.....134 8.4. IMPLEMENTACIN DE ARBOLES BINARIOS EN MODO GRFICO..136 8.5. OPERACIONES EN ABB.......147 8.6. ACTIVIDADES FORMATIVAS.....168 CAPTULO 9. GRAFOS......170 9.1 CONCEPTOS BSICOS.....170 9.2 GRAFO DIRIGIDO (RED) .......................................................................... 172 9.3.GRAFO NO DIRIGIDO.172 9.4 GRAFO CONEXO ..................................................................................... 174 9.5 GRAFOS PONDERADOS ......................................................................... 175 9.6 MATRIZ DE ADYACENCIAS ..................................................................... 175 9.7 REPRESENTACIN DE GRAFOS...175 9.7.1 REPRESENTACIN POR MATRIZ DE ADYACENCIA....176 9.7.2 REPRESENTACIN POR LISTA DE ADYACENCIA.....176 9.8 EXPLORACIN DE GRAFOS...178
9.8.1 BSQUEDA EN PROFUNDIDAD..179 9.8.2 BSQUEDA EN AMPLITUD O ANCHURA..180 9.9 ALGORITMOS SOBRE GRAFOS............................................................. 181 9.10. CAMINO MS CORTO ........................................................................... 182 BIBLIOGRAFA....182 ANEXOS.......183
1. FICHA TECNICA
NOMBRE DEL CURSO
ESTRUCTURA DE DATOS
PALABRAS CLAVE
Computadora, Hardware, Software, Informtica, Cdigo binario, Memoria, Programacin de computadoras, Memoria dinmica, Programacin estructurada, Listas, Colas, Pilas, Lenguaje de programacin, Estructuras, Estructuras lineales, Estructuras no lineales, Variable, Constante, Apuntadores, Algoritmos, Funciones, Arreglos, cadenas, Arboles, Grafos, Recorridos, Paso de parmetros. UNIVERSIDAD NACIONAL ABIERTA DISTANCIA UNAD SANTA FE DE BOGOT HERMES MOSQUERA ANGULO hermes.mosquera@unad.edu.co DEL hhmosquera@gmail.com Autor de la primera Versin: IVAN ARTURO LOPEZ Ivan.lopezortiz@gmail.com Y A
INSTITUCION CIUDAD
AO UNIDAD ACADEMICA CAMPO FORMACION AREA CONOCIMIENTO CREDITOS ACADEMICOS TIPO DE CURSO DESTINATARIOS COMPETENCIA GENERAL APRENDIZAJE METODOLOGIA OFERTA FORMATO CIRCULACION DE DE
El estudiante se inicia en los fundamentos esenciales de DE las tcnicas y destrezas del diseo, anlisis, construccin y aplicacin de las estructuras dinmicas. DE A DISTANCIA DE Documentos impresos y digitales, CD-ROM con
apoyo en la Web.
DENOMINACION DE 1. Memoria Dinmica. LAS UNIDADES 2. Estructuras Dinmicas Lneales. DIDACTICAS 3. Estructuras No Lineales
PLANIFICACIN DE LAS UNIDADES DIDCTICAS. Unidades didcticas, captulos, temas, secciones, fragmentos
Unidades Didcticas Captulos Temas Conceptos Bsicos Operaciones con apuntadores Aritmtica de Apuntadores Conceptos de memoria Uso de la Memoria Dinmica Asignacin con tamao conocido y desconocido Conceptos Bsicos Recorridos Operaciones con Pilas Conceptos Bsicos Recorridos Operaciones con Colas Lineales Enlazadas Circulares Doblemente enlazadas Conceptos Bsicos Representacin Teora Recorridos Aplicacin Teora Recorridos Aplicacin Secciones Aplicacin Apuntadores de
1. Apuntadores
1. Memoria Dinmica
2.Gestin dinmica de memora 3.Operadores new y delete. Funciones Malloc y Free. 4. Pilas
Aplicaciones
Reglas de funcionamiento de new y delete Recorridos,y operaciones de Insercin, visualizacin y Eliminacin Recorridos,y operaciones de Insercin, visualizacin y Eliminacin Recorridos,y operaciones de Insercin, visualizacin y Eliminacin Aplicaciones Recorridos Recorridos
5.Colas
6.Listas
INTRODUCCION
El curso de estructura de datos cobra vital importancia y al cual se le puede sacar el mximo provecho, puesto que los participantes tienen conocimientos previos fuertes, que vienen de los cursos anterior (Algoritmos e Introduccin a la programacin), en este modulo se incluir un pequeo apartado al retomar conceptos bsicos este modulo incia con los fundamentos bsicos de Apuntadores y Asignacin dinamica de memoria, que de una u otra manera se trabajo en el curso de introduccin a la programacin, pero que es vital para que el estudiante retome los conocimientos necesarios para encarar este temario, un poco ms adelante profundisaremos en temas como estructuras dinamicas lineales, donde veremos temas como pilas, colas, listas, listas enlazadas, entre otros, como vemos estos temas sern nuevos para el estudiante, por lo cual se pide mucho cuidado en su aplicabilidad, son temas importantes los rboles y grafos, que permitiran ahondar o introducir al mundo de la programacin orientada a objetos. Para terminar, solo resta decir que este modulo esta construido, con base en una recopilacin terica y de ejercicios prcticos, de diferentes autores, sitios web que se incluirn en la amplia bibliografa, esta informacin llevara al estudiante a un aprendizaje significativo. Se reiterera la invitacin a que consulten diversidad de textos que existen con referencia a los temas que se trabajan en este modulo.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
Captulo 1. Apuntadores
Para entender 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, y 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. 1.1. Conceptos bsicos 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 objeto: un char, un int, un float, un array, una estructura, una funcin u otro puntero. Seremos nosotros 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 lenguje C/C++. 1.2. Declaracin de apuntadores Los apuntadores son variables automticas cuyos valores representan direcciones de memoria correspondientes a otras variables. La sintxis para la declaracin de un apuntador es la siguiente: tipo * identificador ; Ejemplo: int *apunt; // Declaracin del apuntador apunt // Se dice que : "apunt va a apuntar a // variables de tipo int"
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas donde: apunt es el nombre del apuntador y (*) es el operador de indireccin En el ejemplo anterior, puede decirse que: *apunt se refiere al objeto apuntado por apunt . apunt es un apuntador a objetos de tipo int
Obsrve 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 *p, *q; a es un apuntador de tipo entero. c es un apuntador de tipo carcter. p y q son apuntadores de tipo real doble precisin.
Los operadores utilizados para trabajar variables apuntadores son el ( * ) asterisco llamado operador de indireccin, y el ( & ) ampersand, llamado operador de direccin.
Recordemos su utilizacin en el siguiente grupo de instrucciones: Vamos un ejemplo Listado 1.1 #include <iostream.h> #include <conio.h> void main(void) { int x, y; int *p, *q; p = &x; q = &y; *p = 10; *q = *p * 2; y = y + *p; cout<<*p; cout<<,*q; getch(); }
Define x, y variables enteras. Define p y q variables tipo apuntador. asigna a p la direccin de x. (p apunta a x). asigna a q la direccin de y. (q apunta a y). almacena en x el valor 10. almacena en y el valor de x multiplicado por 2 (20). a la variable y le suma el valor en x (20+10). imprime el contenido de x (10). imprime el contenido de y (30).
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 1.3. Variables automticas y apuntadores
Las variables automticas se crean en tiempo de compilacin y se destruyen al terminar la ejecucin del mdulo donde fueron declaradas. Aunque no es estrictamente necesario, se pueden manejar las variables automticas por medio de apuntadores, vamos un ejemplo. Listado 1.2 #include <iostream.h> #include <conio.h> void main() { int automatica ; // Se declara la variable automatica. int *apunt ; // Se declara el apuntador apunt, que apun// tar a objetos de tipo int. automatica = 100 ; // Se asigna el valor 100 a la variable // automatica. apunt = &automatica ; // Se asigna a apunt la direccin de // automatica apunt apunta a // automatica. clrscr(); cout << "VALOR=" << automatica << " \n"; // 100 *apunt="200" ; // Se asigna el valor 200 al objeto apuntado- // por apunt. cout << "VALOR=" << automatica << " \n"; // 200 getch();
Las instrucciones del listado 1.3, se traducen en la siguiente secuencia, donde los apuntadores se representan con una flecha (para simular que "apuntan hacia" "sealan" un objeto) y los objetos apuntados se representan por un cuadro (para simular un recipiente). INSTRUCCION int automatica ; int *apunt ; automatica = 100 ; REPRESENTACION GRAFICA automatica ----> ? automatica 100 ?
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas apunt = &automatica ; apunt ----> *apunt = 200 ; apunt ----> automatica, *apunt 100
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. Al declarar un apuntador, se est especificando el tipo de variable al que va a apuntar. Por ejemplo, no podr declararse un apuntador a objetos de tipo int y despus intentar utilizarlo para apuntar a objetos de tipo float. Cuando se desee manejar un apuntador a cualquier tipo de objeto, se puede declarar de tipo void, como en: void *multiusos ; En el listado 1.3 se muestra un ejemplo de aplicacin de un apuntador de tipo void. #include <iostream.h> #include <conio.h> #define NL cout << "\n"; void main() { int varent="0" ; float varflot="0.0" ; void *apmulti="&varent; // apmulti APUNTA A varent *(int *)apmulti="2" ; // ASIGNA 2 AL OBJETO NL; // APUNTADO POR apmulti cout << varent ; apmulti="&varflot" ; // apmulti APUNTA A varflot *(float *)apmulti="1.1" ; // ASIGNA 1.1 AL OBJETO APUNTADO // POR apvoid NL;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas cout << varflot ; NL; getch();
Del listado 1.3, analicemos la instruccin: *(int *)apmulti = 2 ; en donde: apmulti es un apuntador de tipo void. (int *)apmulti est forzando a que apmulti apunte a objetos de tipo int. *(int *)apmulti se refiere a un objeto de tipo entero apuntado por apmulti.
1.4. Apuntadores y cadenas Una cadena es un arreglo de caracteres cuyo ltimo elemento es el caracter nulo. Utilizando la nomenclatura de arreglos, podemos declarar: char nombre[ ] = "COMERCIO" ; Esto mismo puede hacerse por medio de apuntadores, como se muestra en siguiente ejemplo. Listado 1.4 #include <iostream.h> #include <conio.h> #include <stdio.h> void main() { char *nombre = "COMERCIO" ; clrscr(); gotoxy(30,12); cout<< "!! HOLA, " ; puts(nombre); gotoxy(43,12); cout << " !!"; getch(); } 1.5. Arreglos de apuntadores
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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. El programa completo para el manejo de este ejemplo. Listado 1.5 #include <iostream.h> #include <conio.h> #include <string.h> void main() { char *nombres[ ] = { "HUGO", "PACO", "LUIS" } ; char invitado[11]; int bandera; clrscr(); gotoxy(30,10); cout << "CUAL ES SU NOMBRE ? " ; gotoxy(50,10); cin>> invitado ; gotoxy(30,12); for( int x = 0 ; x <3 ; x++ ) if(strcmp(invitado, nombres[x])="=" 0) bandera="0;" if(bandera="=" 0) cout << "!! PASE, ESTIMADO " << invitado << " !!"; else cout << "!! FUERA DE AQUI, " << invitado << " !!"; getch();
1.6. Paso de arreglos como parmetros Un arreglo puede pasarse como parmetro a una funcin. Si tuviera que pasarse por valor un arreglo muy grande, sera un desperdicio de memoria. En el Lenguaje C++ el paso de arreglos se hace por referencia, ya que el nombre del arreglo corresponde a un apuntador al primer elemento del arreglo. Al pasar un parmetro correspondiente a un arreglo, se pasa la direccin del primer elemento, por lo que la funcin invocada puede modificar cualquier elemento del arreglo. El siguiente programa maneja una funcin llamada nputs(), la cual recibe como parmetro un arreglo de caracteres.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Listado 1.6
#include <iostream.h> #include <conio.h> #include <stdio.h> #include <string.h> void nputs(char *); void main() { char cadena[81]; clrscr(); gotoxy(10,10); cout << "ESCRIBA UNA CADENA: "; gets(cadena); gotoxy(10,12); nputs(cadena); getch(); } void nputs(char cad[ ]) { int x="0;" while(cad[x]) { cout << cad[x] ; x++; } }
En el siguiente listado se muestra el manejo de la funcin nputs(), por medio de apuntadores. #include <iostream.h> #include <conio.h> #include <stdio.h> #include <string.h> void nputs(char *); void main() { char cadena[81]; clrscr(); gotoxy(10,10); cout << "ESCRIBA UNA CADENA: "; gets(cadena); gotoxy(10,12); nputs(cadena); getch(); } void nputs(char *cad) { while(*cad) cout << *cad++ ; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 1.7 Paso de funciones como parmetros
Toda funcin tiene asociada una direccin de inicio de cdigo, la cual puede pasarse un apuntador como parmetro en la invocacin a otra funcin. Veamos un ejemplo de paso de punteros como parmetros a funciones. Listado 1.7 #include <iostream.h> #include <string.h> #include <conio.h> int cmpcad(char*, char*); void compara(char*, char*, int(*)(char*, char*)); void main() { char cadx[80], cady[80]; clrscr(); gotoxy(10,5); cout << "ESCRIBA UNA CADENA : " ; cin>> cadx; gotoxy(10,7); cout << "ESCRIBA OTRA CADENA : " ; cin>> cady; gotoxy(10,9); compara(cadx, cady, cmpcad); gotoxy(1,24);
} void compara(char *cad1, char *cad2, int (*cmpcad)(char*, char*)) { if(!(*cmpcad)(cad1,cad2)) cout << "LAS CADENAS SON IGUALES"; else cout << "LAS CADENAS SON DISTINTAS"; } int cmpcad(char *x, char *y) { return(strcmp(x,y)); }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
10
Expliquemos 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 . 1.8. Apuntadores a apuntadores Como se vi al principio de la unidad, un apuntador tambin es una variable. Su direccin puede ser almacenada por otra variable apuntador, por lo que puede hablarse de un apuntador a un apuntador. Esto puede extrapolarse para dos o ms variables, como se observa en el ejemplo siguiente de apuntadores a apuntadores. Listado 1.8 #include <iostream.h> #include <conio.h> void main() { int x, *a, **b, ***c ; // 1 clrscr(); a = &x ; // 2 *a = 100 ; // 3 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(); } Explicando las lneas marcadas en el listado anterior se tiene. int x, *a, **b, ***c; // 1 Se declaran: x como una variable de tipo entero. a como un apuntador a objetos de tipo entero. b como un apuntador a un apuntador, el cual a su vez apuntar a objetos de tipo entero. Se dice que b es "el apuntador del apuntador". c como un apuntador a un apuntador que apunta a otro apuntador, el cual a su vez
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
11
apunta a objetos de tipo entero. Se dice que c es "el apuntador del apuntador del apuntador". La pila lucira as:
*a = 100 ; // 3 Al objeto apuntado por a se le asigna el valor 100. La pila lucira as:
**b += *a ; // 5 Al objeto apuntado por el apuntador apuntado por b se le suma el valor del objeto apuntado por a. La pila lucira as:
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
12
***c += **b + *a ; // 7 Se asigna al objeto apuntado por el apuntador apuntado por el apuntador c, el valor del objeto apuntado por el apuntador apuntado por el apuntador b ms el valor del objeto apuntado por el apuntador a. La pila lucira as:
El tema de los arreglos est ntimamente ligado al de apuntadores; tanto que es posible intercambiarlos en la solucin de un problema. El nombre de un arreglo corresponde al de un apuntador que almacena un valor constante. Este valor constante es la direccin de memoria del primer elemento del arreglo. Por ejemplo :
int calif[ ]={100,90,95,80,90}; // Declaracin e inicializacin de un arreglo de 5 // enteros.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
13
En realidad, el lenguaje manejar al arreglo a travs de un apuntador llamado calif, el cual tiene almacenado el valor 65494, que a su vez corresponde a la direccin de inicio del elemento calif[0]. La representacin del apuntador calif, en la zona de variables globales de la memoria RAM, es la siguiente :
En el listado 1.9.1 se presenta el manejo del arreglo calif[ ], a travs de la notacin de arreglos, y en el listado 1.9.2 el manejo con la notacin de apuntadores.
Manejo de calif[ ] , notacin de arreglos Listado 1.9.1 #include <iostream.h> void main() { int calif[ ] = { 100,90,95,80,90}; for(int i=0 ; i <5 ; i++) //Notacin de arreglos. cout << "\n" << calif[i] ;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Manejo de calif[ ] , notacin de apuntadores. Listado 1.9.2 #include <iostream.h> void main() { int calif[ ] = { 100,90,95,80,90}; for(int i=0 ; i <5 ; i++) // Notacin de apuntadores cout << "\n" << *(calif+i) ;
14
Como puede observarse, la nica diferencia entre los listados 1.9.1 y 1.9.2 es que el primero utiliza calif[i] y el segundo *(calif+i). Debido a que la ejecucin de los programas de ambos listados producen resultados iguales, se deduce que:
calif[i] == *(calif+i)
Para entender esto que a simple vista no es obvio, revisaremos algunos conceptos: 1. El nombre del arreglo corresponde al de un apuntador que apunta al primer elemento del arreglo, por lo que:
calif apunta a calif[0]
Visto grficamente :
2. Para hacer referencia a un elemento especfico del arreglo, se toma como base la direccin del primer elemento y, con el subndice del elemento especfico, se calcula su direccin. Por ejemplo, para referirse al segundo elemento del arreglo puede procederse as : calif[1] // Notacin de arreglos *(calif+1) // Notacin de apuntadores, donde la expresin calif+1sirve para calcular la direccin del elemento que est una posicin ms all del elemento apuntado por calif.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Para referirse a calif[2] ( tercer elemento ), puede escribirse: *(calif+2)
15
Lo que significa: "El objeto que se encuentra dos posiciones despus del objeto apuntado por calif". En este caso, una posicin es el espacio requerido por cada uno de los elementos, de tal manera que, si calif apunta a la direccin 65494, entonces calif+2 es la expresin que calcula la direccin 65498. La figura muestra los elementos del arreglo calif[ ] con sus nombres en notacin de arreglos y en notacin de apuntadores.
De lo anterior, se infiere la regla: calif[i] == *(calif+i) por lo que: &calif[i] == calif+i Esto es que, la direccin del i-simo elemento de un arreglo se calcula sumndole el subndice a la direccin del primer elemento. Como otro ejemplo, supongamos la siguiente declaracin correspondiente a un arreglo de 10 elementos de tipo float. float* sueldo[10]; Si la direccin del primer elemento es 65494, entonces: &sueldo[5] es igual a : sueldo+5 = 65494 + ( 5 * 4 ) = 65514 Como regla, podemos establecer que el subndice se refiere a la posicin del elemento en el arreglo. Es por esto que al calcular la direccin por medio del subndice, ste debe multiplicarse por el nmero de bytes que representan el tamao de cada elemento (dado por el tipo utilizado en la declaracin del arreglo).
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 1.10. Operaciones con apuntadores Se pueden realizar asignaciones entre punteros. int a = 15; int *p, *q; q = &a; p = q; cout<<p;
16
Se pueden operar solamente el +, el -, el ++ y el --. Int p; p = p + 1; p = p 2; p++; p--; p avanza un entero. p retrocede dos enteros. p apunta al siguiente entero. p apunta al entero anterior.
Los punteros se pueden comparar. int a; int *b, *c; if (b + n > c) b = b +2;
Ejemplo realizar un ejercicio que emplee los operadores & y * #include <iostream.h> #include <conio.h> int main() { clrscr(); int a; //a es un puntero int * ap; //ap es un apuntador a un puntero a = 7; ap= & a; //ap toma la direccin de a cout <<"la direccin de a es " <<&a; cout<<" \n el Valor de ap es " << ap; cout <<"\n el valor de a es" <<a; cout<<"\n el valor de *ap es " << *ap; cout<<"\n\n\n Mostrando los valores de * y &" ; cout <<"\n &* ap = " <<&*ap; cout <<"\n *& ap = " << *≈ getch(); return 0;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas }
17
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
18
La RAM en la computadora est organizada en forma secuencial, un byte tras otro. Cada byte de memoria tiene una direccin nica mediante la cual es identificado, una direccin que tambin lo distingue de todos los otros bytes de la memoria. Las direcciones son asignadas a la memoria en orden, comenzando en 0 y aumentando hasta llegar al lmite del sistema. Para qu se usa la memoria RAM de la computadora?. Tiene varios usos, pero solamente uno, el almacenamiento de datos, le interesa al programador. Los datos significan la informacin con la cual trabaja un programa. Ya sea que el programa est trabajando con una lista de direcciones, monitoreando la bolsa
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
19
de valores, manejando un presupuesto o cualquier otra cosa, la informacin (nombres, precios de acciones, gastos) es guardada en la RAM de la computadora mientras el programa est ejecutando. Hasta el momento, la mayoria de los programas los hemos realizado definiendo variables, sin preocuparnos de que se realiza intermaente en el computador, muchas veces en forma indiscriminada, es decir sin una verdadera depuracin, pero existen ocaciones en que no sabemos cuanta memora necesitaresmos para ejecucin de determinado programa, por ejemplo si deseamos realizar un procesador de textos, no sabemos cual va hacer la longitud del texto. Por eso a veces es necesario poder reservar memoria segn se va necesitando. Adems de esta forma nuestros programas aprovecharn mejor la memoria del computador en el que se ejecuten, usando slo los recursos necesarios. Realmente la utilidad de asignacin dinamica de memoria ser aplicada en gran medidad en los capitulos relacionasdos con las estructuras lineales. Deacurdo a lo anterior podemos definir dos tipos de variables: estticas y dinmicas. 2.1. Variables estticas Las variables estticas como recordamos en los inicios de los fundamentos de programacin, son aquellas que el programador les asigna memoria antes de la ejecucin del programa o de una funcin, las variables estaticas se llaman mediante el nombre de la misma, que ha sido declarado por el programador. 2.2. Variables dinmicas Las variables dinmicas deben su nombre al hecho de que pueden ser creadas y destruidas durante el tiempo de ejecucin de un mdulo. Para el manejo de variables dinmicas se hace indispensable la utilizacin de apuntadores, as como de funciones especiales para la asignacin y liberacin de la memoria correspondiente a dichas variables. En el lenguaje C existen entre otras las funciones Malloc() y Free() para la asignacin y liberacin de memoria dinmicamente respectivamente.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 2.3. Crear y liberar espacios de memoria
20
Cuando se ejecuta un programa, el sistema operativo reserva una zona de memoria para el cdigo o instrucciones del programa y otra para las variables que se usan durante la ejecucin. A menudo estas zonas son la misma zona, es lo que se llama memoria local. Tambin hay otras zonas de memoria, como la pila, que se usa, entre otras cosas, para intercambiar datos entre funciones. El resto, la memoria que no se usa por ningn programa es lo que se conoce como "heap" o montn. Cuando nuestro programa 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. Profundizando un paco en la asignacin dinmica, encontramos el operador Ziseof, 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 ziseof ennuna funcin con el proposito de determinar el tamao en byts de un parmetro. Listado 2.3 #include <iostream.h> #include <conio.h> void main() { char c; short s; int i; long l; float f; double d; long double ld; int arreglo[20], * pt = arreglo; clrscr(); gotoxy(20,2); cout<<"valores utilizando size of para cada una de la varibles \n\n"; cout<<" variable c = " <<sizeof c; cout<<"\t tipo char = " <<sizeof (char); cout<<"\n variable s = " <<sizeof s; 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); cout<<"\n variable f = " <<sizeof i;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas cout<<"\t tipo float = " <<sizeof (float); cout<<"\n variable d = " <<sizeof d; cout<<"\t tipo double = " <<sizeof (double); cout<<"\n variable ld = " <<sizeof ld; cout<<"\t tipo int = " <<sizeof (long double); cout<<"\n variable i = " <<sizeof i; cout<<"\t tipo int = " <<sizeof (int); getch(); return 0;
21
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
22
3.1 Operadores New y Delete El lenguaje C++ cuenta con dos operadores interconstruidos, ellos son: New y Delete, de tal manera que no se requiere incluir ningn archivo de cabecera para utilizarlos. New que realiza una labor parecida a la de la funcin malloc(), asignando un bloque de memoria. Delete que libera un bloque de memoria asignada en tiempo de ejecucin, de manera semejante a como lo hace 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 de memoria, con tamao deacurdo al tipo de datos (recordemos la funcin sizeof), si este espacio esta disponible, la operacin regresa la direccin real que se otorga, en caso de no haber espacio regresa el balor de NULL (0), La sintaxis para el uso del operador delete es: delete apuntador; 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 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. No os fiis de lo que diga el compilador, de que estas variables se liberan solas al terminar el programa, no siempre es verdad. Veamos un ejemplo de utilizacin de estos operadores: Listado 3.0 # include <iostream.h>
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas main() { int index, *point1, *point2;
23
point1 = &index; *point1 = 77; point2 = new int; *point2 = 173; 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; c_point = new char; delete c_point; c_point = new char [sizeof(int) + 133]; delete c_point;
El resultado de la ejecucin del listado 3.0 es: Los valores son 77 77 173 Los valores son 77 999 999
En las primeras lneas del programa, se hace uso de los punteros tal y como se hacen tambien en C.
point2 ilustra el uso del operador new. Este operador requiere un modificador que debe ser un tipo. La parte new int significa que se crea un nuevo entero en la memoria, y devuelve la localizacin del entero creado. Esta localizacin es asignada a point2. La siguiente lnea asigna 173 al entero al que apunta point2. Es importante distinguir entre point2, la localizacin del entero, y *point2, el entero. El puntero point2 apunta
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
24
ahora a una variable entera que se ha reservado dinmicamente, y que puede utilizarse de igual forma que se haca en C. Como ejemplo, se imprime el valor al que apunta.
A continuacin, se reserva memoria para una nueva variable, y point2 se refiere a la misma variable reservada dinmicamente a la que apunta point1. En este caso, la referencia a la variable a la que point2 apuntaba previamente se ha perdido, y nunca podr ser utilizada o su memoria liberada. Slo cuando se vuelva al sistema operativo se liberar la memoria que ocupaba. Por tanto, no debe utilizarse.
Ya que el puntero point1 en s no ha cambiado, apunta realmente al dato original. Este dato podra referenciarse otra vez utilizando point1, pero no es una buena prctica de programacin, ya que no hay garanta de lo que el sistema pueda hacer con el puntero o el dato. La localizacin del dato queda libre para ser reservada en una llamada subsiguiente, y ser pronto reutilizada en cualquier programa.
Ya que el operador delete est definido para no hacer nada si se le pasa un valor NULL, se puede liberar la memoria ocupada por un dato al que apunta un puntero NULL, ya que realmente no se est haciendo nada. El operador delete slo puede utilizarse para liberar memoria reservada con el operador new. Si se usa delete con cualquier otro tipo de dato, la operacin no est definida, y por tanto nada sucede.
En el programa tambin declaramos algunas variables reales, y se realizan operaciones similares a las anteriores. De nuevo esto ilustra que en C++ las variables no tienen que ser declaradas al comienzo de cada bloque. Una declaracin es una sentencia ejecutable y puede entonces aparecer en cualquier lugar en la lista de sentencias ejecutables.
Finalmente, ya que el operador new requiere un tipo para determinar el tamao de un bloque dinmicamente reservado, se muestra cmo reservar un bloque de tamao arbitrario. Esto es posible utilizando la construccon de las ltimas lneas del programa, donde un bloque de 37 caracteres de tamao (37 bytes) es reservado. Un bloque de 133 bytes mayor que el tamao de un entero se reserva posteriormente. Por tanto, el operador new se puede utilizar con la misma flexibilidad de la funcin malloc() de C.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
25
Cuando los datos reservados dinmicamente son borrados con delete, todava quedan en memoria. Si repetimos la instruccin cout inmediatamente despus de utilizar delete, veremos que todava se conservan los valores. Si la repetimos de nuevo antes de dejar el programa, cuando el espacio que ocupaban debe haber sido sobreescrito, veremos que ya no es as. Incluso aunque el compilador nos d los nmeros correctos, no es una buena prctica pensar que esos datos estn ah todava, porque en un programa dinmico largo la memoria se usar continuadamente.
Las funciones estndar utilizadas en C para manejo dinmico de memoria, malloc(), calloc() y free(), tambin se pueden utilizar en C++ de la misma forma que en C. Los operadores new y delete no deben mezclarse con estas funciones, ya que los resultados pueden ser impredecibles. Si se est partiendo de cdigo C, lo mejor es continuar utilizando las funciones en las nuevas lneas de programa. Si no es as, se deben utilizar los nuevos operadores, ya que se han construido como parte del lenguaje en s, ms que aadirse, y por tanto son ms eficientes.
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;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
26
// de 2 bytes para manejarlo por medio de apent. *apent = 10 ; // Asigna el valor 10 al objeto apuntado por apent. cout << *apent ; // Despliega el contenido del objeto apuntado por apent. delete apent ; // Libera el espacio de memoria manejado por apent.
En el programa del listado 3.1, se supone que la reservacin ser exitosa porque existe espacio suficiente en el montculo. 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 3.2 se propone una nueva versin del programa. Listado 3.2 #include <iostream.h> #include <stdlib.h> // Para exit(). void main() { int *apent; // Declara un apuntador a entero if((apent = new int)==NULL)//Intenta reservar un bloque de memoria dinmica { // de 2 bytes por medio de apent. cout << "NO hay espacio suficiente\n"; exit(1); // Finaliza la ejecucin del programa. } *apent="10" ; // Asigna el valor 10 al objeto apuntado por apent. cout << *apent ; // Despliega el contenido del objeto apuntado por apent. delete apent ; // Libera el espacio de memoria manejado por apent.
Para crear un arreglo de 25 elementos de tipo double, en el montculo, puede escribirse: Double *dap ; dap = new double[25]; su forma equivalente: double *dap = new double[25]; En este ejemplo, se est declarando a dap como un apuntador a variables dinmicas de tipo doble; al tiempo que se le asigna el valor retornado por new. El valor retornado por new es la direccin del inicio de un bloque de memoria del tamao requerido para almacenar 25 elementos de tipo double. En caso de que el montculo no disponga del espacio requerido, new retorna el valor NULL ( nulo ).
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 3.2. Funciones Malloc() y Free()
27
Malloc() es una de las funciones de asignacin de memoria del lenguaje de programacin C (acrnimo de memory allocation). Cuando se usa malloc () se pasa la cantidad de bytes de memoria que se necesita. Malloc () encuentra y reserva un bloque de memora del tamao pedido y regresa la direccin del primer byte del bloque. No hay de que preocuparse sobre que parte de memoria se usa, ya que esto es manejado automticamente. La funcin malloc () regresa una direccin, y su tipo de retorno es un apuntador a tipo void. Por qu void?. Un apuntador a tipo void es compatible con todos los tipos de datos. Como la memoria asignada por malloc () puede ser usada para guardar cualquiera de los tipos de datos de C, es adecuado el tipo de retorno void. Free() Al igual que malloc () free () es una funcin del lenguaje de programacin C, utilizado para liberar la memoria asignada por malloc (). Al usar la funcin free () se debe tener en cuenta la regla de oro explicada en el apartado del operador delete toda la memoria que se reserve durante el programa hay que liberarla antes de salir del programa Al usar las funciones malloc () y free () se debe incluir el archivo de encabezado STDLIB.H Veamos unos de ejemplos de aplicacin. Ejemplo 1 // asigna memoria para un arreglo de 50 enteros Int *nmeros; Nmeros = (int * ) malloc (50 * sizeof (int)); Ejemplo 2 // asigna memoria para un arreglo de 10 valores float float *nmeros; Nmeros = (float * ) malloc (10 * sizeof (float));
Listado 3.2. /* Programa de asignacion de memoria Por medio de la funcin(MALLOC Y FREE)*/ #include <conio.h> #include <stdlib.h> #include <stdio.h>
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas void main() { clrscr(); int *p==NULL; int nbytes=100; p=(int *)malloc(nbytes); if(p=NULL) { cout<<"Insuficiente espacio en memoria\n"); return -1; } cout<<"se han asignado %d bytes de memoria\n", nbytes); free(p); getch(); }
28
El resultado del programa muestra un mensaje en pantalla confirmando que se realiz la asignacin dinmica de memoria con xito. Ahora vemos otro ejemplo de aplicacin de la asignacin dinmica de memoria utilizando las funciones malloc () y free (), con un ingrediente adicional el uso de una estructura llamada persona que nos permita almacenar el registro de una persona, dos tipos de datos diferentes, un dato de tipo carcter que almacena el nombre de la persona y otro dato de tipo entero para almacenar la edad. Listado 3.3. // Listado de libreras o archives de cabecera #include<iostream.h> #include<stdlib.h> #include<conio.h> // Definicin de la funcin principal void main() { clrscr(); int n, i; // Definicin de la estructura persona struct persona { char nombre[20]; int edad; }; // Definicin del puntero p de tipo persona utilizado para reservar memoria persona *p;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
29
cout<<"PROGRAMA QUE GUARDA EL REGISTRO DE PERSONAS"<<"\n"; cout<<"\nNUMERO DE PERSONAS A INGRESAR : "; cin>>n; // Reserva de memoria dinmica a travs de malloc () p =(persona *)malloc(sizeof(persona)); // El ciclo for usado para la entrada de los datos de la persona for(i=1;i<=n;i++) { cout<<"\nDIGITE EL NOMBRE " << i <<" : "; cin>>p[i].nombre; cout<<"DIGITE LA EDAD : "; cin>>p[i].edad; cout<<"\n"; } 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); } La siguiente imagen muestra el resultado de la impresin del listado 3.3 que registra el nombre y la edad de 3 tres personas.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
30
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
31
Captulo 4. Pilas
4.1. Conceptos bsicos Una pila (stack) es un tipo especial de lista lineal en la que la insercin y borrado de nuevos elementos se realiza slo por un extremo que se denomina cima o tope (top). 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 gatos, etc, como se muestra en la imagen.
Una pila, a un 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. La posicin final la llamamos cima o tambin cabeza de la pila; para darnos una mejor representacin (abstraccin) de ella su representacin grfica en el papel la hacemos en forma vertical, con la cima en la parte de arriba. De esta forma cuando aadamos 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 coloque en orden uno encima de otro. Debido a esto ltimo 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). 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. Las operaciones bsicas de una pila son la insercin la eliminacin y visualizacin, y sern implementadas por medio de punteros y sobre la estructura de datos arreglo unidimensional.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
32
Una Pila es una estructura de datos que almacena elementos de un tipo determinado, que sigue la poltica de que el primer elemento que se extrae (se desapila) es el ltimo que se introdujo (se apil), primero en salir, ultimo en entrar (LIFO).
En principio, la pila est vaca y el puntero de la pila o CIMA est en cero. Al meter un elemento en la pila, se incrementa el puntero en una unidad. Al sacar un elemento de la pila se decrementa en una unidad el puntero. Siendo P el puntero (*P) Al manipular una pila se deben realizar algunas comprobaciones. En una pila vaca no se pueden sacar datos (P = 0). Idealmente, una pila puede contener un nmero ilimitado de elementos y no producir nunca desbordamiento. En la prctica, el espacio de almacenamiento disponible es finito (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. Para trabajar fcilmente con pilas, es conveniente disear funciones o subprogramas de insertar (push) y extraer (pop) elementos. Tambin es necesario con frecuencia comprobar si la pila est vaca; si el puntero =NULL La manipulacin de una pila mediante punteros, se deben disear los siguientes procedimientos que se pueden realizar a travs de funciones como: Consultar(...), Meter(...), Sacar(...), Inicializar(...) Se enumeran los pasos algortmicamente, Los elementos se incorporan siempre por un extremo, cima. Y auxi son declarados punteros.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 1. Cima apunta al ltimo elemento de la pila. 2. Reservar(auxi) 3. Introducimos la informacin en auxi elemento 4. Hacemos que auxi cima apunte a donde cima 5. Cambiamos cima para que apunte a donde lo hace auxi 6. La pila tiene un elemento ms
33
Los elementos se recuperan en orden inverso a como fueron introducidos. 1. Cima apunta al ltimo elemento de la pila. 2. Hacemos que auxi apunte a donde apuntaba cima 3. Hacemos que cima pase a puntar a donde cima cima 4. Liberar(auxi) 5. La pila tiene un elemento menos Una pila es un tipo especial de lista abierta en la que slo se pueden insertar y eliminar nodos en uno de los extremos de la lista. Estas caractersticas implican un comportamiento de lista LIFO (Last In First Out), el ltimo en entrar es el primero en salir. El smil del que deriva el nombre de la estructura es una pila de platos. Slo es posible aadir platos en la parte superior de la pila, y slo pueden tomarse del mismo extremo. El nodo tpico para construir pilas es a travs de las structuras. struct pila { int dato; struct pila *siguiente; }; 4.2. Operaciones bsicas con pilas: Las pilas tienen un conjunto de operaciones muy limitado, slo permiten las operaciones de "push" y "pop": Push: Aadir un elemento al final de la pila. Pop: Leer y eliminar un elemento del final de la pila. Push, insertar elemento: Las operaciones con pilas son muy simples, no hay casos especiales, salvo que la pila est vaca. Push(insertar) 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: El proceso es muy simple, bastar con que: 1. nodo->siguiente apunte a NULL. 2. Pila apunte a nodo. Push(insertar) 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.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
34
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: 1. Hacemos que nodo->siguiente apunte a Pila. 2. Hacemos que Pila apunte a nodo. Pop, leer y eliminar un elemento: 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: 1. Hacemos que nodo apunte al primer elemento de la pila, es decir a Pila. 2. Asignamos a Pila la direccin del segundo nodo de la pila: Pila->siguiente. 3. Guardamos el contenido del nodo para devolverlo como retorno,recuerda que la operacin pop equivale a leer y borrar. 4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar. Si la pila slo tiene un nodo, el proceso sigue siendo vlido, ya que el valor de Pila->siguiente es NULL, y despus de eliminar el ltimo nodo la pila quedar vaca, y el valor de Pila ser NULL.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 4.3. Implementacin de las estructuras lineales tipo pilas.
35
Despues de haber realizado la lectura y analizado la aplicabilidad que se le puede dar a las pilas, pasamos a la implementacin. Tal como se mension en captulos anteriores, la implementacin de las estructuras lineales se puede realizar por medio de punteros o de arreglos. En este curso profundizaremos con ms detalle en la implementacin con punteros, la razn se debe a que el tema de los arreglos se trata en detalle en los cursos Algoritmos y fundamentos de programacin, creando as la necesidad de profundizar en la implementacin de las estructuras lineales con el tema de punteros. Le recomiendo implemetacin ingresados en opciones y tres pila . seguir las siguientes instrucciones paso a paso y obtendr la bsica de una pila para el manejo de nmeros enteros tiempo de ejecucin, para locual usaremos un men de funciones bsicas para insertar visualizar y extraer datos de la
Iniciamos abriendo un documento nuevo en el editor de Turbo C++, ingrese los archivos de cabecera, tambin llamados libreras, las ms usadas o por ser las libreras bsicas como se muestra en imagen: #include<iostream.h> #include<stdio.h> #include<stdlib.h> #include<conio.h> #include<dos.h> En este caso utilizaremos una estructura para el manejo de la informacin que contendr la pila, aunque solo se manejarn datos de tipo entero, es bueno recordar que una estructura es una coleccin de una o ms variables, agrupadas bajo un solo nombre para facilitar su manejo, a diferencia de las que se encuentran en arreglos, pueden ser de diferentes tipos de variables del C, incluyendo arreglos y otras estructuras. Cada variable dentro de una estructura se llama un miembro de la estructura. Despues de esta corta introduccin declaramos la estructura que llamaremos pila. struct pila { int numero; struct pila *sig; }; struct pila *inicio=NULL; struct pila *c=NULL; Otra forma de declarar la estructura es poner a continuacin de la definicin de la estructura una lista de uno o mas nombres de variables inicializadas como se muestra aqu.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas struct pila { int numero; struct pila *sig; }*inicio=NULL, *c=NULL;
36
Para continuar con el programa escogemos 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 declaramos dos varibles de tipo apuntador 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:
Continuamos con la funcin principal haciendo uso de un men de opciones que a mi juicio es la mejor alternativa para interartuar con las estructuras lineales. En este punto es importante compilar el programa para depurar y corregir los posibles errores de sintaxis o de estructura, por lo pronto en las 3 opciones del men solo desplegarn un corto mensaje ya que las funciones de insertar visualizar y extraer aun no han sido declaradas. Void main() { textcolor(10); int opc=0; do { clrscr(); cout<<" MANEJO DE UNA ESTRUCTURA TIPO PILA "; cout<<"\n\n\n");
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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)
37
El cdigo de la funcin main() o tambin llamada funcin principal que incluimos en el programa en construccin, no amerita algn tipo de explicacin, es conocido y muy usado en el curso Introduccin a la Programacin. Compile y ejecute el programa, si lo digit cuidadosamente no generar errores de compilacin tan poco errores de ejecucin, optendremos el siguiente resultado despus de haber digitado la opcin 1.
El color verde del texto es gracias a la funcin textcolor(10)incluida en la primera lnea de cdigo de la funcin principal main(). Hasta aqu todo va bien, ahora vamos a alimentar el programa con la funcin de insertar, la cual insertar los datos numricos en la pila.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
38
Definimos la funcin insertar(), no tiene parmetros y no devolver ningn valor por eso es declarada de tipo void, esta lnea de cdigo la adicionamos al programa justo despues de donde est definida la estructura, ser el sitio dentro del cdigo del programa para definir las tres funciones a utilizar tal como se muestra en la imagen siguiente una vez incliuida la lnea de cdigo void insertar(void);
El otro cambio que haremos 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.
El siguiente cdigo contiene las instrucciones de la funcin insertar(), se incluir al final del cdigo, despus de cerrar las instrucciones de la funcin principal main().como se muestra en la imagen.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
39
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; } } Demos un vistazo al cdigo de la funcin insertar(), encontramos la funcin malloc( ) tratada con detalle en la primera unidad, encargada de asignar un bloque de memoria del tamao requerido y regresa un apuntador. El valor regresado por malloc( ) ha sido asignado a inicio, un apuntador al tipo struct pila, usando el apuntador y el operador de membresa indirecta (-->) se puede accesar a los miembros de la estructura como lo indica la lnea de cdigo cin>>inicio->numero; encontramos un condicional que indica que si no hay elementos en el apuntador c est en NULL, entonces insertamos datos por primera vez a la pila. El apuntador c apunta a donde apunta inicio, lo indica la
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
40
lnea de cdigo c=inicio; indirectamente guardan la misma informacin, posteriormente hacemos que el nuevo nodo apunte a NULL en la lnea de cdigo inicio->sig=NULL; Si la pila no est vacia hacemos que el nuevo nodo inicio a punte a c como lo indica el cdigo inicio->sig=c; ahora c es el nuvo nodo de la pila. Finaliza las instrucciones de la funcin insertar( ). Ejecutamos el cdigo y podremos insertar los datos numricos a la pila, pero que bueno sera si se pudiesen listar los datos insertados. Para ello incluiremos en el cdigo en construccin la funcin visualizar() que es la opcin 3 de el men de opciones, seguimos las indicaciones y los cambios que se llevaron a cabo para la funcin insertar(). Iniciamos definiendo la funcin para viualizar los datos ingresados, la lnea de cdigo es: void visualizar(void); se incluye en el espacio usado para la definicin de las funciones justo en la lnea siguiente de donde se defini la funcin insertar. Luego modificamos el case 3 del swich cambiando el mensaje a desplegar cout<<visualizar; por visualizar(); usado para que el programa principal haga el llamado a la funcin y as podremos seleccionar esta opcin y tendremos en pantalla los datos previamente insertados a la pila. Solo queda adicionar al final del cdigo principal la declaracin completa de la funcin visualizar() que se incluye a continuacin y que no hay cdigo desconocido que amerite explicacin alguna. void visualizar (void) { if (c==NULL) { clrscr(); cout<<"NO HAY ELEMENTOS A LISTAR"); } else { clrscr(); inicio=c; while (inicio!=NULL) { cout<<"Numero: "<<inicio->numero<<endl; inicio=inicio->sig; } } getch(); }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
41
Con la inclusin de este cdigo ya tenemos el programa con las opciones de insertar y visualizar los datos de la pila, es importante que compile el programa para depurar y corregir posibles errores. solo nos queda incluir la opcin de extraer o eliminar datos de la pila con esta opcin tendremos la implementacin completa del programa bsico para el manejo de una pila. Manos a la obra. Como en los dos casos anteriores seguimos las mismas directrices declarando la funcin extraer, en el espacio utilizado para tal fin, el cdigo es: Void extraer(void); con esta se completa la declaracin de las tres funciones Como lo podemos observar en la imagen siguiente.
Continuamos modificando el case 2 del swich cambiando el mensaje a desplegar cout<<extraer; por extraer(); usado para que el programa principal haga el llamado a la funcin y as podremos seleccionar esta opcin y tendremos la eliminacin del ltimo elemento que fue insertado a la pila, lo podemos comprobar haciendo uso de la opcin 3 del men de opciones se visualizarn los datos que aun quedan en la pila pero no sin antes definir al final del cdigo principal las instrucciones completas de la funcin extraer() que se incluyen a continuacin. void extraer (void) { if (c==NULL) { clrscr(); printf("NO HAY ELEMENTOS A ELIMINAR");
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } else { getch();
42
Demos una revisin al cdigo de la funcin extraer( ), si existen datos en la pila guardamos en inicio la ubicacin de c segn el cdigo inicio=c; la instruccin cout<<"El dato a eliminar es: "<<inicio->numero; visualiza en pantalla el dato a eliminar, por medio de la funcin delay() se visualiza por un espacio de tiempo limitado el dato a eliminar. Analice el cdigo de cada funcin con el objetivo de que lo entienda y pueda dar realizar las actividades propuestas, aplicacin a situaciones reales, de igual manera puede plantear cambios para optimizar el cdigo propuesto, en caso de tener inquietudes recuerde que puede consultar al tutor del curso. Es importante aclarar que en esta gua se plantea solo una de tantas alternativas posibles que se pueden usar para la implementacin de una estructura tipo pila. Para resumir la implementacin del manejo de la pila se incluye el listado completo. Copie este cdigo, lo pega en el Bloc de Notas y lo guarda con el nombre PILA.CPP ya tiene listo el programa para que lo abra desde el editor de Turbo C++. Listado 4.3.1. #include<iostream.h> #include<stdio.h> #include<stdlib.h> #include<conio.h> #include<dos.h> struct pila { int numero; struct pila *sig; }*inicio=NULL, *c=NULL; void insertar(void); void extraer(void);
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas void visualizar(void); Void main() { 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: inserter(); 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;
43
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } c=inicio;
44
void visualizar (void) { if (c==NULL) { clrscr(); cout<<"NO HAY ELEMENTOS A LISTAR"); } else { clrscr(); inicio=c; while (inicio!=NULL) { cout<<"Nmero: "<<inicio->numero<<endl; inicio=inicio->sig; } } getch(); } void extraer (void) { if (c==NULL) { clrscr(); printf("NO HAY ELEMENTOS A ELIMINAR"); getch(); } else { inicio=c; cout<<"El dato a eliminar es: "<<inicio->numero; delay(1000); c=c->sig; free(inicio); } }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 4.4 Aplicacin de las estructuras lineales tipo pilas.
45
Al inicio del captulo se mension las dos posibilidades para la implementacin de las estructuras lineales por medio de punteros o de arreglos, aunque se har nfasis en la implementacin con apuntadores he querido incluir un programa para el manejo de una pila de cadena de caracteres implementado con arreglos. Pila Implementada con arreglos Listado 4.4.1 #include <iostream.h> #include <stdio.h> #include <ctype.h> #include <string.h> const int MaxPila=5; const int LargoCadena=20; const int PilaVacia=-1; char Pila[MaxPila][LargoCadena]; //Variables globales int Cima = PilaVacia; void meter(); // Definicin de prototipos void sacar(); void EscribirValoresEnPila(); void meter(){ char item[LargoCadena]; if (Cima == MaxPila-1){ cout << "\n\nDesbordamiento. Digite una tecla"; } else{ cout << "\nDigite elemento (una palabra): "; cin >> item; Cima++; strcpy(Pila[Cima], item); }
void sacar(){ char item[LargoCadena]; if (Cima == PilaVacia) cout << "\n\nSubdesbordamiento. digite una tecla";
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas else { strcpy(item, Pila[Cima]); cout << "Sacado de la pila: " << item; Cima--; }
46
void EscribirValoresEnPila(){ int i; if (Cima > PilaVacia) for (i = Cima; i >= 0; i--) cout << i << ": " << Pila[i] << endl; else cout << "Pila est vaca\n";
void main(){ char opcion; do{ EscribirValoresEnPila(); cout << "\nPuede introducir en la Pila un mximo de " << MaxPila << " elementos\n"; cout << "Meter Sacar Terminar: digite M, S o T: "; cin >> opcion; switch (toupper(opcion)) { case 'M' : meter(); break; case 'S' : sacar(); break; } } while (opcion != 'T');
La siguiente es una prueba de ejecucin manual del Listado anterior, que maneja una pila de cadenas de caracteres: Inicialmente se definen las siguientes constantes y variables: const int MaxPila = 5; const int LargoCadena = 10; const int PilaVaca = -1; char Pila[MaxPila][LargoCadena];
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
47
Pila
4 3 2 1 0
-1
A partir de la funcin principal, main(), podemos efectuar invocacin interactiva de las funciones meter() y sacar(). Analicemos primero la funcin meter(): void meter(){ char item[LargoCadena]; if (Cima == MaxPila-1) cout << "\n\nDesbordamiento. Digite una tecla"; else{ cout << "\nDigite elemento (una palabra): "; cin >> item; Cima++; strcpy(Pila[Cima], item); }
Al entrar a la funcin meter() nos encontramos con: if(Cima == MaxPila-1) -1 == 5-1 es falso vamos para el else, si fuera verdadera estara ya llena la pila. A continuacin se pide digitar un elemento, o sea una palabra, leyendose en la variable item: "Cali", Cima se incrementa en uno, y se asigna el item digitado a la Cima de la Pila:
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
48
Pila item
cali
Cima
4 3 2 1 0 Cali
A continuacin volvamos a invocar la funcin meter(): Cima no es igual a MaxPila-1, por esto, se digitan los caracteres: "Palmira" los cuales son ledos en la variable item, se encrementa Cima y se asignan a la Cima de la Pila, retornando al sitio donde la funcin fu invocada, en el main():
Pila
item
Palmira
Cima
4 3 2 1 Palmira Cali 0
Una vez ms se invoca meter(): se digita la palabra "Zarzl" y la pila queda ahora as:.
Pila item
4 3 2
Zarzal
Zarzal
Cima
1 Palmira 0
Cali
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
49
4 3 2 Toro
Zarzal
Toro
1 Palmira
Cima
Cali
4 Jamundi 3 2 0 Toro
Zarzal
Jamundi
Cima
1 Palmira
Cali
Se invoca meter(): con este caso if (Cima==MaxPila-1) es verdadero, aparecer en pantalla: "Desbordamiento. Digite una tecla" y volver a la funcin main() del programa. Si invocamos a continuacin la funcin sacar(): void sacar(){ char item[LargoCadena]; if (Cima == PilaVacia) cout << "\n\nSubdesbordamiento. digite una tecla"; else { strcpy(item, Pila[Cima]); cout << "Sacado de la pila: " << item; Cima--; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
50
Inicialmente intruccin if (Cima == PilaVaca) es falsa por esto seguir el algoritmo en el else; en la variable item se asigna el valor que est en la Cima de la Pila por medio de strcpy (item, Pila[Cima]) y a continuacin se decrementa Cima en 1, quedando la pila as:
Pila Item
4 3 2 Toro
Zarzal
Jamundi
Cima
1 Palmira 0
Cali
El elemento que estaba en la posicin 4 del vector Pila se ha borrado "lgicamente", es decir del dibujo o sea de lo que debemos abstraer est ocurriendo, en realidad la palabra Jamund sigue en Pila[4], empero ya como "basura". Ahora, de nuevo, invoquemos sacar():
Item
Pila
Toro
4 3
Zarzal
Cima
2 0
1 Palmira
Cali
Invocamos sacar(), por dos iteraciones ms hasta que no hayan elementos en la pila.
Item
cali
Cima
-1
if (Cima == PilaVaca)
4 3 2 1 0
Pila
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas -1 -1
51
El condicional (if) anterior es verdadero, por esto, aparecer en pantalla el aviso "subdesbordamiento. Digite una tecla" y se regresar a la parte principal a continuacin. Pila Implementada con Punteros Listado 4.4.2. #include <iostream.h> #include <conio.h> #include <iomanip.h> #include <ctype.h> #include <stdlib.h> const int MaxPila=5; void EscribirValoresEnPila(); //Definicin de prototipos void meter(int *P); void sacar(int *P); int Pila[MaxPila]; //Definicin variables globales int *Cima=NULL; void main(){ int opcion; for(;;){ EscribirValoresEnPila(); cout << "\nPuede introducir en la Pila un mximo de " << MaxPila << " elementos "; cout << "\n\nMeter Sacar Terminar: digite M, S o T: "; opcion = toupper( getch() ); switch (opcion) { case 'M' : meter(Pila); break; case 'S' : sacar(Pila); break; case 'T' : exit(0); } }
void meter(int *P){ int item; if (Cima == (P+MaxPila-1)){ cout << "\n\nDesbordamiento. Digite una tecla";
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } else { if (Cima == NULL) Cima = Pila; /*Inicializa Pila*/ else Cima++; cout << "\nDigite elemento(un entero): "; cin >> item; *Cima = item; } getch();
52
void sacar(int *P){ if ( !Cima ) cout << "\n\nSubdesbordamiento."; else { cout << "\n\nSacado de la pila: " << *Cima; if (Cima == P) // Era el ltimo elemento Cima = NULL; else Cima--; }
void EscribirValoresEnPila(){ int *p; clrscr(); if (Cima){ p = Cima; while (p >= Pila){ cout << setw(10) << *p << endl; p--; } } else cout << "Pila est vaca\n"; }
4.5 Codigos de ejemplos del funcionamiento de una pila Listado 4.5.1. #include <stdio.h> #include <conio.h>
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas #include <stdlib.h> #include <iostream.h> void insertar(void); void extraer(void); void visualizar(void); struct pila { char nombre[20]; struct pila *ant; }; struct pila *CAB=NULL,*AUX=NULL; main() /* Rellenar, extraer y visualizar */ { char opc; do { clrscr(); /* borramos la pantalla */ gotoxy(30,8); /* columna 30, fila 8 */ cout<<"1.- Insertar"; gotoxy(30,10); cout<<"2.- Extraer"; gotoxy(30,12); cout<<"3.- Visualizar la pila"; gotoxy(30,14); cout<<"4.- Salir"; gotoxy(20,16); cout<<"Ingrese una opcion : "; cin>> opc; // opc=getch( ); otra forma switch(opc) { case '1': insertar( ); break; case '2': extraer( ); break; case '3': visualizar( ); } // getch(); es opcional }while (opc!='4'); return 0;
53
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas //FUNCION PARA INSERTAR DATOS A LA PILA 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; }
54
//FUNCION DE ELINIMAR ELEMENTOS DE LA PILA void extraer(void) { if (CAB==NULL) return; AUX=CAB; CAB=CAB->ant; free(AUX); cout<<"\n Se elimio a " <<AUX->nombre <<" de la pila"; getch(); } //FUNCION DE VISUALIZAR LA PILA void visualizar(void) { if (CAB==NULL) return; clrscr(); AUX=CAB; cout<<"DATOS DE LA PILA \n\n "; while (AUX!=NULL) { cout<<"Nombre: "<<AUX->nombre <<endl;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } getch( ); AUX=AUX->ant;
55
Listado 4.5.2. /* Implementacion de una pila que permite ingresar y sacar datos del registro de personas.*/ #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 /************************ Push (Insertar) ***********************/ void Push() // Funcion que inserta datos a la pila { struct nodo *p; p = (struct nodo*) malloc(sizeof(struct nodo)); // reservamos // espacio para el nodo (dato, sig) printf("Escriba el nombre: "); scanf("%s",p->nombre); if(tope == NULL){ // si no hay elemetos el tope esta en NULL // insertamos por primera vez a la pila printf("Escriba la Edad: ");
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas scanf("%d",&p->edad); printf("Escriba el Salario: "); scanf("%d",&p->salario); p->sig = NULL; // hacemos que el nuevo nodo apunte a NULL tope = p; // Ahora el tope es el nuevo nodo return;
56
} // si no
printf("Escriba la Edad: "); scanf("%d",&p->edad); printf("Escriba el Salario: "); scanf("%d",&p->salario); p->sig = tope; // hacemos que el nuevo nodo apunte al tope tope = p; // ahora el tope es el nuevo nodo } /************************** Pop (Sacar) *************************/ void Pop(){ if(tope == NULL){ printf("PILA VACIA\n"); return; } int i; // es para almacenar el dato que tiene el tope struct nodo *tmp; // temporal para almacenar la direccion del tope tmp = tope; // guardamos en tmp la ubicacion del tope tope = tmp->sig; // hacemos que el tope sea el anterior nodo ingresado // sacamos el dato del nodo que estaba como tope printf("Nombre : %s\n", tmp->nombre); printf("Edad : %d\n", tmp->edad); printf("Salario : %d\n", tmp->salario); free(tmp); // liberamos la memoria reservada para el tope
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas int menu() { int o = 0; do{ clrscr(); // limpiar pantalla printf(" Maneja una Pila de Empleados: Nombre, Edad, Salario\n"); printf("1. Insertar Empleado\n"); printf("2. Sacar Empleado\n"); printf("3. Vaciar Pila de Empleados\n"); printf("4. Salir\n\n"); printf("Ingrese la opcion : "); scanf("%d",&o); // leer opcion del teclado }while( o < 1 || o > 4); // mientras sea menor que 1 o mayor que 4 clrscr(); return o; } int main() { tope = NULL; // hacemos que el tope no apunte a nada (pila vacia) int d = 0; do{ d = menu(); // retorna opcion switch(d) { case 1: Push(); break; case 2: { Pop(); getch(); break; } case 3: { while(tope != NULL) Pop(); printf("PILA VACIA"); getch(); break; }
57
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas }while(d != 4); // mientras que la opcion no sea 4 return 0;
58
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
59
veces que se movi el auto dentro del estacionamiento, incluyendo la salida misma, pero no la llegada. Este nmero es 0 si el carro sale de la fila de espera.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
60
Captulo 5. Colas
5.1. Conceptos bsicos Las colas son otro tipo de estructura lineal de datos, similar a las pilas, diferencindose de ellas en el modo de insertar/eliminar elementos. Una cola es una estructura lineal de datos. En la que las eliminaciones se realizan al principio de la lista, frente, y las inserciones se realizan en el otro extremo, final. En las colas el elemento que entr de primero sale tambin de primero; por ello se conocen como listas FIFO (first-in, first-out, <<primero en entrar, primero en salir>>). 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.
5.2 Aplicacin de las estructuras Lineales tipo Colas En la vida real se tiene ejemplos numerosos de colas: la cola de un autobs, cola de un cine, caravana de coches en una calle, etc. En todas ellas el primer elemento (pasajero, coche, etc) que llega es el primero que sale. En informtica existen numerosas aplicaciones de las colas. Por ejemplo,en un sistema de tiempo compartido suele haber un procesador central y una serie de perifricos compartidos: discos, impresoras, etc. Los recursos se comparten por los diferentes usuarios y se utiliza una cola para almacenar los programas o peticiones de los diferentes usuarios que esperan su turno de ejecucin. El procesador central atiende normalmente por riguroso orden de llamada del usuario; por tanto todas las llamadas se alamacenan en una cola. Existe otra aplicacin muy utilizada que se denomina cola de prioridades; en ella el procesador central no atiende por riguroso orden de llamada, aqu el procesador atiende por prioridades asignadas por el sistema o bien por el usuario y slo dentro de las peticiones de igual prioridad se producir una cola.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
61
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 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 tambien son llamadas listas en las cuales el primer elemento en entrar es el primero en salir. Para las colas que trabajaremos se sobreentender, a menos de decir lo contrario, que la regla es que siempre el primero se atiende primero. Una Cola es una estructura de datos la cual almacena elementos de un tipo determinado, que sigue la poltica de que el primer elemento que se extrae (se desencola) es el primero que se introdujo (se encol) -primero en salir, primero en entrar (FIFO).
5.3. Operaciones bsicas con colas De nuevo nos encontramos ante una estructura con muy pocas operaciones disponibles. Las colas slo permiten aadir y leer elementos:
Aadir: Inserta un elemento al final de la cola. Leer: Lee y elimina un elemento del principio de
la cola.
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.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
62
Implementacin Para la implementacin de la cola utilizaremos la estructura de datos con apuntadores y arreglos unidimensionales. Las funciones que manejarn la cola sern: Insertar() y Atender(). Desarrollemos estas dos funciones de forma "simultnea"; 5.4. Implementacin de las Colas por medio de Arreglos partamos de las definiciones de constantes y variables siguientes: const int MaxCola = 5; const int nulo = -1; int frente = nulo; int final = nulo; int cola[MaxCola];
cola frente nulo 0 1 2 3 4 final nulo
Cuando una cola est vaca el primer elemento que llegue, lgicamente que llegar al frente, supongamos ese elemento es 15:
cola 15 0 1 2 3 4 frente 0 final 0
Las variables frente y final deben colocarse en cero, el fragmento de cdigo correspondiente para obtener lo anterior sera: if (frente == nulo){ //la cola estaba vaca frente = final = 0; cout << "\n\nElemento a insertar: "; cin >> cola[frente]; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
63
Si llega otro elemento, supongamos 18, tendramos que colocarlo al "final de la cola", quedando:
cola 15 0 18 1 2 3 4 frente 0 final 1
Vemos que el final se ha movido hacia la derecha, el cdigo que podra hacer esto, sera: final++; cout << "\n\nElemento a insertar: "; cin >> cola[final]; Este ser el "caso general", pero hay varios casos particulares, los cuales trataremos a continuacin. Supongamos que siguen llegando elementos a la cola, as:
cola 15 0 18 1 -4 2 cola 15 0 18 1 -4 2 cola 15 0 18 1 -4 2 0 3 65 4 0 3 4 frente 0 final 4 3 4 frente 0 final 3 frente 0 final 2
Si trataramos de insertar otro ms, debera el programa darnos un mensaje de "Cola llena", para esto mejoraremos el cdigo anterior de esta forma: if ( (final+1 == MaxCola && frente == 0) ) cout << "cola llena "; else{ final++; cout << "\n\nElemento a insertar: "; cin >> cola[final]; } Ahora supongamos que se comienza a atender(eliminar) elementos, en el frente:
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
cola 18 0 1 -4 2 frente 0 3 65 4 final 1 4
64
Observe que no vamos a correr los elementos hacia la izquierda, como sucedera en una cola de la vida real, no!, todos los elementos permanecern siempre en el mismo sitio, hasta que sean atendidos. Atendamos ahora al 18 en la posicin frente de 1:
cola -4 0 1 2 0 3 65 4 frente 2 final 4
Hasta aqu podramos copiar el algoritmo de atender(eliminar) as: cout << "Atendido el frente: " << cola[frente]; frente++; Estn "desocupadas" en este momento las posiciones 0, 1 y 2, si llega otro elemento, debemos aprovechar esas posiciones, de la siguiente forma, insertemos el elemento 57:
cola 57 0 1 2 0 3 65 4 frente 3 final 0 final pasa de 4 a 0
Es de notar que la cola que el usuario tiene en mente tiene el orden: 0 65 57 Esto ocasiona una nueva modificacin al algoritmo de insertar, veamos: if ( (final+1 == MaxCola && frente == 0) cout << "cola llena "; else { final++;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas if (final == MaxCola) final = 0; cout << "\n\nElemento a insertar: "; cin >> cola[final];
65
La cola para el usuario estara en este orden: 0, 65, 57, 14. Insertemos ahora otro elemento, por ejemplo 81:
cola 57 0 14 1 81 2 0 3 65 4 frente 3 final 2
La cola para el usuario estara como: 0, 65, 57, 14, 81. Llegados a este punto no podramos seguir insertando elementos, ya que esta la cola est llena. Verifique nuestro algoritmo y se dar cuenta que fracasar, permitiendo insertar otro y de esta forma borrando el valor que tenemos en el frente, por ello recodificamos, teniendo en cuenta que si el final est una posicin menos que el frente, la cola est, tambin llena: if ( (final+1 == MaxCola && frente == 0) || (final+1 == frente) ) cout << "cola llena "; else { final++; if (final == MaxCola) // se da "la vuelta al inicio" final = 0; cout << "\n\nElemento a insertar: "; cin >> cola[final]; } A continuacin insertmosle al anterior cdigo, el caso inicial, cuando la cola estaba vaca y tendramos finalmente: if ( (final+1 == MaxCola && frente == 0) || (final+1 == frente) ) cout << "cola llena "; else if (frente == nulo){ //la cola estaba vaca frente = final = 0; cout << "\n\nElemento a insertar: "; cin >> cola[frente]; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas else { // caso general final++; if (final == MaxCola) // se da "la vuelta al inicio" final = 0; cout << "\n\nElemento a insertar: "; cin >> cola[final]; }
66
Dediqumonos ahora a terminar la funcin de Atender(eliminar). Eliminemos el frente, posicin 3, La cola para el usuario est as: 65, 57, 14, 81. Recordemos el cdigo hasta el momento y que nos sirve para este caso: cout << "Atendido el frente: " << cola[frente]; frente++; Atendamos otro, el 65 en posicin frente de 4:
cola 57 0 14 1 81 2 3 4 frente 0 final 2
El frente "da la vuelta", el algoritmo se modifica as: cout << "\nAtendido: " << cola[frente]; frente++; if (frente == MaxCola) frente = 0; Sigamos, sucesivamente, atendiendo los dems elementos en cola y verificndolo cada vez en el algoritmo anterior:
cola 14 0 1 81 2 cola 81 0 1 2 3 4 3 4 frente 2 final 2 frente 1 final 2
Observe que cuando queda un solo elemento en cola, el frente es igual al final. Luego al eliminar el ltimo elemento el algoritmo fallara, las variables deberan quedar:
cola frente nulo 0 1 2 3 4 final nulo
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Para esto se debe modificar nuevamente el cdigo para Atender: cout << "\nAtendido: " << cola[frente]; if (frente == final) frente = final = nulo; else{ frente++; if (frente == MaxCola) frente = 0; }
67
En este momento tenemos la cola vaca. si tratramos de Atender un elemento, el algoritmo anterior nos mostrara "basura", por esto, al fin, recodificamos el algoritmo Atender: if (frente == nulo) cout << "\nCola vacia\a"; else { cout << "\nAtendido: " << cola[frente]; if (frente == final) frente = final = nulo; else{ frente++; if (frente == MaxCola) frente = 0; } }
Representacin Grafica de las operaciones que se puden realizar con estas estructuras
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
68
Como resumen de lo anterior a continuacin se presenta el programa con la implementacin, completa, de la estructura cola en un arreglo unidimensional: Cola Implementada con arreglos Listado 5.4.1. #include <iostream.h> #include <iomanip.h> #include <conio.h> const int MaxCola = 5; const int nulo = -1; int frente = nulo; int final = nulo; int cola[MaxCola]; void Insertar(){ if ( (final+1 == MaxCola && frente == 0) || (final+1 == frente) ){ cout << "cola llena "; getch(); } else if (frente == nulo){ //la cola estaba vaca frente = final = 0; cout << "\n\nElemento a insertar: "; cin >> cola[frente]; } else { // caso general final++; if (final == MaxCola) // se da "la vuelta al inicio" final = 0; cout << "\n\nElemento a insertar: "; cin >> cola[final]; }
void Atender(){ if (frente == nulo) cout << "\nCola vacia\a"; else { cout << "\nAtendido: " << cola[frente]; if (frente == final) // cola qued vaca frente = final = nulo; else{
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas frente++; if (frente == MaxCola) frente = 0;
69
void Listar(){ int i; if (frente==nulo) cout << "\nCola vacia \a\n"; else if (frente <= final) for (i=frente; i <= final; i++) cout << setw(4) << cola[i]; else { for (i=frente; i < MaxCola; i++) cout << setw(4) << cola[i]; for (i=0; i <= final; i++) cout << setw(4) << cola[i];
void main(){ char opcion; do{ 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');
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
70
Ahora realice un anlisis detallado del siguiente programa (Listado 5.4.2), el cual tiene un pequeo cambio, con relacin al anterior: Cola de Registros de personas: Listado 5.4.2. #include <iostream.h> #include <iomanip.h> #include <conio.h> #include <stdio.h> const int MaxCola = 40; const int nulo = -1; int frente = nulo, final = nulo; typedef struct persona PERSONA; struct persona{ char nombre[25]; int edad; float alto; } Cola[MaxCola]; void Insertar(){ PERSONA registro; if ( (final+1 == MaxCola && frente == 0) || (final+1 == frente) ){ cout << "Cola llena "; getch(); } else{ cout << "\n\nDigite nombre: "; cin >> registro.nombre; cout << "Digite edad en aos: "; cin >> registro.edad; cout << "Digite estatura en metros: "; cin >> registro.alto;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas if (frente == nulo){ //la Cola estaba vaca frente = final = 0; Cola[frente] = registro; } else { // caso general final++; if (final == MaxCola) // se da "la vuelta al inicio" final = 0; Cola[final] = registro; }
71
void Atender(){ if (frente == nulo) cout << "\nCola vacia\a"; else { cout << "\nAtendido: " << Cola[frente].nombre << " " << Cola[frente].edad << " " << Cola[frente].alto; if (frente == final) // cola qued vaca frente = final = nulo; else { frente++; if (frente == MaxCola) frente = 0; } } getch();
void listar(){ int i; clrscr(); if (frente==nulo) cout << "Cola vacia \a\n"; else if (frente <= final) for (i = frente; i <= final; i++) cout << "\n" << Cola[i].nombre << " " << Cola[i].edad << " " << Cola[i].alto; else { for (i=frente; i<MaxCola; i++) cout << "\n" << Cola[i].nombre << " " << Cola[i].edad << " " << Cola[i].alto;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas for (i=0; i <= final; i++) cout << "\n" << Cola[i].nombre << " " << Cola[i].edad << " " << Cola[i].alto << endl;
72
void main(){ char opcion; do { listar(); cout << "\n\nInsertar Atender Salir "; opcion = getch(); switch (opcion){ case 'I':; case 'i': Insertar(); break; case 'A':; case 'a': Atender(); break; } } while (opcion != 'S' && opcion != 's');
5.5. Implementacin de las Colas por medio de Punteros 5.5.1 Representacin de las Colas Las colas tambin se pueden representar como estructuras dinmicas, para ello se necesitan dos punteros: CAB y FIN. Aadir un elemento: 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, CAB y FIN que valdrn NULL. El proceso es muy simple, bastar con que: 1. AUX->sig apunte a NULL. 2. Y que los punteros CAB y FIN apunten a AUX. Aadir elemento en una cola no vaca: De nuevo partiremos de un nodo a insertar, con un puntero que apunte a l, y de una cola, en este caso, al no estar vaca, los punteros CAB y FIN no sern nulos. El proceso sigue siendo muy sencillo: 1. Hacemos que AUX->siguiente apunte a NULL. 2. Despus que FIN->siguiente apunte a AUX. 3. Y actualizamos FIN, haciendo que apunte a AUX.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
73
La siguiente funcin resume el anterior anlisis realizado para la insercin de nodos a la cola void insertar(void) { AUX=(struct cola *)malloc(sizeof(struct cola)); clrscr(); cout<<"Nombre: "; gets(AUX->nombre); AUX->sig=NULL; if (FIN==NULL) FIN=CAB=AUX; else { FIN->sig=AUX; FIN=AUX; } } Extraer un elemento de una cola, implica eliminarlo: Usaremos un puntero a un nodo auxiliar llamado CAB que apunta a la cabeza de la cola. Si la cola est bacia si CAB==NULL retorna al programa principal, desplegando el mensaje que indica el estado de la cola. . 1. Hacemos que AUX apunte al primer elemento de la cola, es decir a CAB. 2. Asignamos a CAB la direccin del segundo nodo de la pila: CAB=CAB->sig. 3. Guardamos el contenido del nodo para devolverlo como retorno, recuerda que la operacin de lectura en colas implican tambin borrar. 4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar. Free (AUX); La siguiente funcin resume el anterior anlisis realizado para la eliminacin de nodos a la cola void extraer(void) { if (CAB==NULL) { cout<<"No hay elementos en la cola"; getch(); } else { AUX=CAB; cout<<"El dato eliminado es: "<<AUX->nombre;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas getch(); CAB=CAB->sig; free(AUX); }
74
Visualizar los elementos de una cola Usaremos un puntero llamado CAB que apunta a la cabeza de la cola. Si la cola est bacia si CAB==NULL retorna al programa principal desplegando el mensaje que indica el estado de la cola. En caso contrario, que la cola tenga elementos 1. Hacemos que AUX apunte al primer elemento de la cola, es decir a CAB. 2. inicia el recorrido por todos los elementos de la cola, por medio del apuntador AUX, AUX->nombre, posteriormente a AUX se le asigna el valor del siguiente nodo, AUX=AUX->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 (CAB==NULL) { cout<<"NO HAY ELEMENTOS EN LA COLA"; getch(); } else { clrscr(); AUX=CAB; while (AUX!=NULL) { cout<<"Nombre:" <<AUX->nombre <<"\n"; AUX=AUX->sig; } getch(); } El siguiente listado muestra el cdigo completo de la iplementacin de una cola objeto del anlisis. Listado 5.5.1. #include <stdio.h> #include <iostream.h> #include <conio.h>
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas #include <stdlib.h> void insertar(void); void extraer(void); void visualizar(void); struct cola { char nombre[20]; struct cola *sig; }*CAB=NULL,*AUX=NULL,*FIN=NULL; main() {
75
char opc; do { 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( ); cout<<"TODOS LOS ELEMENTOS DE LA COLA \n";
void insertar(void) {
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas AUX=(struct cola *)malloc(sizeof(struct cola)); clrscr(); cout<<"Nombre: "; gets(AUX->nombre); AUX->sig=NULL; if (FIN==NULL) FIN=CAB=AUX; else { FIN->sig=AUX; FIN=AUX; }
76
void extraer(void) { if (CAB==NULL) { cout<<"No hay elementos en la cola"; getch(); } else { AUX=CAB; cout<<"El dato eliminado es: "<<AUX->nombre; getch(); CAB=CAB->sig; free(AUX); } } void visualizar(void) { if (CAB==NULL) { cout<<"NO HAY ELEMENTOS EN LA COLA"; getch(); } else { clrscr(); AUX=CAB; while (AUX!=NULL) { cout<<"Nombre:" <<AUX->nombre <<"\n"; AUX=AUX->sig; } getch(); }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } 5.6 Codigos de ejemplos del funcionamiento de una cola
77
El siguiente programa de aplicacin de una cola implementa un planificador de citas con un menu de iteraciones. Listado 5.6 #include <string.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <conio.h> #include <iostream.h> #define MAX 5 char *p[MAX], *crecup(void); int spos=0; int rpos=0; char *crecup(void); void intro(void), calmac(char *c), revisar(void), eliminar(void); int main() { clrscr(); char s[80]; 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();
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas break; case 'R': revisar(); break; case 'E': eliminar(); break; case 'S': exit(0); }
78
} }
//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); if(!p) { cout<<"No hay memoria \n"; return; } strcpy(p, s); if(*s)calmac(p); }while(*s); clrscr(); } //ver que hay en la cola void revisar(void) { clrscr(); register int t; cout<<endl <<endl <<" LISTADO DE CITAS" <<endl <<endl; for(t=rpos;t<spos;++t) cout<<t+1 <<p[t] <<endl; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas //Eliminar una cita de la cola void eliminar(void) { clrscr(); char *p; if ((p=crecup())==NULL) return; cout<<endl <<"CITA ELIMINADA:" <<p; } //guardar una cita void calmac(char *c) { if(spos==MAX) { cout<<"\n La Cola esta llena. Presione Intro \n"; return; } p[spos] = c; spos++; } //Recuperar una cita char *crecup(void) { if(rpos==spos) { cout<<"No hay mas citas \n"; return NULL; } rpos++; return p[rpos-1]; } Ejemplo Real de Aplicacin de las Colas
79
La situacin es muy real a la de un jefe que tiene una secretaria a su servicio para manejar el telfono y la correspondencia. La secretaria organiza la agenda de las actividades que debe realizar su jefe. Las llamadas que se acumulan para el jefe se tratan de una en una, al igual que las actividades y en el orden que prefiera el jefe. Se debe ordenar de acuerdo a la importancia de la gestin.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
80
Ejercicio 3. Aadir al tipo abstracto de las colas: Una operacin que calcule el ltimo elemento de una cola. Una operacin que produzca la inversa de una cola. Una operacin que concatene dos colas, es decir, que coloque los elementos de una al final de la otra. Una operacin que intercale los elementos de dos colas. Disear mtodos que implementen las nuevas operaciones usando la representacin dinmica de las colas. Ejercicio 4. Implementar el tipo abstracto de las colas utilizando como tipo representante un par de pilas. 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: Especificar un tipo abstracto de datos para las colas medievales que disponga al menos de operaciones para: crear una cola medieval vaca, aadir un elemento nuevo a una cola, consultar el primer elemento de una cola, quitar el primer elemento de una cola, consultar el nmero de nobles en una cola, consultar el nmero de plebeyos en una cola, consultar si una cola es vaca o no. Implementar las colas medievales utilizando memoria dinmica. Implementar las colas medievales en trminos de colas ordinarias, de forma que las implementaciones de las operaciones tengan coste constante
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
81
(suponiendo que las operaciones de las colas ordinarias tienen coste constante). Ejercicio 6.
1. en cierto punto de la ciudad hay un estacionamiento como el que se muestra en la figura, en donde hay lugar para 9 vehculos. haga un programa que muestre el manejo de este estacionamiento, considerando los siguientes requisitos: 1. Los vehculos proporcionan la siguiente informacin: Placas (6 digitos), Estado (2-3 caracteres, p.e. SON, DF, CHI, YUC), Marca, Modelo, Ao-Modelo, Nombre del propietario. 2. Al llegar un veculo se acepta solamente si hay lugar disponible. 3. Validar todas las operaciones de la pila. 4. En cualquier momento se puede sacar algn vehculo del estacionamiento, regresando los vehculos en el orden en que estaban. 5. Toda la corrida del programa debe hacerse hacia/desde la terminal estndar
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
82
Captulo 6. Listas
6.1 Concepto de Listas Las listas deacuerdo a 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 6.2. Lista simplemente enlazada. Lista contigua: Es 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. 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. Una lista lineal se almacena en la memoria de la computadora en posiciones sucesivas o adyacentes y se procesa como un array unidimensional. En este caso, el acceso a cualquier elemento de la lista es fcil; sin embargo, la insercin o borrado requiere un desplazamiento de lugar de los elementos que le siguen y en consecuencia el diseo de un algoritmo especfico. Para permitir operaciones con las listas como arrays se deben dimensionar stos con tamao suficiente para que contengan todos los posibles elementos de la lista. La insercin o eliminacin de un elemento, excepto en la cabecera o final de la lista, necesita una traslacin de un parte de los elementos de la misma: la que precede o sigue a la posicin del elemento modificado. Las operaciones directas de aadir y eliminar se efectan nicamente en los extremos de la lista. Esta limitacin es una de las razones por las que esta estructura es poco utilizada.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 6.3. Operaciones con las listas simplemente enlazadas
83
Las operaciones que se pueden realizar con listas lineales contiguas son: 1. 2. 3. 4. 5. 6. 7. 8. Insertar, eliminar o localizar un elemento. Determinar el tamao nmero de elementos de la lista. Recorrer la lista para localizar un determinado elemento. Clasificar los elementos de la lista en orden ascendente o descendente. Unir dos o ms listas en una sola. Dividir una lista en varias sublistas. Copiar la lista. Borrar la lista.
Una lista enlazada o encadenada es un conjunto de elementos en los que cada elemento contiene la posicin o direccin del siguiente elemento de la lista. Cada elemento de la lista enlazada debe tener al menos dos campos: un campo que tiene el valor del elemento y un campo (enlace, link) que contiene la posicin del siguiente elemento, es decir, su conexin, enlace o
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
84
encadenamiento. Los elementos de una lista son enlazados por medio de los campos enlaces Una lista enlazada sin ningn elemento se llama lista vaca. Su puntero inicial o de cabecera tiene el valor nulo (NULL). Una lista enlazada se define por: El tipo de sus elementos: campo de informacin (datos) y campo enlace (puntero). Un puntero de cabecera que permite acceder al primer elemento de la lista. Un medio para detectar el ltimo elemento de la lista: puntero nulo (NULL).
6.4.1. Implementacin de Listas Enlazadas Pues ahora vamos a ver un tipo de estructura totalmente dinmica (que puedan aumentar o disminuir de tamao durante la ejecucin del programa). Ahora "el truco" consistir en que dentro de cada dato almacenaremos todo lo que nos interesa, pero tambin una referencia que nos dir dnde tenemos que ir a buscar el siguiente, para estos casos se hace uso de las estructuras. Sera algo as como: (Posicin: 1023). Nombre : 'Juan Cano ' DireccionInet : 'jcano@pobox.com' SiguienteDato : 1430 Este dato est almacenado en la posicin de memoria nmero 1023. En esa posicin guardamos el nombre y la direccin (o lo que nos interese) de esta persona, pero tambin una informacin extra: la siguiente ficha se encuentra en la posicin 1430. As, es muy cmodo recorrer la lista de forma secuencial, porque en todo momento sabemos dnde est almacenado el siguiente dato. Cuando lleguemos a uno para el que no est definido cual es el siguiente, quiere decir que se ha acabado la lista. Por tanto, en cada dato tenemos un enlace con el dato siguiente. Por eso este tipo de estructuras recibe el nombre de "listas simplemente enlazadas" o listas simples. Si tuvieramos enlaces hacia el dato siguiente y el posterior, se tratara de una "lista doblemente enlazada" o lista doble.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
85
Hemos perdido la ventaja del acceso directo: ya no podemos saltar directamente al elemento nmero 500. Pero, por contra, podemos tener tantos elementos como la memoria nos permita. Para aadir un nodo, no tendramos ms que reservar la memoria para el y el compilador de C nos dira "le he encontrado sitio en la posicin 4079". As que nosotros iramos al ltimo elemento y le diramos "tu siguiente dato va a estar en la posicin 4079". Esa es la idea "intuitiva". Ahora vamos a concretar cosas en forma de programa en C. Primero veamos cmo sera ahora cada una de nuestras fichas: typedef struct f /* Estos son los datos que guardamos: */ { char nombre[30]; /* Nombre, hasta 30 letras */ char direccion[50]; /* Direccion, hasta 50 */ int edad; /* Edad, un numero < 255 */ struct f *siguiente; /* Y direccin de la siguiente */ } Ficha; La diferencia con un "struct" normal est en el campo "siguiente" de nuestro registro, que es el que indica donde se encuentra la ficha que va despus de la actual, y por tanto ser otro puntero a un registro como estos, un "struct f*". Un puntero que "no apunta a ningn sitio" tiene el valor NULL (realmente este identificador es una constante de valor 0, como ya hemos comentado), que nos servir despus para comprobar si se trata del final de la lista: todas las fichas "apuntarn" a la siguiente, menos la ltima, que "no tiene siguiente", y apuntar a NULL. Entonces la primera ficha definiramos con Ficha *dato1; y la crearamos con dato1 = (Ficha*) malloc (sizeof(Ficha)); /* Reservamos memoria */ strcpy(dato1->nombre, "Pepe"); /* Guardamos el nombre, */ strcpy(dato1->direccion, "Su casa"); /* la direccin */ dato1->edad = 40; /* la edad */ dato1->siguiente = NULL; /* y no hay ninguna ms */ Eso de /* Va a ser un puntero a ficha */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas strcpy(dato1->nombre,"Pepe"); es algo que posiblemente tenderamos a escribir as en un principio: *dato1.nombre = "Pepe";
86
Pero recordemos que en el lenguaje C no se puede dar valores as a las cadenas de texto, sino que debemos funciones como "strcpy", y hacer algo parecido a strcpy(*dato1.nombre,"Pepe"); Pero esa expresin todava no es correcta del todo. La forma correcta de escribir que queremos acceder a los campos de un puntero a registro es usando el operador "->", como he indicado anteriormente: strcpy(dato1->nombre,"Pepe"); Ahora que ya tenemos una ficha, podramos aadir otra ficha detrs de ella. Primero guardamos espacio para la nueva ficha, como antes: Ficha *dato2; /* Va a ser otro puntero a ficha */
dato2 = (Ficha*) malloc (sizeof(Ficha)); /* Reservamos memoria */ strcpy(dato2->nombre, "Juan"); /* Guardamos el nombre, */ strcpy(dato2->direccion, "No lo s"); /* la direccin */ dato2->edad = 35; /* la edad */ dato2->siguiente = NULL; /* y no hay ninguna ms */ y ahora enlazamos la anterior con ella: dato1->siguiente = dato2; Si quisieramos introducir los datos ordenados alfabticamente, basta con ir comparando cada nuevo dato con los de la lista, e insertarlo donde corresponda. Por ejemplo, para insertar un nuevo dato entre los dos anteriores, haramos: Ficha *dato3; /* Va a ser otro puntero a ficha */
dato3 = (Ficha*) malloc (sizeof(Ficha)); strcpy(dato3->nombre, "Carlos"); strcpy(dato3->direccion, "Por ah"); dato3->edad = 14; dato3->siguiente = dato2; /* enlazamos con la siguiente */ dato1->siguiente = dato3; /* y la anterior con ella */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas La estructura que hemos obtenido es la siguiente Dato1 - Dato3 - Dato2 - NULL
87
Es decir: cada ficha est enlazada con la siguiente, salvo la ltima, que no est enlazada con ninguna (apunta a NULL). Si ahora quisiramos borrar Dato3, tendramos que seguir dos pasos: 1.- Enlazar Dato1 con Dato2, para no perder informacin. 2.- Liberar la memoria ocupada por Dato3. Esto, escrito en "C" sera: dato1->siguiente = dato2; /* Enlaza Dato1 y Dato2 */ free(dato3); /* Libera lo que ocup Dato3 */ Hemos empleado tres variables para guardar tres datos. Si tenemos 20 datos, necesitaremos 20 variables? Y 3000 variables para 3000 datos? Sera tremendamente ineficiente, y no tendra mucho sentido. Es de suponer que no sea as. En la prctica, basta con dos variables, que nos indicarn el principio de la lista y la posicin actual, o incluso slo una para el principio de la lista. Por ejemplo, una rutina que muestre en pantalla toda la lista se podra hacer de forma recursiva as: void MuestraLista ( Ficha *inicial ) { if (inicial) /* Si realmente hay lista */ { printf("Nombre: %s\n", inicial->nombre); printf("Direccin: %s\n", inicial->direccion); printf("Edad: %s\n", inicial->edad); MuestraLista ( inicial->siguiente ); /* Y mira el siguiente */ } } Lo llamaramos con "MuestraLista(Dato1)", y a partir de ah el propio procedimiento se encarga de ir mirando y mostrando los siguientes elementos hasta llegar a NULL, que indica el final. 6.4.2. Codigos de ejemplos del funcionamiento de una lista Antes de seguir, vamos a juntar todo esto en un programa, para comprobar que realmente funciona: aadimos los 3 datos y decimos que los muestre desde el primero; luego borramos el del medio y los volvemos a mostrar:
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
88
Listado 6.4.1 #include <string.h> #include <stdio.h> #include <stdlib.h> #include <conio.h> typedef struct f /* Estos son los datos que guardamos: */ { char nombre[30]; /* Nombre, hasta 30 letras */ char direccion[50]; /* Direccion, hasta 50 */ int edad; /* Edad, un numero < 255 */ struct f* siguiente; /* Y direccin de la siguiente */ } Ficha; Ficha *dato1; Ficha *dato2; Ficha *dato3; /* Va a ser un puntero a ficha */ /* Otro puntero a ficha */ /* Y otro ms */
void MuestraLista ( Ficha *inicial ) { if (inicial) /* Si realmente hay lista */ { printf("Nombre: %s\n", inicial->nombre); printf("Direccin: %s\n", inicial->direccion); printf("Edad: %d\n\n", inicial->edad); MuestraLista ( inicial->siguiente ); /* Y mira el siguiente */ } } int main() { dato1 = (Ficha*) malloc (sizeof(Ficha)); /* Reservamos memoria */ strcpy(dato1->nombre, "Pepe"); /* Guardamos el nombre, */ strcpy(dato1->direccion, "Su casa"); /* la direccin */ dato1->edad = 40; /* la edad */ dato1->siguiente = NULL; /* y no hay ninguna ms */ dato2 = (Ficha*) malloc (sizeof(Ficha)); /* Reservamos memoria */ strcpy(dato2->nombre, "Juan"); /* Guardamos el nombre, */ strcpy(dato2->direccion, "No lo s"); /* la direccin */ dato2->edad = 35; /* la edad */ dato2->siguiente = NULL; /* y no hay ninguna ms */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas dato1->siguiente = dato2; /* Enlazamos la anterior con ella */ dato3 = (Ficha*) malloc (sizeof(Ficha)); /* La tercera */ strcpy(dato3->nombre, "Carlos"); strcpy(dato3->direccion, "Por ah"); dato3->edad = 14; dato3->siguiente = dato2; /* enlazamos con la siguiente */ dato1->siguiente = dato3; /* y la anterior con ella */ printf("La lista inicialmente es:\n"); MuestraLista (dato1); dato1->siguiente = dato2; free(dato3); /* Borrar dato3: Enlaza Dato1 y Dato2 */ /* Libera lo que ocup Dato3 */
89
El siguiente programa se plantea como ejemplo gua para implementar una lista simplemente enlazada con punteros, para gestionar nmeros enteros, ingresados por teclado con funciones de insertar eliminar recorrer y buscar. Las eliminaciones y la bsqueda, se realizan en cualquier lugar de la lista, Listado 6.4.2 #include <iostream.h> #include <stdlib.h> #include <stdio.h> #include <conio.h> struct nodo { int info; struct nodo *sig; }; void crear(struct nodo **); void insertar(struct nodo **, int); void eliminar(struct nodo **, int); void recorrer(struct nodo **); int buscar(struct nodo **, int); //falso o verdadero int main() {
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas clrscr(); struct nodo *ent; int dato; crear(&ent); cout<<"Ingrese un entero, cero para terminar: "; cin>>dato; while(dato != 0) { insertar(&ent, dato); cout<<"Ingrese un entero, cero para terminar: "; cin>>dato; } recorrer(&ent); cout<<"\n\nIngrese dato a eliminar: "; cin>>dato; eliminar(&ent, dato); recorrer(&ent); cout<<"\n\nIngrese dato a buscar: "; cin>>dato; if(buscar(&ent,dato) == 1) { cout<<"numero "<<dato<<" encontrado"; getchar(); } else { cout<<"El dato no existe"; getchar(); } return 0;
90
// funciones de listas simplemente enlazadas void crear(struct nodo **ent) { *ent = NULL; } void insertar(struct nodo **ent, int dato) { struct nodo *aux, *p, *ant; aux = new nodo; if(!aux) { cout<<"error:memoria insuficiente"<<endl; exit(1);
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
91
} aux->info = dato; ant = NULL; p = *ent; //p es el ptro aux que recorre la lista para insertar ORDENADO while((p != NULL) && (p->info < dato)) { ant = p; p = p->sig; } if(ant == NULL) { aux->sig = *ent; *ent = aux; } else { ant->sig = aux; aux->sig = p; } } void eliminar(struct nodo **ent, int dato) { struct nodo *p, *ant; p = *ent; ant = NULL; while((p != NULL) && (p->info < dato)) { ant = p; p = p->sig;
} if(p->info != dato) cout<<"\n Dato no existe "<<endl; else { if(ant == NULL) //1er nodo *ent = (*ent)->sig; else ant->sig = p->sig; delete p; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas while(p != NULL) { cout<<p->info<< " "; p = p->sig; }
92
int buscar(struct nodo **ent, int dato) { struct nodo *p; p = *ent; while((p != NULL) && (p->info < dato)) p = p->sig; if(p->info == dato) return 1; else return 0; } El resultado del listado anterior lo podemos observar en la siguiente grfica, analice el cdigo y plantee modificaciones al programa, en busca de mejoras.
Acontinuacin se presenta otro programa de ejemplo, que crea una lista de nmeros, predefinidos por el programa, va insertando en ella varios valores ordenados. Listado 6.4.3 #include <stdio.h> #include <stdlib.h> #include <conio.h>
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas typedef struct lista { int numero; struct lista* sig; } tipoDatos; typedef tipoDatos *puntero; puntero CrearLista(int valor) /* Crea la lista, claro */ { puntero r; /* Variable auxiliar */ r = (puntero) malloc (sizeof(tipoDatos)); /* Reserva memoria */ r->numero = valor; /* Guarda el valor */ r->sig = NULL; /* No hay siguiente */ return r; /* Crea el puntero */
93
};
void MuestraLista ( puntero lista ) { if (lista) /* Si realmente hay lista */ { printf("%d\n", lista->numero); /* Escribe el valor */ MuestraLista (lista->sig ); /* Y mira el siguiente */ }; }; void InsertaLista( puntero* lista, int valor) { puntero r; /* Variable auxiliar */ puntero actual; actual = *lista; if (actual) /* Si hay lista */ if (actual->numero < valor) /* y todava no es su sitio */ /* hace una llamada recursiva: */ InsertaLista(&actual->sig,valor); /* mira la siguiente posicin */ else /* Caso contrario: si hay lista */ { /* pero hay que insertar ya: */ r = (puntero) malloc (sizeof(tipoDatos)); /*Reserva espacio, */ r->numero = valor; /* guarda el dato */ r->sig = actual; /* pone la lista a continuac. */ *lista = r; /* Y hace que comience en */ } /* el nuevo dato: r */ else /* Si no hay lista */ { /* deber crearla */ r = (puntero) malloc (sizeof(tipoDatos)); /* Reserva espacio, */ r->numero = valor; /* guarda el dato */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas r->sig = NULL; *lista = r; } int main() { puntero l; l = CrearLista(5); InsertaLista(&l, 3); InsertaLista(&l, 2); InsertaLista(&l, 6); MuestraLista(l); getch(); return 0; } /* no hay nada detrs y */ /* hace que la lista comience */ /* en el dato: r */
94
/* La lista que crearemos */ /* Crea una lista e introduce un 5 */ /* Inserta un 3 */ /* Inserta un 2 */ /* Inserta un 6 */ /* Muestra la lista resultante */ /* Se acab */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
95
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 abiertas doblemente enlazadas. Tambin es posible, y potencialmente til, crear listas doblemente enlazadas y circulares.
El movimiento a travs de listas doblemente enlazadas es ms sencillo, y como veremos las operaciones de bsqueda, insercin y borrado, tambin tienen ms ventajas. 6.5.1. Operaciones bsicas con listas doblemente enlazadas: De nuevo tenemos las mismas operaciones sobre este tipo listas:
Aadir o insertar elementos. Buscar o localizar elementos. Borrar elementos. Moverse a travs de la lista, siguiente
y anterior.
6.5.1.1. Aadir un elemento: 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:
El proceso es muy simple, bastar con que: 1. lista apunta a nodo. 2. lista->siguiente y lista->anterior apunten a null.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
96
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: 1. nodo->siguiente debe apuntar a Lista. 2. nodo->anterior apuntar a Lista->anterior. 3. Lista->anterior debe 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 anterior, partiremos de una lista no vaca, y de nuevo para simplificar, que Lista est apuntando al ltimo elemento de la lista:
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas El proceso es el siguiente: 1. nodo->siguiente debe apuntar a Lista->siguiente (NULL). 2. Lista->siguiente debe apuntar a nodo. 3. nodo->anterior apuntar a Lista.
97
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: 1. 2. 3. 4. Hacemos que nodo->siguiente apunte a lista->siguiente. Hacemos que Lista->siguiente apunte a nodo. Hacemos que nodo->anterior apunte a lista. Hacemos que nodo->siguiente->anterior apunte a nodo.
Lo 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. El paso 4 es el ms oscuro, quizs requiera alguna explicacin. Supongamos que disponemos de un puntero auxiliar, "p" y que antes de empezar a insertar nodo, hacemos que apunte al nodo que quedar a continuacin de nodo despus de insertarlo, es decir p = Lista->siguiente.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
98
Ahora empezamos el proceso de insercin, ejecutamos los pasos 1, 2 y 3. El cuarto sera slo hacer que p->anterior apunte a nodo. Pero nodo>siguiente ya apunta a p, as que en realidad no necesitamos el puntero auxiliar, bastar con hacer que nodo->siguiente->anterior apunte a nodo. Aadir elemento en una lista doblemente enlazada, caso general Para generalizar todos los casos anteriores, slo necesitamos aadir una operacin: 1. Si lista est vaca hacemos que Lista apunte a nodo. Y nodo>anterior y nodo->siguiente a NULL. 2. Si lista no est vaca, hacemos que nodo->siguiente apunte a Lista>siguiente. 3. Despus que Lista->siguiente apunte a nodo. 4. Hacemos que nodo->anterior apunte a Lista. 5. Si nodo->siguiente no es NULL, entonces hacemos que nodo>siguiente->anterior apunte a nodo. El paso 1 es equivalente a insertar un nodo en una lista vaca. Los pasos 2 y 3 equivalen a la insercin en una lista enlazada corriente. Los pasos 4, 5 equivalen a insertar en una lista que recorre los nodos en sentido contrario. Existen ms casos, las listas doblemente enlazadas son mucho ms verstiles, pero todos los casos pueden reducirse a uno de los que hemos explicado aqu. 6.5.1.2 Busqueda de elementos de una lista doblemente enlazada. Buscar o localizar un elemento de una lista doblemente enlazada En muchos aspectos, una lista doblemente enlazada se comporta como dos listas abiertas que comparten los datos. En ese sentido, todo lo dicho Pero adems tenemos la ventaja de que podemos avanzar y retroceder desde cualquier nodo, sin necesidad de volver a uno de los extremos de la lista. Por supuesto, se pueden hacer listas doblemente enlazadas no ordenadas, existen cientos de problemas que pueden requerir de este tipo de estructuras. Pero parece que la aplicacin ms sencilla de listas doblemente enlazadas es hacer arrays dinmicos ordenados, donde buscar un elemento concreto a partir de cualquier otro es ms sencillo que en una lista abierta corriente. Pero de todos modos veamos algn ejemplo sencillo. Para recorrer una lista procederemos de un modo parecido al que usbamos con las listas abiertas, ahora no necesitamos un puntero auxiliar, pero tenemos que tener en cuenta que Lista no tiene por qu estar en uno de los extremos:
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
99
1. Retrocedemos hasta el comienzo de la lista, asignamos a lista el valor de lista->anterior mientras lista->anterior no sea NULL. 2. Abriremos un bucle que al menos debe tener una condicin, que el ndice no sea NULL. 3. Dentro del bucle asignaremos a lista el valor del nodo siguiente al 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; struct _nodo *anterior; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Lista; ... pNodo = indice; ... indice = Lista; while(indice->anterior) indice = indice->anterior; while(indice) { cout<<"%d\n", indice->dato); indice = indice->siguiente; } ... Es importante que no perdamos el nodo Lista, si por error le asignramos un valor de un puntero a un nodo que no est en la lista, no podramos acceder de nuevo a ella. Es por eso que tendremos especial cuidado en no asignar el valor NULL a Lista. 6.5.1.3. Eliminar un elemento de una lista doblemente enlazada: Analizaremos tres casos diferentes: 1. 2. 3. 4. Eliminar el nico nodo de una lista doblemente enlazada. Eliminar el primer nodo. Eliminar el ltimo nodo. Eliminar un nodo intermedio.
Para los casos que lo permitan consideraremos dos casos: que el nodo a eliminar es el actualmente apuntado por Lista o que no. Eliminar el nico nodo en una lista doblemente enlazada: En este caso, ese nodo ser el apuntado por Lista.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
100
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>siguiente.
1. Si nodo apunta a Lista, hacemos que Lista apunte a Lista>siguiente. 2. Hacemos que nodo->siguiente->anterior apunte a NULL 3. 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->anterior.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
101
1. Si nodo apunta a Lista, hacemos que Lista apunte a Lista->anterior. 2. Hacemos que nodo->anterior->siguiente apunte a NULL 3. 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 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 Lista->anterior o Lista->siguiente Se trata de un caso ms general de los dos casos anteriores..
1. Si nodo apunta a Lista, hacemos que Lista apunte a Lista->anterior (o Lista->siguiente). 2. Hacemos que nodo->anterior->siguiente apunte a nodo->siguiente. 3. Hacemos que nodo->siguiente->anterior apunte a nodo->anterior. 4. Borramos el nodo apuntado por nodo.
Eliminar un nodo de una lista doblemente enlazada, caso general: 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->anterior, si no es NULL o Lista->siguiente en caso contrario. 1. Si nodo apunta a Lista, o Si Lista->anterior no es NULL hacemos que Lista apunte a Lista->anterior. o Si Lista->siguiente no es NULL hacemos que Lista apunte a Lista->siguiente. o Si ambos son NULL, hacemos que Lista sea NULL. 2. Si nodo->anterior no es NULL, hacemos que nodo->anterior>siguiente apunte a nodo->siguiente.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
102
3. Si nodo->siguiente no es NULL, hacemos que nodo->siguiente>anterior apunte a nodo->anterior. 4. Borramos el nodo apuntado por nodo. Ejemplo de lista doblemente enlazada Como en el caso de los ejemplos anteriores, construiremos una lista doblemente enlazada para almacenar nmeros enteros. Para aprovechar mejor las posibilidades de estas listas, haremos que la lista est ordenada. Haremos pruebas insertando varios valores, buscndolos y eliminndolos alternativamente para comprobar el resultado. Algoritmo de insercin 1. El primer paso es crear un nodo para el dato que vamos a insertar. 2. Si Lista est vaca, o el valor del primer elemento de la lista es mayor que el del nuevo, insertaremos el nuevo nodo en la primera posicin de la lista. 3. En caso contrario, buscaremos el lugar adecuado para la insercin, tenemos un puntero "anterior". Lo inicializamos con el valor de Lista, y avanzaremos mientras anterior->siguiente no sea NULL y el dato que contiene anterior->siguiente sea menor o igual que el dato que queremos insertar. 4. Ahora ya tenemos anterior sealando al nodo adecuado, as que insertamos el nuevo nodo a continuacin de l. 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 */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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;
103
Algoritmo de la funcin "Borrar": 1. Localizamos el nodo de valor v 2. Existe? o SI: Es el nodo apuntado por lista? SI: Hacer que lista apunte a otro sitio. Es el primer nodo de la lista? NO: nodo->anterior->siguiente = nodo->siguiente Es el ltimo nodo de la lista? NO: nodo->siguiente->anterior = nodo->anterior Borrar nodo 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; /* 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);
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
104
escribir una pequea prueba para verificar el funcionamiento. Le propongo realice las modificaciones pertinentes para que el programa permita ingresar los datos en tiempo de ejecucin, es decir, desde el teclado.
Listado 6.5.1 #include <stdlib.h> #include <conio.h> #include <stdio.h> #include <iostream.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() { clrscr(); Lista lista = NULL; pNodo p; Insertar(&lista, 20); Insertar(&lista, 10); Insertar(&lista, 40); Insertar(&lista, 30); MostrarLista(lista, ASCENDENTE); MostrarLista(lista, DESCENDENTE); Borrar(&lista, 10); Borrar(&lista, 15);
A continuacin se presenta el cdigo completo como ejemplo de la implementacin de una lista doblemente enlazada. Tan slo nos queda
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Borrar(&lista, 45); Borrar(&lista, 30); MostrarLista(lista, ASCENDENTE); MostrarLista(lista, DESCENDENTE); BorrarLista(&lista); system("PAUSE"); getch(); return 0;
105
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; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas /* Buscar el nodo de valor v */ nodo = *lista; while(nodo && nodo->valor < v) nodo = nodo->siguiente; while(nodo && nodo->valor > v) nodo = nodo->anterior; /* 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);
106
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) cout<<"Lista vacia"; nodo = lista; if(orden == ASCENDENTE) { while(nodo->anterior) nodo = nodo->anterior; cout<<"Orden ascendente: "; while(nodo) { cout<<nodo->valor; nodo = nodo->siguiente;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } else { while(nodo->siguiente) nodo = nodo->siguiente; cout<<"Orden descendente: "; while(nodo) { cout<<nodo->valor; nodo = nodo->anterior; } } } cout<<"\n"; }
107
El resultado del anterior listado 6.5.1 se resume en lo que muestra la siguiente grfica despus de las insertar, ordenar, eliminar y ordenar nuevamente.
El siguiente programa implementa una lista doblemente enlazada que permite el ingreso de datos en tiempo de ejecucin conun men de opciones, apuntadores y funciones de crear, visualizar, eliminar y buscar un registro de la lista. Listado 6.5.2 #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 struct direc *ant; //PUNTERO AL REGISTRO ANTERIOR };
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas struct direc *ppio; //PUNTERO A LA PRIMERA ENTRADA ALA LISTA struct direc *final; //PUNTERO ALA ULTIMA ENTRADA struct direc *buscar(char *); void intro(void); void buscar(void); void listar(void); void eliminar(struct direc **, struct direc **); void dl_insert(struct direc *i, struct direc **ppio, struct direc **final); void leecad(char *, char *, int), mostrar(struct direc *); int menu(void); 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); } } }
108
//selecionar una operacion int menu(void) { 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;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas cout<<"5. Salir" <<endl; do { cout<<"\nIntroduce una opcion: "; gets(s); c = atoi(s); }while(c<0 || c>5); clrscr(); return c; }
109
//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(); }
/* Esta funcion lee una cadena de longitud maxima cont y previene el desbordamiento de la cadena. tambien visualiza un mensaje indicativo */ void leecad(char *indic, char *s, int cont) {
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas char p[255]; do { printf(indic); fgets(p, 254, stdin); }while(strlen(p) > cont); p[strlen(p)-1] = 0; //Eliminar el salto de linea strcpy(s, p);
110
// crear una lista doblemente enlazada void dl_insert( struct direc *i, //nuevo elemento struct direc **ppio, //primer elemento de la lista struct direc **final //ultimo elemento de la lista ) { struct direc *ant, *p; if(*final == NULL) //primer elemento de la lista { i->sig = NULL; i->ant = NULL; *final = i; *ppio = i; return; } p = *ppio; //principio de la lista ant = NULL; while(p) { if(strcmp(p->nombre, i->nombre) <0) { ant = p; p = p->sig; } else { if(p->ant) { p->ant->sig = i; i->sig = p; i->ant = p->ant; p->ant = i;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas *ppio = i; return; } i->sig = p; //nuevo primer elemento i->ant = NULL; p->ant = i; *ppio = i; return;
111
} } 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 { 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
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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
112
//mostrar la lista entera void listar(void) { struct direc *info; info = ppio; while(info) { mostrar(info); info = info->sig; //obtener la siguiente direccion } 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) {
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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(); }
113
Los inconvenientes, por el contrario son: 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.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
114
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 (flag) que seale cundo es nodo cabecera.
El campo de la informacin del nodo cabecera no se utiliza, lo que se seala con el sombreado de dicho campo. Una lista enlazada circularmente vaca se representa como se muestra LISTA NULL
6.6.1. 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: 1. lista apunta a nodo. 2. lista->siguiente apunte a nodo.
6.6.2. 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:
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 1. Hacemos que nodo->siguiente apunte a lista->siguiente. 2. Despus que lista->siguiente apunte a nodo.
115
6.6.3. Aadir elemento en una lista circular, caso general: Para generalizar los dos casos anteriores, slo necesitamos aadir una operacin: 1. Si lista est vaca hacemos que lista apunte a nodo. 2. Si lista no est vaca, hacemos que: nodo->siguiente apunte a lista->siguiente. 3.Despus que lista->siguiente apunte a nodo. La implementacin de las listas circulares queda propuesta como ejercicio de aplicacin, para que sea realizada por parte de los estudiantes, en pequeos grupos colaborativos con la participacin del tutor.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas El mtodo de ordenacin por mezclas, El mtodo de ordenacin rpida (quicksort)
116
Ejercicio 4. 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 5. 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. Ejercicio 6. Las listas doblemente ligadas tienen nodos que estn divididos en tres segmentos:
1. Anterior: Un apuntador a un nodo 2. Info: La informacin de un nodo 3. Siguiente: Un apuntador a un nodo Implemente las operaciones borrarNodo(p), insertarNodoAntes e insertarNodoDespues.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
117
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
118
Captulo 7. rboles
7.1. Teora general de rboles Los rboles son, sin duda, una de las estructuras de datos no lineales, ms empleadas en informtica, tanto para resolver problemas de hardware como de software. Los rboles de directorios son una de las organizaciones ms empleada por cualquier usuario o programador de una computadora. En esta unida se describen los tipos de rboles ms sobresalientes tales como los generales, binarios o binarios de bsqueda. 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 y para representar la estructura sintctica de un programa fuente en compiladores. Despues de haber conceptualizado la segunda unidad y haber realizado la implementacin de los programas de aplicacin con Arreglos y Apuntadores, presentamos otra alternativa para la aplicacin y conceptualizacin de los rboles se recomienda que se realice por medio del entorno grfico que nos presenta el compilador de C/C++, de esta manera nos vamos acercando a la programacin orientada a objetos.
Los rboles son estructuras parecidas a las listas enlazadas, en el sentido que tienen punteros que sealan a otros elementos, pero 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 "cuelgan" 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 no lineal en la que cada nodo puede apuntar a uno o varios nodos. Tambin se suele dar una definicin recursiva: un rbol es una estructura compuesta por un dato y varios rboles. Esto son definiciones simples. Pero las caractersticas que implican no lo son tanto.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
119
Definiremos varios conceptos. En relacin con otros nodos: 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'.
Nodo
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: 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'.
Nodo
Un rbol en el que en cada nodo o bien todos o ninguno de los hijos existe, se llama rbol completo. En una cosa, los rboles se parecen al resto de las estructuras que hemos visto: dado un nodo cualquiera de la estructura, podemos considerarlo como una estructura independiente. Es decir, un nodo cualquiera puede ser considerado como la raz de un rbol completo. Existen otros conceptos que definen las caractersticas del rbol, en relacin a su tamao:
Orden: es el nmero potencial de hijos que puede tener cada elemento de rbol. De este modo, diremos que un rbol en el que cada
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
120
nodo puede apuntar a otros dos es de orden dos, si puede apuntar a tres ser de orden tres, etc. Grado: el nmero de hijos que tiene el elemento con ms hijos dentro del rbol. En el rbol del ejemplo, el grado es tres, ya que tanto 'A' como 'D' tienen tres hijos, y no existen elementos con ms de tres hijos. Nivel: se define para cada elemento del rbol como la distancia a la raz, medida en nodos. El nivel de la raz es cero y el de sus hijos uno. As sucesivamente. En el ejemplo, el nodo 'D' tiene nivel 1, el nodo 'G' tiene nivel 2, y el nodo 'N', nivel 3. Altura: la altura de un rbol se define como el nivel del nodo de mayor nivel. Como cada nodo de un rbol puede considerarse a su vez como la raz de un rbol, tambin podemos hablar de altura de ramas. El rbol del ejemplo tiene altura 3, la rama 'B' tiene altura 2, la rama 'G' tiene altura 1, la 'H' cero, etc. Los rboles de orden dos son bastante especiales, de hecho ampliaremos un poco la informacin. Estos rboles se conocen tambin como rboles binarios. Frecuentemente, aunque tampoco es estrictamente necesario, para hacer ms fcil moverse a travs del rbol, aadiremos un puntero a cada nodo que apunte al nodo padre. De este modo podremos avanzar en direccin a la raz, y no slo hacia las hojas. Es importante conservar siempre el nodo raz ya que es el nodo a partir del cual se desarrolla el rbol, si perdemos este nodo, perderemos el acceso a todo el rbol. El nodo tpico de un rbol difiere de los nodos que hemos visto hasta ahora para listas, aunque slo en el nmero de nodos. Veamos un ejemplo de nodo para crear rboles de orden tres: struct nodo { int dato; struct nodo *rama1; struct nodo *rama2; struct nodo *rama3; }; O generalizando ms: #define ORDEN 5 struct nodo { int dato; struct nodo *rama[ORDEN]; }; El movimiento a travs de rboles, salvo que implementemos punteros al nodo padre, ser siempre partiendo del nodo raz hacia un nodo hoja. Cada vez que lleguemos a un nuevo nodo podremos optar por cualquiera de los nodos a los que apunta para avanzar al siguiente nodo.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
121
Un ejemplo de estructura en rbol es el sistema de directorios y ficheros de un sistema operativo. Aunque en este caso se trata de rboles con nodos de dos tipos, nodos directotio y nodos fichero, podramos considerar que los nodos hoja son ficheros y los nodos rama son directorios. 7.2. Operaciones bsicas con rboles. Salvo que trabajemos con rboles especiales, como los que veremos ms adelante, las inserciones sern siempre en punteros de nodos hoja o en punteros libres de nodos rama. Con estas estructuras no es tan fcil generalizar, ya que existen muchas variedades de rboles. De nuevo tenemos casi el mismo repertorio de operaciones de las que disponamos con las listas:
Aadir o insertar elementos. Buscar o localizar elementos. Borrar elementos. Moverse a travs del rbol. Recorrer el rbol completo.
Los algoritmos de insercin y borrado dependen en gran medida del tipo de rbol que estemos implementando, de modo que por ahora los pasaremos por alto y nos centraremos ms en el modo de recorrer rboles.
7.3. rboles ordenados A partir del siguiente captulo slo hablaremos de rboles ordenados, ya que son los que tienen ms inters desde el punto de vista de TAD, y los que tienen ms aplicaciones genricas. Un rbol ordenado, en general, es aquel a partir del cual se puede obtener una secuencia ordenada siguiendo uno de los recorridos posibles del rbol: inorden, preorden o postorden. En estos rboles es importante que la secuencia se mantenga ordenada aunque se aadan o se eliminen nodos. Existen varios tipos de rboles ordenados, que veremos a continuacin: rboles binarios de bsqueda (ABB): son rboles de orden 2 que mantienen una secuencia ordenada si se recorren en inorden. rboles AVL: son rboles binarios de bsqueda equilibrados, es decir, los niveles de cada rama para cualquier nodo no difieren en ms de 1. rboles perfectamente equilibrados: son rboles binarios de bsqueda en los que el nmero de nodos de cada rama para cualquier nodo no difieren en ms de 1. Son por lo tanto rboles AVL tambin.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
122
rboles 2-3: son rboles de orden 3, que contienen dos claves en cada nodo y que estn tambin equilibrados. Tambin generan secuencias ordenadas al recorrerlos en inorden. rboles-B: caso general de rboles 2-3, que para un orden M, contienen M-1 claves.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
123
8.1. Arboles Binarios. Este tipo de rbol se caracteriza porque tienen un vrtice principal y de l se desprende dos ramas. La rama izquierda y la rama derecha: VRTICE PRINCIPAL principal
RAMA IZQUIERDA
RAMA DERECHA
La rama izquierda y la derecha, tambin son dos rboles binarios. El Vrtice principal se denomina raz y cada una de las ramas se denomina rbol izquierdo y rbol derecho. Por ejemplo:
A B C D E
La raz de este rbol es A y el rbol izquierdo est conformado por otro rbol:
B C D
Que a su vez tiene como raz B. El rbol derecho est conformado tambin por otro rbol. E
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Este ltimo no tiene ramificaciones.
124
Nodo: Un rbol binario es un conjunto de elementos cada uno de los cuales se denomina nodo. Un rbol Binario puede tener cero nodos y este caso se dice que est vaco. Puede tener un slo nodo, y en este caso solamente existe la raz del rbol o puede tener un nmero finito de nodos. Cada nodo puede estar ramificado por la izquierda o por la derecha o puede no tener ninguna ramificacin. Padre: Un Padre es un nodo que puede o no tener ramificaciones. Por ejemplo: A B B D CASO1 CASO2 CASO3 A C
En los tres casos el nodo A es un padre. En el caso 1 es un padre que no tiene hijos. En el caso 2, el nodo A es el padre del nodo B. En el caso 3 el nodo A es padre de los nodos B y C pero no es padre del nodo D. Hijo: En el ejemplo anterior. El caso 1 el nodo A no tiene hijos. En el caso 2,B es un hijo del nodo A y en caso 3, D es hijo de B y el Padre de B es el nodo A. Hermano: Nos referimos al caso 3 del ejemplo anterior. Los hermanos son los hijos de un mismo padre. Los nodos B y C son hermanos. El nodo D no tiene Hermanos. Hoja: Una hoja es un nodo que no tiene ramificaciones. Por ejemplo A
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
125
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.
G Al nodo C podemos llegar desde el nodo B. Nunca se puede examinar el nodo B a partir del nodo C. Los apuntadores derecho o izquierdo de cualquier nodo apuntan al rbol derecho o izquierdo que siguen a ese nodo. Nunca apuntan a los nodos precedentes. Un Camino, es el conjunto de nodos que tenemos que visitar con el propsito de llegar a un nodo especfico. Por ejemplo para llegar al nodo F, es necesario recorrer el camino: A D F
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas A D E G
126
Obsrvese que los Caminos se configuran siempre hacia abajo. Longitud: Longitud es el nmero de nodos que se deben recorrer para pasar de un nodo a otro. Por ejemplo: A G
La longitud entre A y E es 3. La longitud entre G y G es 0. La longitud entre A y B es 1. Obsrvese que no podemos calcular la longitud entre B y G ya que el camino B A G no existe. Descendiente: El nodo C es descendiente del nodo A si a partir de A podemos llegar a C a travs de un camino. Por ejemplo:
A B D
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
127
Ancestro: El nodo A es un ancestro del nodo C si existe un camino entre A y C. Basndonos en el ejemplo anterior, A es un ancestro de C ya que existe un camino entre los nodos. No se puede hablar de que D sea un ancestro de C ya que el camino D A B C no existe. Nivel: Cada nodo tiene un nivel dentro de un rbol binario. Por definicin el nodo raz tiene un nivel 0 y los dems nodos tienen el nivel de su padre ms 1. Por esto los nodos que son hijos del nodo raz tienen un nivel 1. Veamos este ejemplo:
Nivel 0
Nivel 1 Nivel 2
F G
P V
Nivel 3
Los nodos A, M y S tienen un nivel 0 en tanto que los nodos G y V tienen un nivel 3 Obsrvese que el nivel del nodo G es la longitud del camino desde la raz hasta el nodo. Grado de un Nodo: El grado de un nodo es el nmero de hijos. Por ejemplo el grado del nodo A es 2, el grado del nodo T es 1. El grado de un nodo terminal siempre es 0. En los rboles binarios, el grado de un nodo flucta entre 0 y 2.
Altura: La altura de un rbol binario es el nivel de la hoja o de las hojas que estn ms distantes de la raz. Basndose en el ejemplo anterior, la altura del rbol cuya raz es A, corresponde a la longitud del camino para llegar a la hoja ms distante de la raz, En este caso ser 3. La altura del rbol cuya raz es M, corresponde al nivel de la hoja P. Arbol Binario completo: Un rbol binario completo es aquel en el que todo nodo no terminal tiene sus dos hijos. El siguiente es un rbol binario completo de nivel 3.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
128
B C E J
Obsrvese que todos los nodos no terminales tienen sus dos hijos. El mximo nmero de nodos que puede tener un rbol de nivel n es : 2 +2+2+2...+2 n
Si n es 3 entonces: 2 +2+2+2 = 15 Este rbol es un rbol binario completo de nivel 3 y ste es el mximo nmero de nodos que puede tener un rbol de nivel 3. Arbol binario Igual: Dos rboles son iguales si los dos son vacos. Existe otro caso en el cual dos rboles son iguales:
A C
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
129
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, necesario que el contenido de cada uno de sus respectivos nodos sea el mismo y que tengan las mismas relaciones de parentesco. Arbol Binario Semejante: Dos rboles 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:
C A
B C
Estos rboles son semejantes. Contienen los mismos valores en cada uno de sus nodos. Arbol 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.
C E
F H
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
130
Peso: El peso de un rbol en un nodo dado es el nmero de nodos en el rbol sin contarse el mismo. Por ejemplo: A P
El peso del rbol cuya raz es A, corresponde al nmero de nodos de ese rbol: 4. Los nodos Q, C y R tienen un peso de 2. 8.2. Forma de Recorrer un Arbol Binario Preorden: Recorrer un rbol en preorden consiste en: -Examinar el dato del nodo raz -Recorrer el rbol izquierdo en preorden -Recorrer el rbol derecho en preorden
A C B D ABDECFG F G
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
131
10
15
14
17
16
20
Inorden: Recorrer un rbol en Inorden consiste en: - Recorrer el rbol izquierdo en inorden - Examinar la raz - Recorrer el rbol derecho en inorden Por ejemplo: 10
12
11
15
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Debemos recorrer en inorden el rbol a la izquierda de la raz:
132
Al recorrer el rbol en inorden los resultados son: 3 5 7 Al terminar de recorrer el rbol a la izquierda de la raz, debemos examinar la raz y luego recorrer en inorden el rbol a la derecha de la raz.
12
11
15
Con lo cual al examinar todo el rbol en inorden los datos impresos sern: 3 5 7 10 11 12 15
Por ltimo estudiemos la tercera forma de recorrer un rbol binario. Posorden: Examinar un rbol binario en posorden consiste en: Recorrer el rbol izquierdo en posorden Recorrer el rbol derecho en posorden Examinar raz
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Veamos un ejemplo: A
133
Al recorrer el rbol izquierdo en posorden , el nico dato impreso ser B. Despus de hacer recorrido todo el rbol de la izquierda en posorden, se debe recorrer todo el rbol de la derecha en posorden. Al recorrer el rbol de la derecha en posorden , el nico dato impreso ser C. Una vez recorridos los rboles izquierdo y derecho, debemos examinar la raz . Segn este caso los datos impresos sern: B C A
Dado el siguiente rbol Cules seran los datos impresos si se recorre en: Preorden, Inorden , Posorden. P Q
R V T U W Y X Z
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Preorden: P Q S T R U W X V Y Z Inorden: S Q T P W U X R Y V Z Posorden: S T Q P W X U Y Z V R P
134
bol binario de busqueda Para puntualizar aun ms, trataremos los rboles binarios de bsqueda, en los que tenemos prefijado un cierto orden, que nos ayudar a encontrar un cierto dato dentro de un rbol con mucha rapidez. Y como es este "orden prefijado"? Sencillo: para cada nodo tendremos que:
la rama de la izquierda contendr elementos menores. la rama de la derecha contendr elementos mayores.
Asusta? Con un ejemplo seguro que no: Vamos a introducir en un rbol binario de bsqueda los datos 5,3,7,2,4,8,9 5 Primer nmero: 5 (directo) Segundo nmero: 3 (menor que 5) / 3 5
Tercer nmero: 7 (mayor que 5) 5 / \ 3 7 Cuarto: 2 (menor que 5, menor que 3) 5 / \ 3 / 2 Quinto: 4 (menor que 5, mayor que 3) 7
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 5 / \ 3 / \ 2 4 7
135
Sptimo: 9 (mayor que 5, mayor que 7, mayor que 8) 5 / \ 3 / \ 2 4 7 \ 8 \ 9 Y qu ventajas tiene esto? Pues la rapidez: tenemos 7 elementos, lo que en una lista supone que si buscamos un dato que casualmente est al final, haremos 7 comparaciones; en este rbol, tenemos 4 alturas => 4 comparaciones como mximo. Y si adems hubiramos "equilibrado" el rbol (irlo recolocando, de modo que siempre tenga la menor altura posible), seran 3 alturas. Esto es lo que se hace en la prctica cuando en el rbol se va a hacer muchas ms lecturas que escrituras: se reordena internamente despus de aadir cada nuevo dato, de modo que la altura sea mnima en cada caso. De este modo, el nmero mximo de comparaciones que tendramos que hacer sera log2(n), lo que supone que si tenemos 1000 datos, en una lista podramos llegar a tener que hacer 1000 comparaciones, y en un rbol binario, log2(1000) => 10 comparaciones como mximo. La ganancia en velocidad de bsqueda es clara. No vamos a ver cmo se hace eso de los "equilibrados", que considero que sera propio de un curso de programacin ms avanzado, o incluso de uno de "Tipos Abstractos de Datos" o de "Algortmica", y vamos a empezar a ver rutinas para manejar estos rboles binarios de bsqueda. Despues de haber trabajado la segunda unidad con la implementacin de estructuras dinmicas lineales con punteros, se recomienda que la tercera
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
136
unidad se realice por medio del modogrfico, solo que para poder ejecutar cualquier progrma que trabaje con las librerias graficas el compilador de C++ o Turbo C, debe habiltarse esa funcin, asi:
Para probar la configuracin de su compilador lo invito a que pruebe el siguiente listado, es un buen pequeo acercamiento a la implementacin de un rbol binario, se incluir otro listado como implementacin de un rbol binario haciendo uso del modo grfico en los anexos 2 del mdulo. Listado 8.2 #include<graphics.h> #include<iostream.h> #include<string.h> #include<dos.h> #include<conio.h>
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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 int ingresar(char a); 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,z; texto(); //llama la caja de texto outtextxy(55,388,"Cuandos hijos tiene A "); gotoxy(31,25); 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(145,90,"B"); //b if(A==2)
137
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas { 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(447,90,"C"); } z=ingresar('B'); gotoxy(20,8);cout<<z; 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(67,180,"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(67,180,"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 outtextxy(215,180,"G"); //G } z=ingresar('D'); gotoxy(10,13);cout<<z; 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(15,240,"E"); z=ingresar('E'); gotoxy(4,17);cout<<z; } if(D==2) //E Y F
138
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas { 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(15,240,"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(107,240,"F"); z=ingresar('E'); gotoxy(4,17);cout<<z; z=ingresar('F'); gotoxy(15,17);cout<<z; } if(B==2) { z=ingresar('G'); gotoxy(28,13);cout<<z; 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(166,240,"H"); setcolor(5); z=ingresar('H'); gotoxy(22,17);cout<<z; } 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(166,240,"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(255,240,"I"); z=ingresar('H'); gotoxy(22,17);cout<<z; z=ingresar('I'); gotoxy(33,17);cout<<z; }
139
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } } //termina lado izquierdo if(A==2) { z=ingresar('C'); gotoxy(58,8);cout<<z; 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(513,180,"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(372,180,"M"); 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(513,180,"P"); } z=ingresar('P'); gotoxy(66,13);cout<<z; 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(555,240,"Z"); z=ingresar('Z'); gotoxy(71,17);cout<<z; }
140
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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(475,240,"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(555,240,"Z"); z=ingresar('Z'); gotoxy(71,17);cout<<z; z=ingresar('Q'); gotoxy(61,17);cout<<z; } if(C==2) { z=ingresar('M'); gotoxy(48,13);cout<<z; 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 outtextxy(326,240,"N"); z=ingresar('N'); gotoxy(42,17);cout<<z; } 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(326,240,"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(416,240,"O"); z=ingresar('N'); gotoxy(42,17);cout<<z; z=ingresar('O'); gotoxy(53,17);cout<<z; } }
141
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } //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(10); } for(i=1; i<ty; i++) { outtextxy(px2,i+py2,"."); delay(10); } } int linea_der(int tx, int px1, int py1, int ty, int px2, int py2) { for(int i=1; i<tx; i++) { outtextxy(px1+i,py1,"."); delay(10); } for(i=1; i<ty; i++) { } outtextxy(px2,i+py2,"."); delay(10);
142
int presentacion() {
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
143
cajadetexto_a(12,25,130,30);//px,py,largo,ancho A cuadro de mensaje arbo cajadetexto_a(482,25,130,30);//px,py,largo,ancho A cuadro de mensaje carlos sleep(1); setcolor(11); outtextxy(15,32,"Arboles"); sleep(1); outtextxy(68,44,"Binarios"); sleep(1); setcolor(11); outtextxy(495,32,"Carlos Javier"); sleep(1); outtextxy(524,44,"Guzman"); } int texto() { 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 spbrescribir } if(n==1 || n==2) { return n; } return n; } int ingresar(char a) { int v; outtextxy(55,388,"Ingrese valor para "); // gotoxy(27,25); cout<<a; gotoxy(31,25); cin>>v; texto();// llama caja de texto para no spbrescribir// return v; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
144
Recordemos que la idea importante es que todo dato menor estar a la izquierda del nodo que miramos, y los datos mayores estarn a su derecha. Ahora la estructura de cada nodo (dato) ser: typedef int TipoDato; typedef struct t { TipoDato dato; struct t* hijoIzq; struct t* hijoDer; } TipoBase; typedef TipoBase* puntero; /* Vamos a guardar enteros */ /* El tipo base en s: */ /* - un dato */ /* - puntero a su hijo izquierdo */ /* - puntero a su hijo derecho */
Y las rutinas de insercin, bsqueda, escritura, borrado, etc., podrn ser recursivas. Como primer ejemplo, la de escritura de todo el rbol (la ms sencilla) sera: void Escribir(puntero punt) { if (punt) /* Si no hemos llegado a una hoja */ { Escribir(punt->hijoIzq); /* Mira la izqda recursivamente */ printf("%d ",punt->dato); /* Escribe el dato del nodo */ Escribir(punt->hijoDer); /* Y luego mira por la derecha */ }; };
La rutina de insercin sera parecida, aunque algo ms "pesada" porque tenemos que pasar el puntero por referencia, para que se pueda modificar el puntero: void Insertar(puntero* punt, TipoDato valor) { puntero actual= *punt; if (actual == NULL) /* Si hemos llegado a una hoja */ { *punt = (puntero) malloc (sizeof(TipoBase)); /* Reserv. memoria */ actual= *punt; actual->dato = valor; /* Guardamos el dato */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas actual->hijoIzq = NULL; actual->hijoDer = NULL; /* No tiene hijo izquierdo */ /* Ni derecho */
145
};
} else /* Si no es hoja */ if (actual->dato > valor) /* Y encuentra un dato mayor */ Insertar(&actual->hijoIzq, valor); /* Mira por la izquierda */ else /* En caso contrario (menor) */ Insertar(&actual->hijoDer, valor); /* Mira por la derecha */
Y finalmente, la de borrado de todo el rbol, casi igual que la de escritura, slo que en vez de borrar la izquierda, luego el nodo y luego la derecha, borraremos primero las dos ramas y luego el nodo para evitar incongruencias (borrar el hijo de algo que ya no existe): void Borrar(puntero punt) { if (punt) /* Si no hemos llegado a una hoja */ { Borrar(punt->hijoIzq); /* Va a la izqda recursivamente */ Borrar(punt->hijoDer); /* Y luego va por la derecha */ free(punt); /* Libera lo que ocupa el nodo */ } } todo esto en un ejemplo "que funcione":
#include <stdio.h> #include <stdlib.h> #include <conio.h> typedef int TipoDato; typedef struct t { TipoDato dato; struct t* hijoIzq; struct t* hijoDer; } TipoBase; typedef TipoBase* puntero;
/* Vamos a guardar enteros */ /* El tipo base en s: */ /* - un dato */ /* - puntero a su hijo izquierdo */ /* - puntero a su hijo derecho */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas void Escribir(puntero punt) { if (punt) /* Si no hemos llegado a una hoja */ { Escribir(punt->hijoIzq); /* Mira la izqda recursivamente */ printf("%d ",punt->dato); /* Escribe el dato del nodo */ Escribir(punt->hijoDer); /* Y luego mira por la derecha */ } } void Insertar(puntero* punt, TipoDato valor) { puntero actual= *punt;
146
if (actual == NULL) /* Si hemos llegado a una hoja */ { *punt = (puntero) malloc (sizeof(TipoBase)); /* Reserv. memoria */ actual= *punt; actual->dato = valor; /* Guardamos el dato */ actual->hijoIzq = NULL; /* No tiene hijo izquierdo */ actual->hijoDer = NULL; /* Ni derecho */ } else /* Si no es hoja */ if (actual->dato > valor) /* Y encuentra un dato mayor */ Insertar(&actual->hijoIzq, valor); /* Mira por la izquierda */ else /* En caso contrario (menor) */ Insertar(&actual->hijoDer, valor); /* Mira por la derecha */
/* Cuerpo del programa */ int main() { puntero arbol = NULL; Insertar(&arbol, 5); Insertar(&arbol, 3); Insertar(&arbol, 7); Insertar(&arbol, 2); Insertar(&arbol, 4); Insertar(&arbol, 8); Insertar(&arbol, 9); Escribir(arbol); } return 0;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
147
8.3. Operaciones en ABB El repertorio de operaciones que se pueden realizar sobre un ABB es parecido al que realizbamos sobre otras estructuras de datos, ms alguna otra propia de rboles:
Buscar un elemento. Insertar un elemento. Borrar un elemento. Movimientos a travs del rbol: o Izquierda. o Derecha. o Raiz. Informacin: o Comprobar si un rbol est vaco. o Calcular el nmero de nodos. o Comprobar si el nodo es hoja. o Calcular la altura de un nodo. o Calcular la altura de un rbol.
Buscar un elemento Partiendo siempre del nodo raz, el modo de buscar un elemento se define de forma recursiva.
Si
el rbol est vaco, terminamos la bsqueda: el elemento no est en el rbol. Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la bsqueda con xito. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho. El valor de retorno de una funcin de bsqueda en un ABB puede ser un puntero al nodo encontrado, o NULL, si no se ha encontrado. Insertar un elemento Para insertar un elemento nos basamos en el algoritmo de bsqueda. Si el elemento est en el rbol no lo insertaremos. Si no lo est, lo insertaremos a continuacin del ltimo nodo visitado. Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raz actual. El valor inicial para ese puntero es NULL.
Padre = NULL nodo = Raiz Bucle: mientras
el elemento.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
o
148
Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo: Padre=nodo, nodo=nodo->izquierdo. o Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho: Padre=nodo, nodo=nodo->derecho. Si nodo no es NULL, el elemento est en el rbol, por lo tanto salimos. Si Padre es NULL, el rbol estaba vaco, por lo tanto, el nuevo rbol slo contendr el nuevo elemento, que ser la raz del rbol. Si el elemento es menor que el Padre, entonces insertamos el nuevo elemento como un nuevo rbol izquierdo de Padre. Si el elemento es mayor que el Padre, entonces insertamos el nuevo elemento como un nuevo rbol derecho de Padre. Este modo de actuar asegura que el rbol sigue siendo ABB. Borrar un elemento Para borrar un elemento tambin nos basamos en el algoritmo de bsqueda. Si el elemento no est en el rbol no lo podremos borrar. Si est, hay dos casos posibles: 1. Se trata de un nodo hoja: en ese caso lo borraremos directamente. 2. Se trata de un nodo rama: en ese caso no podemos eliminarlo, puesto que perderamos todos los elementos del rbol de que el nodo actual es padre. En su lugar buscamos el nodo ms a la izquierda del subrbol derecho, o el ms a la derecha del subrbol izquierdo e intercambiamos sus valores. A continuacin eliminamos el nodo hoja. Necesitamos un puntero auxiliar para conservar una referencia al padre del nodo raz actual. El valor inicial para ese puntero es NULL.
Padre = NULL Si el rbol est
vaco: el elemento no est en el rbol, por lo tanto salimos sin eliminar ningn elemento. (1) Si el valor del nodo raz es igual que el del elemento que buscamos, estamos ante uno de los siguientes casos: o El nodo raz es un nodo hoja: Si 'Padre' es NULL, el nodo raz es el nico del rbol, por lo tanto el puntero al rbol debe ser NULL. Si raz es la rama derecha de 'Padre', hacemos que esa rama apunte a NULL. Si raz es la rama izquierda de 'Padre', hacemos que esa rama apunte a NULL. Eliminamos el nodo, y salimos. o El nodo no es un nodo hoja: Buscamos el 'nodo' ms a la izquierda del rbol derecho de raz o el ms a la derecha del rbol izquierdo. Hay que tener en cuenta que puede que slo exista uno de
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
149
esos rboles. Al mismo tiempo, actualizamos 'Padre' para que apunte al padre de 'nodo'. Intercambiamos los elementos de los nodos raz y 'nodo'. Borramos el nodo 'nodo'. Esto significa volver a (1), ya que puede suceder que 'nodo' no sea un nodo hoja. (Ver ejemplo 3) Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho. Borrar un nodo hoja En el rbol de ejemplo, borrar el nodo 3. 1. Localizamos el nodo a borrar, al tiempo que mantenemos un puntero a 'Padre'. 2. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL. 3. Borramos el 'nodo'.
Borrar un nodo rama con intercambio de un nodo hoja. En el rbol de ejemplo, borrar el nodo 4. 1. Localizamos el nodo a borrar ('raz'). 2. Buscamos el nodo ms a la derecha del rbol izquierdo de 'raz', en este caso el 3, al tiempo que mantenemos un puntero a 'Padre' a 'nodo'. 3. Intercambiamos los elementos 3 y 4. 4. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL. 5. Borramos el 'nodo'.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
150
Borrar un nodo rama con intercambio de un nodo rama. Para este ejemplo usaremos otro rbol. En ste borraremos el elemento 6.
1. Localizamos el nodo a borrar ('raz'). 2. Buscamos 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 optamos por la rama izquierda, estaremos en un caso anlogo. Al mismo tiempo que mantenemos un puntero a 'Padre' a 'nodo'. 3. Intercambiamos los elementos 6 y 12. 4. Ahora tenemos que repetir el bucle para el nodo 6 de nuevo, ya que no podemos eliminarlo.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
151
5. Localizamos de nuevo el nodo a borrar ('raz'). 6. Buscamos el nodo ms a la izquierda del rbol derecho de 'raz', en este caso el 16, al mismo tiempo que mantenemos un puntero a 'Padre' a 'nodo'. 7. Intercambiamos los elementos 6 y 16. 8. Hacemos que el puntero de 'Padre' que apuntaba a 'nodo', ahora apunte a NULL. 9. Borramos el 'nodo'.
Este modo de actuar asegura que el rbol sigue siendo ABB. Movimientos a travs del rbol Hay varios parmetros que podemos calcular o medir dentro de un rbol. Algunos de ellos nos darn idea de lo eficientemente que est organizado o el modo en que funciona. Comprobar si un rbol est vaco. Un rbol est vaco si su raz es NULL.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
152
Calcular el nmero de nodos. Tenemos dos opciones para hacer esto, una es llevar siempre la cuenta de nodos en el rbol al mismo tiempo que se aaden o eliminan elementos. La otra es, sencillamente, contarlos. Para contar los nodos podemos recurrir a cualquiera de los tres modos de recorrer el rbol: inorden, preorden o postorden, como accin sencillamente incrementamos el contador. Comprobar si el nodo es hoja. Esto es muy sencillo, basta con comprobar si tanto el rbol izquierdo como el derecho estn vacos. Si ambos lo estn, se trata de un nodo hoja. Calcular la altura de un nodo. No hay un modo directo de hacer esto, ya que no nos es posible recorrer el rbol en la direccin de la raz. De modo que tendremos que recurrir a otra tcnica para calcular la altura. Lo que haremos es buscar el elemento del nodo de que queremos averiguar la altura. Cada vez que avancemos un nodo incrementamos la variable que contendr la altura del nodo.
Empezamos
con el nodo raz apuntando a Raiz, y la 'Altura' igual a cero. Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la bsqueda y el valor de la altura es 'Altura'. Incrementamos 'Altura'. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho. Calcular la altura de un rbol. La altura del rbol es la altura del nodo de mayor altura. Para buscar este valor tendremos que recorrer todo el rbol, de nuevo es indiferente el tipo de recorrido que hagamos, cada vez que cambiemos de nivel incrementamos la variable que contiene la altura del nodo actual, cuando lleguemos a un nodo hoja compararemos su altura con la variable que contiene la altura del rbol si es mayor, actualizamos la altura del rbol.
Iniciamos
un recorrido del rbol en postorden, con la variable de altura igual a cero. Cada vez que empecemos a recorrer una nueva rama, incrementamos la altura para ese nodo. Despus de procesar las dos ramas, verificamos si la altura del nodo es mayor que la variable que almacena la altura actual del rbol, si es as, actualizamos esa variable.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
153
En el siguiente ejemplo de ABB vamos a ver cmo implementar en C algunas de las funciones que hemos explicado para rboles ABB, al final se incluye un ejemplo completo para rboles de enteros. Declaracin de tipos: Como estamos trabajando con un rbol binario, slo necesitamos una estructura para referirnos tanto a cualquiera de los nodos como al rbol completo. Recuerda que cualquier nodo puede ser considerado como la raz de un rbol. typedef struct _nodo { int dato; struct _nodo *derecho; struct _nodo *izquierdo; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Arbol; Insertar un elemento en un rbol ABB: Disearemos una funcin que se ajuste al algoritmo que describimos en el punto 7.4: 1. Padre = NULL 2. nodo = Raiz 3. Bucle: mientras actual no sea un rbol vaco o hasta que se encuentre el elemento. a. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo: Padre=nodo, nodo=nodo->izquierdo. b. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho: Padre=nodo, nodo=nodo->derecho. 4. Si nodo no es NULL, el elemento est en el rbol, por lo tanto salimos. 5. Si Padre es NULL, el rbol estaba vaco, por lo tanto, el nuevo rbol slo contendr el nuevo elemento, que ser la raz del rbol. 6. Si el elemento es menor que el Padre, entonces insertamos el nuevo elemento como un nuevo rbol izquierdo de Padre. 7. Si el elemento es mayor que el Padre, entonces insertamos el nuevo elemento como un nuevo rbol derecho de Padre. void Insertar(Arbol *a, int dat) { pNodo padre = NULL; /* (1) */ pNodo actual = *a; /* (2) */ while(!Vacio(actual) && dat != actual->dato) { /* (3) */ padre = actual;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas if(dat < actual->dato) actual = actual->izquierdo; /* (3-a) */ else if(dat > actual->dato) actual = actual->derecho; /* (3-b) */
154
if(!Vacio(actual)) return; /* (4) */ if(Vacio(padre)) { /* (5) */ *a = (Arbol)malloc(sizeof(tipoNodo)); (*a)->dato = dat; (*a)->izquierdo = (*a)->derecho = NULL; } else if(dat < padre->dato) { /* (6) */ actual = (Arbol)malloc(sizeof(tipoNodo)); padre->izquierdo = actual; actual->dato = dat; actual->izquierdo = actual->derecho = NULL; } else if(dat > padre->dato) { /* (7) */ actual = (Arbol)malloc(sizeof(tipoNodo)); padre->derecho = actual; actual->dato = dat; actual->izquierdo = actual->derecho = NULL; }
Eliminar un elemento de un rbol ABB: Disearemos una funcin que se ajuste al algoritmo que describimos en el punto 7.5: 1. Padre = NULL 2. Si el rbol est vaco: el elemento no est en el rbol, por lo tanto salimos sin eliminar ningn elemento. 3. Si el valor del nodo raz es igual que el del elemento que buscamos, estamos ante uno de los siguientes casos: a. El nodo raz es un nodo hoja: i. Si 'Padre' es NULL, el nodo raz es el nico del rbol, por lo tanto el puntero al rbol debe ser NULL. ii. Si raz es la rama derecha de 'Padre', hacemos que esa rama apunte a NULL. iii. Si raz es la rama izquierda de 'Padre', hacemos que esa rama apunte a NULL. iv. Eliminamos el nodo, y salimos. b. El nodo no es un nodo hoja: i. Buscamos el 'nodo' ms a la izquierda del rbol derecho de raz o el ms a la derecha del rbol izquierdo. Hay que tener en cuenta que puede que slo exista uno de esos rboles. Al mismo tiempo, actualizamos 'Padre' para que apunte al padre de 'nodo'. ii. Intercambiamos los elementos de los nodos raz y 'nodo'.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
155
iii. Borramos el nodo 'nodo'. Esto significa volver a (3), ya que puede suceder que 'nodo' no sea un nodo hoja. 4. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo. 5. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho. void Borrar(Arbol *a, int dat) { pNodo padre = NULL; /* (1) */ pNodo actual; pNodo nodo; int aux; actual = *a; while(!Vacio(actual)) { /* Bsqueda (2) else implcito */ if(dat == actual->dato) { /* (3) */ if(EsHoja(actual)) { /* (3-a) */ if(padre)/* (3-a-i caso else implcito) */ if(padre->derecho == actual) padre->derecho = NULL; /* (3-a-ii) */ else if(padre->izquierdo == actual) padre->izquierdo = NULL; /* (3a-iii) */ free(actual); /* (3-a-iv) */ actual = NULL; return; } else { /* (3-b) */ /* Buscar nodo */ padre = actual; /* (3-b-i) */ if(actual->derecho) { nodo = actual->derecho; while(nodo->izquierdo) { padre = nodo; nodo = nodo->izquierdo; } } else { nodo = actual->izquierdo; while(nodo->derecho) { padre = nodo; nodo = nodo->derecho; } } /* Intercambio */ aux = actual->dato; /* (3-b-ii) */ actual->dato = nodo->dato; nodo->dato = aux; actual = nodo; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } else { padre = actual; if(dat > actual->dato) actual = actual->derecho; /* (4) */ else if(dat < actual->dato) actual = actual->izquierdo; /* (5) */ }
156
Buscar un elemento en un rbol ABB: Disearemos una funcin que se ajuste al algoritmo que describimos en el punto 7.3: 1. Si el rbol est vaco, terminamos la bsqueda: el elemento no est en el rbol. 2. Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la bsqueda con xito. 3. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo. 4. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho. int Buscar(Arbol a, int dat) { pNodo actual = a; while(!Vacio(actual)) { if(dat == actual->dato) return TRUE; /* dato encontrado (2) */ else if(dat < actual->dato) actual = actual->izquierdo; /* (3) */ else if(dat > actual->dato) actual = actual->derecho; /* (4) */ } return FALSE; /* No est en rbol (1) */
Comprobar si el rbol est vaco: Esta funcin es fcil de implementar: int Vacio(Arbol r) { return r==NULL; } Comprobar si un nodo es hoja: Esta funcin tambin es sencilla de implementar: int EsHoja(pNodo r) { return !r->derecho && !r->izquierdo; }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
157
Contar nmero de nodos: En el punto 7.7 comentbamos que para contar los nodos podemos recurrir a cualquiera de los tres modos de recorrer el rbol: inorden, preorden o postorden y como accin incrementamos el contador de nodos. Para implementar este algoritmo recurrimos a dos funciones: int NumeroNodos(Arbol a, int *contador) { *contador = 0; auxContador(a, contador); return *contador;
void auxContador(Arbol nodo, int *c) { (*c)++; /* Accin: incrementar nmero de nodos. (Preorden) */ if(nodo->izquierdo) auxContador(nodo->izquierdo, c); /* Rama izquierda */ if(nodo->derecho) auxContador(nodo->derecho, c); /* Rama derecha */ } Calcular la altura de un rbol: Es un problema parecido al anterior, pero ahora tenemos que contar la altura, no en nmero de nodos. Cada vez que lleguemos a un nodo hoja, verificamos si la altura del nodo es la mxima, y si lo es, actualizamos la altura del rbol a ese valor: 1. Iniciamos un recorrido del rbol en postorden, con la variable de altura igual a cero. 2. Cada vez que empecemos a recorrer una nueva rama, incrementamos la altura para ese nodo. 3. Despus de procesar las dos ramas, verificamos si la altura del nodo es mayor que la variable que almacena la altura actual del rbol, si es as, actualizamos esa variable. int AlturaArbol(Arbol a, int *altura) { *altura = 0; /* (1) */ auxAltura(a, 0, altura); return *altura;
void auxAltura(pNodo nodo, int a, int *altura) { /* (2) Cada vez que llamamos a auxAltura pasamos como parmetro a+1 */ if(nodo->izquierdo) auxAltura(nodo->izquierdo, a+1, altura); /* Rama izquierda */
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
158
if(nodo->derecho) auxAltura(nodo->derecho, a+1, altura); /* Rama derecha */ if(EsHoja(nodo) && a > *altura) *altura = a; /* Proceso (Postorden) (3) */ } Calcular la altura del nodo que contienen un dato concreto: Lo que haremos ser buscar el elemento del nodo del que queremos averiguar la altura. Cada vez que avancemos un nodo incrementamos la variable que contendr la altura del nodo. 1. Empezamos con el nodo raz apuntando a Raiz, y la 'Altura' igual a cero. 2. Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la bsqueda y el valor de la altura es 'Altura'. 3. Incrementamos 'Altura'. 4. Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo. 5. Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho. int Altura(Arbol a, int dat) { int altura = 0; pNodo actual = a; /* (1) */ while(!Vacio(actual)) { if(dat == actual->dato) return altura; /* dato encontrado. (2) */ else { altura++; /* (3) */ if(dat < actual->dato) actual = actual->izquierdo; /* (4) */ else if(dat > actual->dato) actual = actual->derecho; /* (5) */ } } return -1; /* No est en rbol */
Aplicar una funcin a cada elemento del rbol, segn los tres posibles recorridos: Todos los recorridos se aplican de forma recursiva. En este ejemplo crearemos tres funciones, una por cada tipo de recorrido, que aplicarn una funcin al elemento de cada nodo. La funcin a aplicar puede ser cualquiera que admita como parmetro un puntero a un entero, y que no tenga valor de retorno. InOrden En Inorden, primero procesamos el subrbol izquierdo, despus el nodo actual, y finalmente el subrbol derecho: void InOrden(Arbol a, void (*func)(int*))
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas { if(a->izquierdo) InOrden(a->izquierdo, func); /* Subrbol izquierdo */ func(&(a->dato)); /* Aplicar la funcin al dato del nodo actual */ if(a->derecho) InOrden(a->derecho, func); /* Subrbol derecho */
159
PreOrden En Preorden, primero procesamos el nodo actual, despus el subrbol izquierdo, y finalmente el subrbol derecho: void PreOrden(Arbol a, void (*func)(int*)) { func(&(a->dato)); /* Aplicar la funcin al dato del nodo actual */ if(a->izquierdo) PreOrden(a->izquierdo, func); /* Subrbol izquierdo */ if(a->derecho) PreOrden(a->derecho, func); /* Subrbol derecho */ } PostOrden En Postorden, primero procesamos el subrbol izquierdo, despus el subrbol derecho, y finalmente el nodo actual: void PostOrden(Arbol a, void (*func)(int*)) { if(a->izquierdo) PostOrden(a->izquierdo, func); /* Subrbol izquierdo */ if(a->derecho) PostOrden(a->derecho, func); /* Subrbol derecho */ func(&(a->dato)); /* Aplicar la funcin al dato del nodo actual */ } El siguiente programa es una muy buena representacin de un rbol binario implementado con punteros. Listado 8.3 #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <ctype.h> struct arbol { int dato; struct arbol *izq; struct arbol *der; }*raiz; enum{ FALSO=0, VERDADERO }; /*PROTOTIPOS*/ void inicializar( void );
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas int vacio( struct arbol *hoja ); int eshoja( struct arbol *hoja ); struct arbol *insertar( struct arbol *raiz, struct arbol *hoja, int num ); int busqueda( struct arbol *hoja, int num ); int alturax( struct arbol *hoja, int num ); int alturafull( struct arbol *hoja, int *altura ); void auxaltura( struct arbol *hoja, int *altura, int cont ); int nodos( struct arbol *hoja ); void auxnodos( struct arbol *hoja, int *cont ); struct arbol *borrarx( struct arbol *hoja, int num ); struct arbol *podar( struct arbol *hoja ); void preorden( struct arbol *hoja ); void inorden( struct arbol *hoja ); void posorden( struct arbol *hoja ); void menu_recorridos( void ); void menu_busquedas( void ); void menu_alturas( void ); void menu_nodos( void ); void menu_podar( void );
160
void inicializar( void ) { raiz= NULL; } int vacio( struct arbol *hoja ) { if( !hoja ) return VERDADERO; return FALSO; } int eshoja( struct arbol *hoja ) { if( hoja->izq==NULL && hoja->der==NULL ) return VERDADERO; return FALSO; } struct arbol *insertar( struct arbol *raiz, struct arbol *hoja, int num ) { if( !hoja ) { hoja= (struct arbol *) malloc( sizeof (struct arbol) ); hoja->dato= num; hoja->izq= NULL; hoja->der= NULL; if( !raiz ) return hoja;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas else if( num<raiz->dato ) raiz->izq= hoja; else raiz->der= hoja; return hoja; } else if( num<hoja->dato ) insertar( hoja, hoja->izq, num ); else insertar( hoja, hoja->der, num ); return raiz; } int busqueda( struct arbol *hoja, int num ) { while( hoja ) { if( num==hoja->dato ) return VERDADERO; else { if( num<hoja->dato ) hoja= hoja->izq; else hoja= hoja->der; } } return FALSO; } int alturax( struct arbol *hoja, int num ) { int altura=1; while( hoja ) { if( num==hoja->dato ) return altura; else { altura++; if( num<hoja->dato ) hoja= hoja->izq; else hoja= hoja->der; } } return FALSO; } int alturafull( struct arbol *hoja, int *altura ) { auxaltura( hoja, altura, 1 ); return *altura; } void auxaltura( struct arbol *hoja, int *altura, int cont ) {
161
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas if( !hoja ) return; auxaltura( hoja->izq, altura, cont+1 ); auxaltura( hoja->der, altura, cont+1 ); if( (eshoja( hoja ) && cont)>*altura ) *altura= cont; } int nodos( struct arbol *hoja ) { int nodos=0; auxnodos( hoja, &nodos ); return nodos; } void auxnodos( struct arbol *hoja, int *cont ) { if( !hoja ) return; (*cont)++; auxnodos( hoja->izq, cont ); auxnodos( hoja->der, cont ); } struct arbol *borrarx( struct arbol *hoja, int num ) { if( hoja->dato==num ) { struct arbol *p, *p2; if( vacio( hoja ) ) { free( hoja ); hoja= NULL; return hoja; } else if( hoja->izq==NULL ) { p= hoja->der; free( hoja ); return p; } else if( hoja->der==NULL ) { p= hoja->izq; free( hoja ); return p; } else {
162
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas p= hoja->der; p2= hoja->der; while( p->izq ) p= p->izq; p->izq= hoja->izq; free( hoja ); return p2; }
163
} else if( num<hoja->dato ) hoja->izq= borrarx( hoja->izq, num ); else hoja->der= borrarx( hoja->der, num ); return hoja; } struct arbol *podar( struct arbol *hoja ) { if( !hoja ) return hoja; podar( hoja->izq ); podar( hoja->der ); free( hoja ); hoja= NULL; return hoja; } /*Recorridos*/ void preorden( struct arbol *hoja ) { if( !hoja ) return; printf( "%i ", hoja->dato ); preorden( hoja->izq ); preorden( hoja->der ); } void inorden( struct arbol *hoja ) { if( !hoja ) return; inorden( hoja->izq ); printf( "%i ", hoja->dato ); inorden( hoja->der ); } void posorden( struct arbol *hoja ) { if( !hoja ) return;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas posorden( hoja->izq ); posorden( hoja->der ); printf( "%i ", hoja->dato ); } /*Menus del Arbol*/ void menu_recorridos( void ) { char _op='S'; while( _op!='4' ) { clrscr(); printf( "1. PreOrden." ); printf( "\n2. InOrden." ); printf( "\n3. PosOrden." ); printf( "\n4. Salir." ); printf( "\n\n:: " ); _op= getch(); switch( _op ) { case '1': preorden( raiz ); getch(); break; case '2': inorden( raiz ); getch(); break; case '3': posorden( raiz ); getch(); break; } } return; } void menu_busquedas( void ) { int val; printf( "\n\nNumero: " ); scanf( "%i", &val ); if( busqueda( raiz, val ) ) printf( "\n\nEncontrado.." ); else printf( "\n\nError, No se encuentra." ); getch();
164
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } void menu_alturas( void ) { char _op='A'; int val, altura; while( _op!='3' ) { clrscr(); printf( "1. Altura de Un Nodo \( Profundidad \). " ); printf( "\n2. Altura de Todo el Arbol." ); printf( "\n3. Salir." ); printf( "\n\n:: " ); _op= getch(); switch( _op ) { case '1': printf( "\n\nNumero: " ); scanf( "%i", &val ); altura= alturax( raiz, val ); if( !altura ) printf( "\n\nImposible, numero inexistente." ); else printf( "\n\nLa Altura es: %i", altura ); getch(); break; case '2': altura= 0; printf( "\n\nLa Altura del Arbol es: %i", alturafull( raiz, &altura ) ); getch(); break; } } return; } void menu_nodos( void ) { printf( "\n\nEl Numero de Nodos es: %i", nodos( raiz ) ); getch(); } void menu_podar( void ) { char _op='A'; int val; while( _op!='3' ) {
165
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas clrscr(); printf( "1. Podar Un Nodos del Arbol." ); printf( "\n2. Podar Todo el Arbol." ); printf( "\n3. Salir." ); _op= getch(); switch( _op ) { case '1': printf( "\n\nNumero: " ); scanf( "%i", &val ); raiz= borrarx( raiz, val ); printf( "\n\n.... Borrado ...." ); break; case '2': raiz= podar( raiz ); printf( "\n\nArbol Borrado por Completo." ); getch(); break; } } return; } int main() { char _op='A'; int val; inicializar(); while( _op!='S' ) { clrscr(); printf( "Insertar." ); printf( "\nRecorridos." ); printf( "\nBusquedas." ); printf( "\nAlturas." ); printf( "\nNodos." ); printf( "\nPodar." ); printf( "\nSalir." ); printf( "\n\n:: " ); _op= toupper( getch() ); switch( _op ) { case 'I': printf( "\n\nNumero: " ); scanf( "%i", &val ); if( busqueda( raiz, val ) ) {
166
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas printf( "\n\nEste numero ya ha sido insertado." ); getch(); break; } raiz= insertar( raiz, raiz, val ); break; case 'R': if( vacio( raiz ) ) { printf( "\n\nEl Arbol Aun esta Vacio." ); getch(); break; } menu_recorridos(); break; case 'B': if( vacio( raiz ) ) { printf( "\n\nEl Arbol Aun esta Vacio." ); getch(); break; } menu_busquedas(); break; case 'A': if( vacio( raiz ) ) { printf( "\n\nEl Arbol Aun esta Vacio." ); getch(); break; } menu_alturas(); break; case 'N': if( vacio( raiz ) ) { printf( "\n\nEl Arbol Aun esta Vacio." ); getch(); break; } menu_nodos(); break; case 'P': if( vacio( raiz ) ) { printf( "\n\nEl Arbol Aun esta Vacio." ); getch(); break; }
167
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas menu_podar(); break;
168
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
169
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
170
Ejercicio 9 Suponiendo que el tipo de los elementos sobre el que se construyen los multiconjuntos admite una relacin de orden total, implementar la especificacinde los multiconjuntos en trminos de rboles de bsqueda en cuyos nodos se guardan pares de elemento y multiplicidad de dicho elemento en el multiconjunto. Ejercicio 10. Implemente un rbol binario por medio del entorno grfico de C/C++, de tal manera que se pueda gestionar la teora de un rbol binario (Creacin y visualizacin del rbol, al igual que los tres recorridos Inorden, Preorden, Posorden, altura del rbol, el grado)
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
171
Captulo 9. Grafos
9.1 Conceptos bsicos 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). La implementacin de los grafos se recomienda que se realice por medio del entorno grfico que nos presenta el compilador de C/C++, de esta manera nos vamos acercando a la programacin orientada a objetos. En trminos simples, un grafo es un objeto matemtico conformado por una coleccin de vrtices (o nodos) y aristas que modela fielmente este tipo de situaciones. Los vrtices son objetos simples que pueden tener un nombre y otras propiedades (informacin) y una arista es la conexin entre dos vrtices.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 9.2 Grafo Dirigido (Red) Sea donde:
172
, entonces el par
La arista se dice que es incidente con los vrtices y . El vrtice (origen o fuente) es adyacente al vrtice (destino o final). es un vrtice aislado (no es incidente con ninguna arista). La arista es un lazo.
Nunca se debe olvidar que la definicin de un grafo es independiente de su representacin. 9.3 Grafo No Dirigido Cuando no importa la direccin de una arista, el grafo se denomina no dirigido lo muestra la siguiente figura.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
173
En general el trmino grafo hace referencia a un grafo no dirigido, a menos que se especifique lo contrario. Camino Sea en de a un grafo no dirigido, para se dice que hay un camino
como:
Cuando el camino se denomima ciclo. El nmero de aristas de un camino (ciclo) se denomina longitud de camino (ciclo). Un camino es simple si slo pasa una sola vez por cada nodo. Todos estos conceptos se ilustran en la Figura
Un camino simple de a a f = {a,b}, {b,c}, {c,f} Un camino simple de a a f = {a,b}, {b,c}, {c,e}, {e,d}, {d,c}, {c,f} Un ciclo simple: {a,b}, {b,d}, {d,a}
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas Un ciclo no simple: {a,b}, {b,d}, {d,c}, {c,e}, {e,d}, {d,a}
174
9.4 Grafo Conexo Sea un grafo no dirigido, entonces G es conexo si existe un camino entre cada par de vrtices de G. Por otra parte, sea un grafo dirigido, y sea su grafo no dirigido asociado, es conexo, se considera conexo. entonces si La Figura muestra un grafo no conexo sin embargo est conformado por dos partes conexas denominadas componentes conexas.
Ntese que un grafo conexo tiene una sola componente conexa. Teorema 2.1 Si G=(V,A) es un grafo conexo entonces existe un camino simple entre dos vrtices cualesquiera de G. Grafos Completos Si es el nmero de aristas de un grafo no dirigido y entonces: es el nmero de vrtices
Los grafos con todas las aristas posible de denominan grafos completos. Se denominan grafos densos aquellos que tienen muchas aristas ( ) y grafos dispersos aquellos que tienen pocas aristas ( ).
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 9.5 Grafos Ponderados Se le asignan pesos a las aristas para representar la distancia o el costo asociado a pasar por dicha arista. 9.6 Matriz de Adyacencias Una forma de representar un grafo es a travs de una matriz booleanos. Si el elemento
175
de valores hasta
Ntese que:
cada arista se representa con dos bits. para grafos no dirigidos la matriz es simtrica, osea que puede utilizarse slo una de las triangulares, pero los algoritmos se simplifican si se utiliza completa. normalmente se supone que existe una arista desde cada vrtice consigo mismo ( ), aunque esto no es conveniente en algunos casos.
La representacin por matriz de adyacencia slo es satisfactoria si los grafos a procesar son densos. La matriz requiere bits de almacenamiento y pasos de inicializacin. Estructura de Adyacencias Si un grafo es disperso, la simple inicializacin de la matriz de adyacencias podra ser un factor determinante en el tiempo de ejecucin de los algoritmos. Para representar grafos no densos es mejor utilizar el siguiente esquema: todos los vrtices conectados con uno dado se incluyen en su lista de adyacencias.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
176
Es la mejor representacin para grafos dispersos pues el espacio necesario es . Ntese que:
de nuevo cada arista se representa dos veces. Esto es importante pues en caso contrario no podra contestarse eficientemente una pregunta tan simple como cules nodos estn conectados directamente al nodo X? el orden en que aparecen los vrtices en la lista de adyacencias est determinado por la entrada de datos y el mtodo de insercin utlizado. En consecuencia, un mismo grafo puede representarse de muchas formas empleando estructuras de adyacencias. Es claro que el orden de aparicin de los vrtices influye en el orden en que los algoritmos procesan los vrtices. un algoritmo debe dar una respuesta correcta sin importar el orden de los vrtices en las listas de adyacencias. Si existe ms de una respuesta correcta, diferentes ordenamientos de los vrtices pueden arrojar resultados diferentes
Esta representacin hace ms complejas algunas operaciones (e.g. eliminar un nodo). 9.7 Representacin de grafos Una caracterstica especial en los grafos es que podemos representarlos utilizando dos estructuras de datos distintas. En los algoritmos que se aplican sobre ellos veremos que adoptarn tiempos distintos dependiendo de la forma de representacin elegida. En particular, los tiempos de ejecucin variarn en funcin del nmero de vrtices y el de aristas, por lo que la utilizacin de una representacin u otra depender en gran medida de si el grafo es denso o disperso. Para nombrar los nodos utilizaremos letras maysculas, aunque en el cdigo deberemos hacer corresponder cada nodo con un entero entre 1 y V (nmero de vrtices) de cara a la manipulacin de los mismos.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
177
9.7.1 Representacin por matriz de adyacencia Es la forma ms comn de representacin y la ms directa. Consiste en una tabla de tamao V x V, en que la que a[i][j] tendr como valor 1 si existe una arista del nodo i al nodo j. En caso contrario, el valor ser 0. 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 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++) { scanf("%c %c %d\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 densos. 9.7.2 Representacin por lista de adyacencia Otra forma de representar un grafo es por medio de listas que definen las aristas que conectan los nodos. Lo que se hace es definir una lista enlazada para cada nodo, que contendr los nodos a los cuales es posible acceder. Es decir, un nodo A tendr una lista enlazada asociada en la que aparecer un elemento con una referencia al nodo B si A y B tienen una arista que los une. Obviamente, si el grafo es no dirigido, en la lista enlazada de B aparecer la correspondiente referencia al nodo A.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
178
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 se ha utilizado un nodo z ficticio en la cola (ver listas, apartado cabeceras y centinelas). struct nodo { int v; 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++) { scanf("%c %c %d\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. Una consecuencia de esto es que si un problema tiene varias soluciones la primera que se encuentre depender de la entrada dada. Podra presentarse el
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
179
caso de tener varias soluciones y tener que mostrarlas siguiendo un determinado orden. Ante una situacin as podra ser muy conveniente modificar la forma de meter los nodos en la lista (por ejemplo, hacerlo al final y no al principio, o incluso insertarlo en una posicin adecuada), de manera que el algoritmo mismo diera las soluciones ya ordenadas. 9.8 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) por una cola nos proporciona el segundo mtodo de bsqueda o recorrido, la bsqueda en amplitud o anchura.
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), tenemos 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 (el A). Esto es debido a que primero se explora la rama del nodo C, que tambin conduce al nodo D. En estos ejemplos 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. 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
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
180
9.8.1 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. 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,
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
181
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; val[3]=2; val[4]=4; 9.8.2 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; } } } } 9.9 Algoritmos sobre Grafos Este curso abordar algoritmos clsicos para resolver dos problemas tambin clasicos: 1. Encontrar la forma de conectar todos los puntos de un grafo ponderado al menor costo (rbol de expansin mnimo).
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
182
2. Encontrar el camino de menor coste entre dos puntos dados (camino ms corto). Camino ms Corto Sea un grafo dirigido y ponderado, entonces se toma un nodo como origen. El problema consiste en determinar la longitud del camino mnimo que va desde el nodo origen hasta cada uno de los dems nodos. Este problema se puede resolver mediante un algoritmo voraz conocido como Algoritmo de Dijkstra. El algoritmo utiliza: i) el conjunto que contiene aquellos nodos que han sido seleccionados (la distancia mnima desde el origen que contiene ya es conocida para todos los nodos de ), y ii) el conjunto todos los dems nodos cuya distancia mnima desde el origen an no es conocida, y que son candidatos a ser seleccionados en una etapa posterior. Entonces .
Inicialmente contiene nicamente el nodo origen y al final contendr todos los nodos de . En cada paso se selecciona aqul nodo de cuya distancia al origen sea mnima y lo aadimos a . Diremos que un camino desde el origen hasta algn otro nodo es especial si todos los nodos intermedios a lo largo del camino pertenecen a . En cada fase del algoritmo hay un arreglo (o vector) d que contiene la longitud del camino especial ms corta que va hasta cada nodo del grafo. Se puede demostrar que al momento de aadir un nuevo nodo v a , el camino especial ms corto hasta v es tambin el ms corto de los caminos posibles hasta v.Cuando se detiene el algoritmo todos los nodos del grafo pertenecen a y por ende todos los caminos desde el nodo origen hasta algn nodo son especiales. Por consiguiente, los valores que hay en d dan la solucin al problema de caminos mnimos.
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
183
BIBLIOGRAFA
INSUASTY R, Luis Delfn, Guia A,B,C,D de aprendizaje autonomo. Bogot Colombia, UNAD- Cafan. MAURREN, Priestley . Tecnicas y estrategias del pensamiento critico. Mexico D.F. 1996 (reimp .2000). Trillas. ARCEO B, Frida y Otro. Estrategias Decentes Para un Aprendizaje Significativo. Mexico D,F 1999. McGRAW-HILL. KENNETH C, louden . Lenguajes de programacin (segunda edicin). Mexico D.F 2004. Thomson. AGUILAR, Luis. Fundamentos de programacin, algoritmos y estructura de datos (segunda edicin). Espaa. McGRAW-HILL. AGUILAR, Luis. Fundamentos de programacin, algoritmos, estructura de datos y Objetos (tercera edicin). Espaa. 2003. McGRAW-HILL. DEYTEL Y DEYTEL. Como programa C++(segunda Edicin). Mexico D.F. 1999. Prentice Hall. McGRAW-HILL. FARREL, Joyce, introduccin a la programacin lgica y diseo. Mexico D.F 2000. Thomson. BROOKSHEAR, J. Glenn , Introduccin a las ciencias de la Computacin (Cuarta Edicn). Edicin Espaola 1995. Addison-Wesley Iberoamericana. Sitios WEB Este curso en su mayoria es tomado del curso de c con clase, publicado en la web, que cumple con las espetactivas propias de un temario de tal profundida http://c.conclase.net/edd/index.php?cap=006 www.Cconclase\Untitled\index.php-cap=004.htm www.Cconclase\Untitled\index.php-cap=003.htm http://www.ica.luz.ve/juancol/eda/grafos/grafos.html http://kataix.umag.cl/~mmarin/topinf/cs23/c++/Indice.htm http://www.geocities.com/david_ees/Algoritmia/curso.htm http://members.tripod.com/~MoisesRBB/c.html http://www.ilustrados.com/publicaciones/EpZVVEZpyEdFpAKxjH.php http://www.programacionfacil.com/cbueno/indice.htm http://www.ilustrados.com/buscar.php http://www.inf.utfsm.cl/~mcloud/iwi-131/diapositivas.html) http://www.ucsm.edu.pe/rabarcaf/vonuep00.htm http://www.funlam.edu.co/bired/index.asp-offset=0.htm
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
184
http://www.itq.edu.mx/vidatec/espacio/aisc/ARTICULOS/leng/LENGUAJESDEP ROGRAMACI%D3N.htm www.microsoft.com (Productos de programacin) www.borland.com (Productos de programacin) http://computacion.cs.cinvestav.mx/~acaceres/courses/estDatosCPP/ node41.html. http://www.algoritmia.net/articles.php?id=18 www.Cconclase\Untitled\index.php-cap=003.htm http://members.tripod.com/~MoisesRBB/c.html
http://www.itlp.edu.mx/publica/tutors.htm
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
185
ANEXOS ANEXO 1 Implementacin de Listas enlazadas // PROGRAMA DE MANEJO DE LISTAS ENLAZADAS // DESARROLLADO POR: // ROGER GOMEZ CHAMORRO // PABEL GRANADOS ZEVALLOS // ROQUE GUTIERREZ GONZALES // ERIC VASQUEZ MEZA // LINDA NAVARRO SOLSOL // #include<stdio.h> #include<string.h> #include<stdlib.h> #include<string.h> #include<conio.h> #include<dos.h> #include<graphics.h> #include<iostream.h> #include <stdlib.h> #include<ctype.h> #define NULL 0 int lim; struct lista{ char codigo[5]; char alumno[50]; char num_cur[10]; char num_cred[10]; struct lista *sig; }; /* campos que seran considerados en cada registro */ typedef struct lista nodo; int i=1,j=0; int r=6; char con[6]="WINMAR",clave[6],usuario[10]; /*************************************************************/ main() { nodo *prin; int eleccion; void sonido(); void ventana();
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas void presen(); void ingreso(); int menu(void); /* funcion menu de opciones */ void create (nodo *pt); /* funcion que permite crear una lista enlazada */ void ordenat(nodo *pt); nodo *insertar (nodo *pt); /* funcion crea e inserta un nuevo registro*/ nodo *borrar (nodo *pt); /* funcion que borra un registro */ void mostrar(nodo *pt); /* funcion que muestra los registros existentes */ clrscr(); ingreso(); presen(); clrscr(); do{ clrscr(); eleccion = menu(); switch (eleccion) { case 1: sonido(); prin=(nodo *) malloc(sizeof(nodo)); /*reserva memoria para el registri prin*/ create(prin); printf("\n"); continue; case 2: sonido(); prin=insertar(prin); printf("\n");r=6; mostrar(prin); continue; case 3: sonido(); prin=borrar(prin); printf("\n"); mostrar(prin);r=6; continue; case 4: sonido();clrscr(); gotoxy(3,2);textattr(2); cprintf(" L I S T A D O D E D A T O S"); i=1;r=6; mostrar(prin); gotoxy(3,6+i);textattr(11); cprintf("\n"); getch(); continue; case 5: sonido(); ordenat(prin);//FUncion que ordenara los registros printf("\n"); clrscr(); mostrar(prin); getch(); continue; default:
186
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas if (eleccion>6) {gotoxy(10,18);textattr(RED+BLINK);cprintf("DIgite un numero entre 1-5");} if(eleccion>0&&eleccion<7) {gotoxy(10,18);textattr(3+BLINK);cprintf("Esta saliendo del programa\n");} if (eleccion==NULL) {gotoxy(10,18);textattr(2+BLINK);cprintf("Escoja una opcion\n");} getch(); clrscr(); } }while (eleccion !=6); return 0; } /**********************************************************/ int menu (void) /*opciones a escoger*/ { char aux[4]; int eleccion; do{ textattr(30); gotoxy(28,8); cprintf("Menu Principal\n"); gotoxy(28,9); textattr(14); cprintf("1"); textattr(7); cprintf(" - CREAR\n"); gotoxy(28,10); textattr(14); cprintf("2"); textattr(7); cprintf(" - INSERTAR\n"); gotoxy(28,11); textattr(14); cprintf("3"); textattr(7); cprintf(" - ELIMINAR\n"); gotoxy(28,12); textattr(14); cprintf("4"); textattr(7); cprintf(" - VER LA LISTA\n"); gotoxy(28,13); textattr(14); cprintf("5"); textattr(7); cprintf(" - ORDENAR LISTA"); gotoxy(28,14); textattr(14); cprintf("6");
187
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas textattr(7); cprintf(" - SALIR\n"); gotoxy(28,15); textattr(15); cprintf("Opcion"); textattr(RED+BLINK); cprintf("[ ]\b\b"); cscanf("%c",aux); eleccion=atoi(aux); } while (eleccion<1&&eleccion>5);//cambie or por and return(eleccion); } void create(nodo *registro) { clrscr(); textattr(2); gotoxy(20,2); cprintf("I N G R E S O D E D A T O S\n"); textattr(11); gotoxy(1,3); cprintf("\n"); gotoxy(5,4); textattr(11); cprintf("digite"); textattr(13); cprintf("<ALT>+<31>+<ENTER>"); textattr(11); cprintf(" para regresar al menu\n\n"); gotoxy(4,7); textattr(7); cprintf("CODIGO : "); gets(registro->codigo); if(strcmp(registro->codigo,"")!=0 ) /*si la cadena ingresada es diferente de "fin"*/ { gotoxy(4,8); textattr(7); cprintf("NOMBRE: "); gets(registro->alumno); int k=0; do{ if(k>0){clreol();gotoxy(4,20); cout<<"\tNo puede matricularse en mas de 7 cursos....Intentelo de nuevo"; } gotoxy(4,9); clreol(); textattr(7); cprintf("NUM. DE CURSO : "); gets(registro->num_cur); k++; }while(atoi(registro->num_cur)>7); k=0;
188
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas int nota; do{ // nota=atoi(registro->num_cur)*(2.5); gotoxy(4,20);clreol(); if(k>0) {clreol();gotoxy(4,20); cout<<"\tNo puede llevar mas de 21 creditos....Intentelo de nuevo"; } gotoxy(4,10); clreol(); textattr(7); cprintf("NUM. DE CRED. : "); gets(registro->num_cred);k++; }while((atoi(registro->num_cred)>21); /*&&(atoi(registro->num_cred)<nota)*/); } printf("\n"); if(strcmp(registro->codigo,"")==0) /*si la cadena ingresada es "fin"*/ registro->sig=NULL; /*la variable puntero es ltimo <fin de lista>*/ else{ j+=1; registro->sig=(nodo *)malloc(sizeof(nodo)); /*reserva memoria para otro registro*/ create (registro->sig); /*este registro es creado*/ /*recursividad*/ } return ; } void mostrar (nodo *registro) { gotoxy(3,4);textattr(2); cprintf(" CODIGO NOMBRE NUM. DE CURSOS NUM. DE CRED "); gotoxy(3,5);textattr(11); cprintf(""); gotoxy(3,r);textattr(11); cprintf(""); gotoxy(76,r);textattr(11); cprintf(""); r++; if(j!=0) { if(registro->sig !=NULL) /*si la variable puntero no apunta a nulo*/ { gotoxy(5,5+i); textattr(7); cprintf("%s\n",registro->codigo); gotoxy(24,5+i);textattr(7); cprintf("%s\n",registro->alumno); gotoxy(53,5+i);textattr(7); cprintf("%s\n",registro->num_cur); /*lista los campos del registro actual*/ gotoxy(63,5+i);textattr(7); cprintf("%s\n",registro->num_cred); /*lista los campos del registro actual*/ i+=1;lim=i; mostrar(registro->sig); /*lista el siguiente registro apuntado por su var. puntero*/ /*recursividad*/
189
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas } } else { gotoxy(4,6);textattr(YELLOW+BLINK); cprintf(" LA LISTA ESTA VACIA ...INGRESE DATOS"); r=6;} // return; } nodo *insertar (nodo *primero){ nodo *localizar(nodo *,char[]); /*funcion para localizar registro registro y devuelve su direccion*/ nodo *newregistro; /*nuevo registro a insertarse*/ nodo *marca; /*direcc. de mem. aux que recibira de la funcion localizar*/ char newelem[5]; char newelem1[50]; char newelem2[2]; /*variables auxiliares donde se almacenar n los nuevos valores*/ char newelem3[10]; char objetivo[50]; textattr(7); gotoxy(2,16); cprintf("\nNuevo Codigo : "); gets(newelem); textattr(7); cprintf("Nuevo Nombre: "); gets(newelem1); textattr(7); cprintf("Nuevo Numero de cursos: "); gets(newelem2); textattr(7); cprintf("Nuevo Numero de credito : "); gets(newelem3); textattr(7); cprintf("colocar antes del nombre : "); gets(objetivo); if (strcmp(primero->alumno,objetivo)==0) /* si el obj. se encuentra en el primer registro*/ { newregistro=(nodo *)malloc (sizeof(nodo)); /*reserva mem. para nuevo registro*/ strcpy(newregistro->alumno,newelem); strcpy(newregistro->codigo,newelem1); strcpy(newregistro->num_cur,newelem2); /*asignacion de valores*/ strcpy(newregistro->num_cred,newelem3); newregistro->sig=primero; /*el nuevo registro apunta al primero*/ primero = newregistro; /*el primer registro ahora es el nuevo registro*/ } else /*si el objetivo no es el primer registro*/ { marca = localizar (primero, objetivo); /*marca almacena le
190
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
191
direccion del objetivo localizado*/ if(marca==NULL) {cprintf("\nNo se encuentra coincidencias"); /*si no se encuentra el objetivo*/ getch();} else { newregistro = (nodo *)malloc(sizeof(nodo)); /*se reserva memoria para el nuevo registro*/ strcpy (newregistro->alumno, newelem); strcpy(newregistro->codigo,newelem1); strcpy(newregistro->num_cur,newelem2); /*asignacion de valores*/ strcpy(newregistro->num_cred,newelem3); newregistro->sig = marca->sig; /*el nuevo registro apunta al registro objetivo*/ marca->sig = newregistro; /*el nuevo registro es apuntado por la posc. objetivo*/ } } return(primero); } nodo *localizar(nodo *registro, char objetivo[]) /*localiza direccin de memoria*/ { while(registro->sig->alumno!='\0')//&&strcmp(registro->sig>alumno,objetivo)==0)) {if((strcmp(registro->sig->alumno,objetivo)==0)) return(registro); if(registro->sig==NULL) return (NULL); registro=registro->sig; }; } nodo *loc_curs(nodo *registro, char objetivo[]) /*localiza direccin de memoria*/ { while(registro->sig->alumno!='\0')//&&strcmp(registro->sig>alumno,objetivo)==0)) {if((strcmp(registro->sig->alumno,objetivo)==0)) return(registro); if(registro->sig==NULL) return (NULL); registro=registro->sig; }; } nodo *borrar(nodo *primero){ nodo *localizar (nodo *, char[]); nodo *marca; nodo *temp; char objetivo[50]; textattr(7); gotoxy(5,18); cprintf("Dato a borrar : "); gets(objetivo); if (strcmp(primero->alumno,objetivo)==0) /*si reg. a borrar ocupa primer
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas lugar en la lista*/ { temp = primero->sig; /*salva direccion del siguiente registro*/ free(primero); /*liberacion de memoria del registro*/ primero = temp; /*el primer registro de la lista ahora es el siguiente registro*/ } else{ marca = localizar(primero,objetivo); /*busca registro a borrar*/ if(marca==NULL) {printf("no se encuentra"); /*si registro buscado no encontrado*/ getch();} else{ temp = marca->sig->sig; /*salva direccion del siguiente registro*/ free(marca->sig); /*liberacion de memoria del registro*/ marca->sig = temp; /*la direccion del registro es el siguiente*/ } } return(primero); /*retorna direccion del registro*/ } void ordenat(nodo *p) {nodo *temp; nodo *q; while(p!=NULL) for(i=0;i<5;i++) for(j=i+1;j<=5;j++) if(stricmp((p+i)->alumno,(q+j)->alumno)>0) {*temp=*(p+i); *(p+i)=*(q+j); *(q+j)=*temp; } return ; } void sonido() {sound(400);delay(50);sound(1000);delay(50);sound(400);delay(50); nosound(); } void presen() {void ventana(); int i; char cad[51]=" Cargando base de datos.............PRESS KEY..."; clrscr(); ventana(); for(i=3;i<51;i++) {textattr(14);gotoxy(i,20);cprintf("");delay(50); gotoxy(i,18);cout<<cad[i-1]; } getch(); clrscr();ventana();
192
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
193
for(i=0;i<6;i++) usuario[i]=toupper(usuario[i]); gotoxy(15,15); cout<<"BIENVENIDO Sr. "<<usuario; getch(); } void ingreso() {clrscr(); gotoxy(10,8);textattr(11); cprintf(""); for(i=9;i<14;i++){gotoxy(10,i);cprintf("");} for(i=9;i<14;i++){gotoxy(60,i);cprintf("");} gotoxy(10,14);textattr(11); cprintf("\n"); gotoxy(10,8);textattr(30); cprintf(" "); textattr(7); int x=0; do{if(x>0) {gotoxy(11,10);clreol();textattr(11);gotoxy(60,10);cprintf("");} gotoxy(12,10);cout<<"CLAVE : ";gets(clave); x++; }while(stricmp(clave,"winmar")!=0); gotoxy(12,12);cout<<"USUARIO : ";gets(usuario); } void ventana() { gotoxy(6,5);textattr(11); cprintf(""); for(i=6;i<11;i++){gotoxy(6,i);cprintf("");} for(i=6;i<11;i++){gotoxy(72,i);cprintf("");} gotoxy(6,11);textattr(11); cprintf("\n"); gotoxy(6,5);textattr(30); cprintf(" "); gotoxy(9,7); textattr(7); cout<<"BASE DE DATOS";gotoxy(20,9);cprintf("\n RELACION DE ALUMNOS INGRESANTES 2000-I"); }
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas
194
ANEXO 2 //Implementacin de un rbol binario en modo grfico //Autor: Carlos Javier Guzmn. #include<graphics.h> #include<iostream.h> #include<string.h> #include<dos.h> #include<conio.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;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas texto(); //llama la caja de texto outtextxy(55,388,"Cuandos hijos tiene A "); gotoxy(31,25); 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 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);
195
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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); } 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) {
196
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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 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"); }
197
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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 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,".");
198
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas delay(15); } for(i=1; i<ty; i++) { outtextxy(px2,i+py2,"."); delay(15); } } int linea_der(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); } for(i=1; i<ty; i++) { outtextxy(px2,i+py2,"."); delay(15); } }
199
int presentacion() { cajadetexto_a(12,25,130,30);//px,py,largo,ancho A cuadro de mensaje arbo cajadetexto_a(482,25,130,30);//px,py,largo,ancho A cuadro de mensaje carlos sleep(1); setcolor(11); outtextxy(15,32,"Arboles"); sleep(1); outtextxy(68,44,"Binarios"); sleep(1); setcolor(11); outtextxy(495,32,"Carlos Javier"); sleep(1); outtextxy(524,44,"Guzman"); } int texto() { 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;
Universidad Nacional Abierta y A Distancia Unad Escuela de Ciencias Bsicas, Tecnologa e ingeniera Programa Ingeniera de Sistemas 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 spbrescribir } if(n==1 || n==2) { return n; } return n; }
200