Pi Lasy Colas
Pi Lasy Colas
Pi Lasy Colas
La abtraccin de datos es la tcnica que permite inventar o definir nuevos tipos de datos (tipos de datos definidos por el usuario), adecuados a la aplicacin que se desea realizar. Tipos Abstractos de Datos (TAD): Es un conjunto de valores y un grupo de operadores que trabajan sobre tales valores. Ejemplo: Si tenemos los nmeros dgitos (1, 2, 3,...,9) y los operadores (+, -, *,/), podremos sumar, restar, multiplicar, dividir esos valores. Un programa, se compone almenos un TAD ms un algoritmo de control (PROGRAMA= TAD + ALGORITMO DE CONTROL) Ventajas de los TADs 3. 4. 5. 6. 7. Mejora la comprensin y la presentacin de los programas Permite gran riqueza conceptual en nuetros programas Para los sistemas tipificados, optimiza el tiempo de compilacin Permite la modificacin de los mismos sin afectar la interfaz al usuario Un TAD, lo podemos volver a usar, siempre y cuando lo hayamos creado en archivo de tipo cabecera (*.h), el cual podemos invocar desde cualquier otro programa. 8. Se mantienen casi intactas, las peculiaridades del tipo definido. TAD en C Las caractersticas del lenguaje C que va a permitir la implementacin de un TAD son principalmente, las estructuras o registros para representacin de los datos , y las funciones para representar las operaciones especificadas. Adems en un archivo de inclusin o cabecera se guarda la representacin de los datos y el interfaz, prototipos de funciones, etc. Ejemplo:
Se desea especificar el un TAD que manipule nmeros complejos (los nmeros cmplejos estn compuestos por una parte real y otra imaginaria a+bi) .typedef struct { float a; int b; }complejo; La anterior declaracin puede hacerse en un archvo .h, y en programa principal, debe espcificarse esa inclusin de la siguiente manera: #include "nuevotad.h" y con ello, ya podemos hacer uso de nuestro TAD, haciendo declaraciones como la siguiente: complejo p1; Cdigo /*archivo camplejo.h*/ typedef struct { float a; int b; }complejo; /*archivo complejo.c*/ #include <stdio.h> #include <conio.h> #include "complejo.h" main() { complejo p, q,r; clrscr(); p.a=5.6; q.a=6.5; p.b=3; q.b=8; r.a=p.a+q.a; Ing. Alberto Moreno Cueva
3 r.b=p.b+q.b;
printf("El nemero complejo es %.1f + %di\n", r.a, r.b); getch(); return 0; } Explicacin El lector debe comprender la importanci, de lo que acabamos de hacer, y es que con la declaracin anterior, en cualquier otro de nuestros programas deseamos usar el tipo de dato, complejo, lo nico que debemos hacer es incluir la cabecera complejo. Hque definimos en un archivo .h, algunos escritores, indican que en este tipo de archivos (.h), podemos declarar las funciones que vamos a usar en nuetro programa, lo cual, no est errado, sino que; personalmente considero que, para mantener de una manera fidedigna, el concepto de TAD, debemos nicamente declararlo en el archivo *.h. Tambin hay que apuntar que la cabecvera complejo.h, se distingue de las dems por que va entre comillas ("") y no entre signos (<>), y es que, si una cabecera va entre signos mayor y menor que, le estamos indicando al compilador que lo busque en la carpeta de los includes (por lo menos para turbo C), pero si va entre comillas(""), es como decirle al compilador que busque el archivo *.h en la misma carpeta en la que est guardado el archivo *.c que estamos compilando. Lo siguiente de lo que hablaremos es, en sencia, la mdula central de sta segunda parte del curso, por tanto, si para el lector, no han quedado claros algunos conceptos de punteros, estructuras, etc; le recomiendo que vuelva a leer los captulos correspondientes, ya que de lo contrario, le ser un poco difcil la comprensin de lo que sigue, puesto que, continuamos con: La Gestin de Memoria Dinmica. Para ello, iniciremos hablando de una estrictura muy importante como lo son las: Pilas y sus Aplicaciones Una pila es un tipo especial de estructura de datos en la que slo se pueden insertar y eliminar nodos en uno de los extremos de la lista. Estas operaciones se conocen como "push" y "pop", respectivamente "empujar" y "tirar". Adems, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el nodo ledo. Estas caractersticas implican un comportamiento de lista LIFO (Last In First Out), el ltimo en entrar es el primero en salir.
El smil del que deriva el nombre de la estructura es una pila de platos. Slo es posible aadir platos en la parte superior de la pila, y slo pueden tomarse del mismo extremo.
Tambin una rimera de libros, en la que no se puede acceder a un determinado libro, sino se mueven primero los libros que estn encima de l. Las pilas se pueden implementar de dos formas: ->Como Arreglos ->Usando Memoria Dinmica. Operaciones con Pilas push-> Se utiliza para introducir elementos, sta funcin necesita como argumento a la pila y el elemento a introducir. pop-> se utiliza para sacar elementos de la pila, Como argumentos, necesita, unicamente a la pila.
Hemos llenado nuestra pila, llamada "s", con los valores que le insicamos en la funcin push. Ahora si queremos sacar el elemento del tope, basta indicar con la siguiente sentencia: Pop(s); Pop(s); Y la pila quedara:
Se debe tener en cuenta que, dentro de las funciones pop y push, puden estar otras funciones inmersas, por ejemplo, si queremos introducir ms datos, debemos tener otra funcin que verifique si la pila, no est llena. Por el contrario si queremos sacar datos, debemos sersiorarnos que la pila no est vaca, es ah donde nacen estas otras funciones que deben estar presentes en nuestros programas: Ing. Alberto Moreno Cueva
->stacktop->retorna el elemento superior de la pila. Representacin de Pilas usando arreglos Para sta abstraccin consideraremos que nuestra pila, est compuesta por un arreglo de n elementos y una variable que controla el subndice de la cima de la pila. De declaracin puede ser la siguiente: Typedef struct { char elementos[100]; int top; }Pila; donde Pila, es el nombre de nuestra estructura. Elementos, es el arreglo que contendr 100 caracteres Y top, es la variable, que ser inicializada a 1, y que aumentar (o disminuir) a medida que se agreguen (o eliminen) datos. Por ejemplo: s.top=-1; /*inicializamos la pila*/ push(&s, x); s.top++; /*ahora top vale 0*/ push (&s, y); s.top++; /*top vale 1*/ push(&s, k); s.top++; /*ahora top vale 2*/ pop(&s); s.top-- /*s.top=1*/ claro que ste aumento (o decremento) debe hacerse dentro de la funcin push (o pop), segn corresponda. Muchas veces un programa puede llevar otras funciones, pero digamos que eso ya es valor agregado por parte del programador, las funciones ms importantes son pop y push, y son esas las que vamos a describir a continuacin: Algoritmo de la funcin push (para arreglos) 9. 10. 11. Verificar si la pila no est llena incrementar en 1 el puntero ndice de la pila almacenar el elemento en la posicin del puntero de la pila
si la pila est vaca imprimir un mensaje sino est vaca, leer el elemento de la posicin del puntero de la pila decrementar en uno el puntero de la pila.
Ejemplo 10.2 Se desea guardar un aproximado de 100 nmeros enteros en una estructura tipo pila, la cual permita aadir elementos, sacar los elemtos e imprimir los datos contenidos en la pila. /*pila en forma de arreglo*/ #include <stdio.h> #include <conio.h> /*declaracion de la pila*/ typedef struct{ int datos[100]; int top; }Pila; /*declaracion de las funciones*/ void push(Pila *ps, int x); /*Introduce un elemento a la pila*/ int top (Pila *ps); /*elimina y muestra un elemento de la pila*/ int empty (Pila *ps); /*Programa Pincipal*/ main() { Pila pila; /*definicion de la variable pila*/ int x, opc=5, i, k=0; pila.top=-1; clrscr(); while(opc!=4) { printf("\t\t\t MENU PRINCIPAL\n\n\n"); printf("\t1. Introducir datos\n"); printf("\t2. Sacar datos\n"); printf("\t3.Imprimir la pila\n"); printf("\t4.Salir\n"); Ing. Alberto Moreno Cueva
7 scanf("%d", &opc); switch(opc) { case 1: if(pila.top==99) printf("ERROR, pila llena\a\n"); else { printf("Ingrese el dato\n"); scanf("%d", &x); push(&pila, x); k++; } break;
case 2: printf("El elemento sacado es %d\n\n", pop(&pila)); k--; getch(); break; case 3: if(pila.top>=0) { printf("Los elementos de la pila son:\n"); for(i=0; i<k; i++) printf("%d->", pila.datos[i]); getch(); } else printf("No hay datos en la pila\a\n"); break; } clrscr(); } printf("Fin del programa\n\n"); getch(); Ing. Alberto Moreno Cueva
8 return 0; } /*funcin que agregaun dato a la pila*/ void push (Pila *ps, int x) { ps->datos[++(ps->top)]=x; }
/*funcin que elimina y devuelve un elemento de la pila*/ int pop(Pila *ps) { int r=NULL; if(empty(ps)==1) printf("No hay elementos para sacar\a\n"); else r=ps->datos[(ps->top)--]; return r; } /*funcion que verifica si la pila esta vaca*/ int empty (Pila *ps) { int r; if(ps->top==-1) r=1; else r=0; return r; } Explicacin El programa enterio, muestra, en forma sencilla, el uso de las pilas, en forma esttica, (usando arreglos), con funciones muy sencillas como pop, push y empty, pero el lector debe recordar que l puede modificar, crear otras funciones (o estas mismas) segn sea el problema que se est resolviendo. Para el caso, en este ejemplo, he usado sintaxis como la siguiente: Ing. Alberto Moreno Cueva
9 r=ps->datos[(ps->top)--];
lo cual, podra haberse hecho en ms pasos, de la siguiente forma: i=ps->top--; r=ps->datos[i]; y as sucesivamente, por tanto se debe encasillar a que la sintaxis anterior es la nica solucin viable a ste problema. Las instrucciones pueden cambiar, pero lo que debe permanecer siempre invariable, es el algoritmo correspondiente a las funciones anteriores (pop y push). Tambin el lector se preguntar, el por que hemos usado una variable auxiliar, identificada como k. Pues bien la respuesta es muy simple, esta variable sirve para controlar el nmero de impresiones que se harn en la funcin pertinente es por ello que esa variable crece (en la funcin push) y decrece (en la funcin pop). Pilas Implementadas con Memoria Dinmica Las pilas, que hasta ahora hemos tratado, han sido usando nicamente memoria esttica, es decir definimos ciertos espacios, dentro de los cuales guardamos nuestros datos. Pero, que pasara, si los datos superan el espacio reservado en memoria para ellos?. Es aqu donde surge, la importancia que la pila crezca y decrezca dinmicamente, donde el nico lmite existente es la memoria misma de la pc. La forma de declararlo es la siguiente: typedef struct _nodo { int dato; struct _nodo *siguiente; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Pila;
tipoNodo es el tipo para declarar nodos, evidentemente. pNodo es el tipo para declarar punteros a un nodo. Pila es el tipo para declarar pilas.
As que sigue siendo muy importante que nuestro programa nunca pierda el valor del puntero al primer elemento, igual que pasa con las listas abiertas.
10
Teniendo en cuenta que las inserciones y borrados en una pila se hacen siempre en un extremo, lo que consideramos como el primer elemento de la lista es en realidad el ltimo elemento de la pila. Las operaciones bsicas siguen siendo las mismas, aunque claro con sus respectivas variantes: -push, para igresar nuevos valores en la pila -pop, para eliminar lementos de la pila Funcin push (para memoria dinmica) 15. Supondremos que ya se cre un nodo nuevo (hablaremos de eso despus), si la pila est vaca, es decir el puntero que apunta a la pila, est apuntando a NULL. 16. lo que debemos hacer es que, nodo en su parte de siguiente, apunte a NULL 17. Y el puntero que apunta a la pila, apunte ahora al nuevo nodo. Un nodo, est compuesto del dato (que puede ser entero, real, carcter u otra estructura) y un puntero, que enlazar ste nodo con el siguiente.
El puntero Pila, apunta a la cima de la pila, cuando no hay datos est inicializada a NULL. Si la pila, no est vaca (es decir hay elementos): creamos un nuevo nodopara el valor que colocaremos en la pila
18. 19.
hacemos que nodo, en su parte de siguiente, apunte a pila hacemos que pila, apunte a nodo.
Funcin Pop Partiremos del supuesto que exiten ms de un nodo en la pila, el algoritmo, sera el siguiente:
11
Hacemos que nodo, apunte al primer elemento de la pila asignamos a pilala direccin del segundo elemento de la pila guardamos el contenido del nodo para devolverlo posteriormente liberamos la memoria del nodo que queremos eliminar.
(NOTA: las imgenes anteriores han sido tomadas de http://www.conclase.net/c/edd/index.php?cap=002b). Si por ejemplo, tenemos slo un nodo, el proceso ser parecido, slo que pila, apuntara ahora a nodo->siguiente, que sera NULL. Funcin push void push(Pila *pila, int v) { pNodo *nuevo; nuevo=(pNodo)malloc(sizeof(tiponodo)); nuevo->valor=v; nuevo->siguiente=*pila; *pila=nuevo; } en la funcin anterior, observamos que, no devuelve ningn valor, que recibe como argumentos, la direccin de la pila y el valor (entero, en ste caso) que vamos a guardar en la pila. Posteriomente, declara un nuevo puntero que tendr la direccin del nodo que vamos a crear. nuevo=(pNodo)malloc(sizeof(tiponodo)) quiz, la lnea anterior es una de las ms potentes e interesantes que podemos encontrar y es que con esa lnea le estamos diciendo al compilador que vamos a crear un nuevo nodo, del tamao de tiponodo, para ello usamos la instruccin malloc, que sive para pedirle al sistema memoria, sizeof, lo que hace es determinar el tamao (en bytes), de la variable que le pasamos como argumento y ese valor, es lo que malloc le pide al sistema, y como ste devuelve un puntero del tipo void, por eso es necesario hacer el casting: (pNodo)malloc. Ing. Alberto Moreno Cueva
12 Funcin Pop: int pop (Pila *pila) { pNodo nuevo; int v; nodo=*pila; if(!nodo) *pila=nodo->siguiente; v=nodo->valor; free(nodo); return (v); }
Note que sta funcin lo nico que recibe es el puntero a la pila. La funcin free(), sirve para liberar ese espacio de memoria. Ejemplo 10.3 Cdigo completo para el uso de las pilas #include <stdio.h> #include <conio.h> typedef struct nodo{ int valor; struct nodo *siguiente; }tiponodo; typedef tiponodo *pNodo; typedef tiponodo *Pila; void push(Pila *pila, int v); int pop(Pila *pila); main() { Pila pila=NULL; push(&pila, 20); push(&pila, 30); Ing. Alberto Moreno Cueva
13 push(&pila, 40); printf("%d", pop(&pila)); printf"%d", pop(&pila)); getch(); return 0; } void push(Pila *pila, int v) { pNodo *nuevo; nuevo=(pNodo)malloc(sizeof(tiponodo)); nuevo->valor=v; nuevo->siguiente=*pila; *pila=nuevo; } int pop (Pila *pila) { pNodo nuevo; int v; nodo=*pila; if(!nodo) *pila=nodo->siguiente; v=nodo->valor; free(nodo); return (v); } Explicacin.
La salida, de ste programa no es muy atractiva, pero hagamos un esfuerzo por comprenser que es lo que hemos hecho. Y aunque lo que veamos en pantalla, son slo unos nmeros, que a lo mejor al principio, no tengamos ni idea de donde aparecieron, (igual que yo, la primera vez), debemos estar seguros que ste programita cumple con todas las especificaciones de una pila. Por ejemplo, las invocaciones de push, mandamos a la pila, los valores de 20, 30, 40. de los cuales el nmero 40, es el que se encuentra en la cima de la pila, por eso, al llamar a pop, manda a impresin el nmero 40. ahora quien est en la cima es 30, y al volver a Ing. Alberto Moreno Cueva
14
invocar a pop, es ese valor el que se imprime. El lector puede modificar este programa colocando otros valores en push, agregando ms llamadas a pop, etc. A pesar que el programa anterior es muy apropiado para exponer el funcionamiento de las pilas, hasta cierto punto, est incompleto, ya que no interacta mucho que digamos con el usuario. Por ello mostramos a continucacin otro cdigo que es un poco ms completo. En el cual no pasamos parmetros a las funciones, por que las variables son de tipo global, ste es un mtodo, para hacer las cosas un poco ms fciles. Ejemplo 10.4 Se desean guadar en una pila, cierta cantidad de nombres, a la vez que el usuario puede eliminar e imprimir el estado de la pila, segn lo desee. Disee un programa en C, que de soporte a dicho problema, usando pilas implementadas con memoria dinmica. /* Ejemplo de una pila. */ #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <alloc.h> void push(void); void pop(void); void visualizar(void); struct pila { char nombre[20]; struct pila *ant; }*CAB=NULL,*AUX=NULL; main( )/* Rellenar, extraer y visualizar */ { char opc=8; while(opc!=4) { clrscr( ); /* borramos la pantalla */ printf("\t\t1.- Insertar\n"); printf("\t\t2.- Extraer\n"); printf("\t\t3.- Visualizar la pila\n"); Ing. Alberto Moreno Cueva
15 printf("\t\t4.- Salir\n\n"); opc=getch( ); switch(opc) { case '1': push( ); break; case '2': pop( ); break; case '3': visualizar( ); } } getch(); } void push(void) { AUX=(struct pila *)malloc(sizeof(struct pila)); clrscr( ); printf("Nombre: "); gets(AUX->nombre); if (CAB==NULL) { CAB=AUX; AUX->ant=NULL; } else { AUX->ant=CAB; CAB=AUX; }
16 } void pop(void) { if (CAB==NULL) return; AUX=CAB; CAB=CAB->ant; free(AUX); } void visualizar(void) { if (CAB==NULL) return; clrscr( ); AUX=CAB; while (AUX!=NULL) { printf("Nombre: %s\n",AUX->nombre); AUX=AUX->ant; } getch( ); } Explicacin
ste ejemplo es un poco ms completo, ya que le permite al usuario, interactuar, al poder ingresar los datos cmo l los desee, adems que, note, que en las funciones (push, pop e insertar) no mandamos parmetros. Ya que stos son declarados fuera del main(), por tanto se pueden acceder a ellas, por cualquier funcin dentro del programa. Lo cual puede ser muy til, cuando estamos trabajando, por ejemplo, con cadenas de caracteres, como en ste caso. Evaluciones de Expresiones Las expresiones aritmticas que hasta ahora hemos usado, las encontramos en forma infija, es decir usando (), *,/,-,+... Ejemplo: X=z+(b+c)^(q-m)-(b*c) A la expresin anterior tambin algunos autores la llaman, interfija. Sin embargo las expresiones tienen otras formas de poderlas representar, por ejemplo: la notacin posfija o tambin conocida como polaca inversa (en honor al matemtico de origen Ing. Alberto Moreno Cueva
17
polaco, que la propuso), y sta consiste en colocar el operador a continuacin de los operandos. Por ejemplo: A*b/(c-d) /*infija*/ A*b/c-d /*quitamos parntesis*/ Ab*/cd-/*signo delante de operador*/ Ab*cd-/ /*posfija*/ Otro ejemplo: A+(B*C) A+B*C A+BC* ABC*+ Ahora bien, lo anterior podra parecer bastante complejo, y ciertamente lo es, por lo cuala continuacin mostramos el algoritmo para pasar una expresin de infija a posfija: 24. 25. 26. 1. 2. leer la cadena de caracteres, y repetir el paso 2 al 4 por cada carcter si es un operando, pasarlo a expresin posfija si es un operador: si la pila est vaca, meterlo en la pila. Repetir desde 1 si la pila no est vaca:
-si la prioridad del operador ledo es mayor que la prioridad del operador cima de la pila, meterlo en la pila y repetir dede 1 -si la prioridad del operador es menor o igual que la prioridad del operador de la cima de la pila, sacar operador cima de la pila y pasarlo a la expresin posfija, volver a 3 27. 1. 2. 3. 4. 28. 29. si es parntesis derecho: sacar operador cima de la pila y pasarlo a la expresin posfija si nueva cima es parntesis izquierdo suprimir elemento cima si cima no es parntesis izquierdo, volver a 4.1 volver a partir de 1 si quedan elementos en la pila pasarlos a la expresin posfija fin del algoritmo
(Algoritmo tomado de: "Algoritmos y estructuras de datos, una perspectiva en C". Joyanes Aguilar, Luis. Madris 2004. Pg. 329) el cdigo sera el siguiente: Ejemplo 10.5 #include<stdio.h> #include<string.h> #define n 60 Ing. Alberto Moreno Cueva
18
/* *********** Prototipo de funciones de pila **************** */ void push(struct pila *p, struct operador num);//meter datos a la pila int full(struct pila *p); //devuelve 1 si la pila esta llena void clear(struct pila *p); //limpia la pila struct operador pop(struct pila *p); //elimina el dato de la cima y lo devuelve struct operador ver(struct pila *p); //devuelve el dato de la cima sin eliminarlo int empty(struct pila *p); //devuelve 1 si la pila esta vacia void tranformacion( char expin[n], char *expos,struct pila *p); //transforma de infija a posfija int infija(char expin[n]); //devuelve 1 si la expresion infija es valida struct operador asignacion(char i); //devuelve la prioridad de los operadores void marco(); //funcion adicional para el marco void error(); /*describe las posibles causas de error en la introduccion de la expresion infija*/ /* ***************** Declaracion de la pila ***************** */ struct operador{ int prioridad; char caracter; }; struct pila{ int tope; struct operador vect[n]; }; /* ********************** Programa Principal************************* */ void main(void) { char expin[n],expos[n];/* expin contiene la expresion infija expos contiene la expresion posfija */ int s; struct pila pila1; //creacion de la pila clrscr(); clear(&pila1); //inicializacion de la pila Ing. Alberto Moreno Cueva
19 marco();
printf("Introduzca una expresion en notacion infija \n"); scanf("%s",expin); //introduccion de la expresion infija clrscr(); tranformacion( expin,expos,&pila1); getch(); clrscr(); marco(); printf("-.Si desea introducir otra expresion presione 1\n"); printf("-.Otro numero para salir.\n"); scanf("%i",&s); if(s==1) main(); } /* *****funciones de ordenamiento de expresion infija a postfija ******** */ void tranformacion( char expin[n], char expos[n], struct pila *p) { struct operador auxiliar; /* auxiliar se utiliza para introducir operadores a la pila*/ struct operador comparador;/* comparador se utiliza para contener el valor de la cima de la pila */ int i,j,bandera; /* i y j son variables de cambio , bandera permite sacar los operadores de apertura de la pila y operadores de menor prioridad al que se introducira*/ if( infija(expin)== 1) //1.si expresion infija es valida { for(i=0,j=-1 ;i<=(strlen(expin)-1);i++)//1.evaluacion caracter por caracter { // 2. si es caracter lo copiara en la expresion posfija if (((expin[i]>=65 )&&(expin[i]<=90)) || ((expin[i]>=97 )&& (expin[i]<=122))) { Ing. Alberto Moreno Cueva
if( (expin[i]=='}' )||(expin[i]==']' )||(expin[i]==')' )) { bandera=1; do{ auxiliar=pop(p); //quite la cima de la pila j+=1; expos[j]=auxiliar.caracter;/* agregar el operador quitado a la expresion posfija */ comparador=ver(p); //comparador contiene lo que hay en la cima if(comparador.prioridad==0)//si la cima de la pila es operador de apertura { auxiliar=pop(p); //quitar operador de apertura bandera=1; } else bandera=0; //si cima de la pila es operador regrese a 3 }while(bandera==0); } //cierra 3 else // 4 si es operador de apertura o +,/,*,-,^ { bandera=1; do{ auxiliar=asignacion(expin[i]); //asignacion prioridad a operadores if (empty(p)==1) // si la pila esta vacia operador entra a la pila { if(auxiliar.prioridad==6)// si es operador de apretura auxiliar.prioridad=0; // en la pila su prioridad es 0 Ing. Alberto Moreno Cueva
21 push(p,auxiliar); bandera=1; }
else{ // comparando prioridad de operadores del tope y el entrante comparador=ver(p); //comparador tiene el valor de la cima if(auxiliar.prioridad > comparador.prioridad) { if(auxiliar.prioridad==6) //si es operador de apertura auxiliar.prioridad=0; //en la pila su prioridad es 0 push(p,auxiliar); bandera=1; } else { //si operado entrante es menor o igula que el de la pila auxiliar=pop(p);//sacar operandor de la cima de la pila 4 j+=1; expos[j]=auxiliar.caracter; //agregarlo a expresion posfija bandera=0; //volver a evaluar evaluar operador entrante regreso a } } }while(bandera==0); }//cierra 4 } }//cierra 1 while(empty(p)!=1)//sacar todos los operadores sobrantes en pila { auxiliar=pop(p); j+=1; expos[j]=auxiliar.caracter; } //impresion de resultado marco(); Ing. Alberto Moreno Cueva
22
printf("\n\nLA EXPRESION EN NOTACION INFIJA ES :\n "); printf("%s",expin); printf("\n\nLA EXPRESION EN NOTACION POSFIJA ES :\n"); for(i=0;i<=j;i++) { printf("%c",expos[i]);} } //cierre de expresion infija valida else{ //expresion infija no valida marco(); printf("\n\n\aLA EXPRESION INFIJA ES ERRONEA:"); error(); } }//cierra funcion transformacion //funcion que asigna la prioridad de los operadores struct operador asignacion(char i) { struct operador auxiliar; switch(i){ //asignacion de prioridades case '^': auxiliar.prioridad=5; auxiliar.caracter='^'; break; case '*': auxiliar.prioridad=4; auxiliar.caracter='*'; break; case '/': auxiliar.prioridad=3 ; auxiliar.caracter='/'; break; case '+': auxiliar.prioridad=2 ; auxiliar.caracter='+'; break; case '-': auxiliar.prioridad=1 ; auxiliar.caracter='-'; break; Ing. Alberto Moreno Cueva
23 case '(': auxiliar.prioridad=6; auxiliar.caracter='('; break; case '[': auxiliar.prioridad=6 ; auxiliar.caracter='['; break; case '{': auxiliar.prioridad=6 ; auxiliar.caracter='{'; break; } return auxiliar; }
/* ************ funcion de validacion de la expresion *********************/ int infija (char expin[n]) { int i,numero[3],parentesis,bandera=1; //evaluacion: operando operador operando for(i=1;i<=(strlen(expin)-2);i++) { if((expin[i]=='+')||(expin[i]=='-')||(expin[i]=='*')|| (expin[i]=='/')||(expin[i]=='^')) { if(!(((expin[i+1]>=65 )&&(expin[i+1]<=91)) || ((expin[i+1]>=97 )&& (expin[i+1]<=123)) ||(expin[i+1]==40) || (expin[i+1]==41 )|| (expin[i+1]==93) || (expin[i+1]==125 ) )) bandera=0; if(!(((expin[i-1]>=65 )&&(expin[i-1]<=91)) || ((expin[i-1]>=97 )&& (expin[i-1]<=123)) ||(expin[i-1]==40) || (expin[i-1]==41 )|| (expin[i-1]==93) || (expin[i-1]==125 ) )) bandera=0; }; } //evaluacion:no deben haberdos operandos juntos Ing. Alberto Moreno Cueva
24 for(i=0;i<=(strlen(expin)-2);i++) {
if (((expin[i]>=65 )&&(expin[i]<=90)) || ((expin[i]>=97 )&& (expin[i]<=122))) { if (((expin[i+1]>=65 )&&(expin[i+1]<=91)) || ((expin[i+1]>=97 )&& (expin[i+1]<=123)) || (expin[i+1]==40 )) bandera=0; if (((expin[i-1]>=65 )&&(expin[i-1]<=90)) || ((expin[i-1]>=97 )&& (expin[i-1]<=122)) || (expin[i-1]==41 )|| (expin[i-1]==93) || (expin[i-1]==125 )) bandera=0; } } // evaluacion: la expresion no comience con operador if((expin[0]=='+')||(expin[0]=='-')||(expin[0]=='*')||(expin[0]=='/')|| (expin[0]=='^')) bandera=0; // evaluacion: la expresion no termine con operador if((expin[strlen(expin)-1]=='+')||(expin[strlen(expin)-1]=='-')|| (expin[strlen(expin)-1]=='*')||(expin[strlen(expin)-1]=='/')|| (expin[strlen(expin)-1]=='^')) bandera=0; //evaluacion: despues de un simbolo de apertura no debe haber operador for(i=0;i<=(strlen(expin)-2);i++) { if((expin[i]=='(')||(expin[i]=='{')||(expin[i]=='[')) if ((expin[i+1]=='+')||(expin[i+1]=='-')||(expin[i+1]=='*')|| (expin[i+1]=='/')||(expin[i]=='^')) bandera=0; }; //evaluacion: antes de un simbolo de cierre no debe haber operador Ing. Alberto Moreno Cueva
25 for(i=1;i<=(strlen(expin)-1);i++) { if((expin[i]==')')||(expin[i]=='}')||(expin[i]==']'))
if ((expin[i-1]=='+')||(expin[i-1]=='-')||(expin[i-1]=='*')|| (expin[i-1]=='/')||(expin[i-1]=='^')) bandera=0; } //evaluacion de los parentesis parentesis=0; //suma final=0, evita (}, (],[} for(i=0;i<=2;i++) numero[i]=0; // evita {) ,{],[) for(i=0;i<=(strlen(expin)-1);i++) { switch(expin[i]) { case '(':parentesis+=1; numero[0]+=1; break; case '[':parentesis+=2; numero[1]+= 2; break; case '{':parentesis+=3; numero[2]+=3; break; case ')':parentesis-=1; numero[0]-=1; if(parentesis<0) bandera=0; break; case ']':parentesis-=2; numero[1]-=2; if(parentesis<0) bandera=0; break; Ing. Alberto Moreno Cueva
if(parentesis!=0) // si la suma de los parentesis es <> 0 existe error bandera=0; for(i=0;i<=2;i++) // debe haber un numero igual operadores {if(numero[i]!=0) // de cierre y apetura por cada tipo bandera=0;} return bandera; }//terminacion de funcin validacin expresin /* ************************* funciones de la pila ******************* */ int full (struct pila *p) //funcion full devuelve 1 si la pila esta llena { if (p->tope==4) return 1; else return 0; } void push(struct pila *p,struct operador num)//funcion push encargada de { //introducir datos a la pila if(full(p)==1) printf("pila llena"); else { p->tope++, p->vect[(p->tope)]=num; } } void clear(struct pila *p)//funcion clear encargada de limpia la pila Ing. Alberto Moreno Cueva
27 { p->tope=-1; }
int empty(struct pila *p)// funcion empty devulve 1 si la pila esta vacia { if (p->tope==-1) return 1; else return 0; } struct operador pop(struct pila *p) //funcion pop quita el dato que { //se encuntre en la cima de la pila struct operador auxiliar; if (empty(p)==1) { auxiliar.caracter='0'; } else { auxiliar= p->vect[p->tope]; p->tope--; }; return auxiliar; }; struct operador ver(struct pila *p) // funcion ver devuelve el dato { // que esta en la cima de la pila struct operador auxiliar; // sin removerlo auxiliar= p->vect[p->tope]; return auxiliar; }; /* ***************** funcione adicional ******************** */ void marco() Ing. Alberto Moreno Cueva
printf("\nPROGRAMA QUE CALCULA UNA EXPRESION EN NOTACION POSFIJA\n\n\n"); } void error() { printf("Posibles razones:\n"); printf("1-hay dos operadores juntos\n"); printf("2-hay dos operandos juntos\n"); printf("3-la expresion comienza con operador\n"); printf("4-la expresion termina con operador\n"); printf("5-hay un operador luego de ( ,[ o{ \n"); printf("6-hay un operador antes de ),] o }\n"); printf("7-Existe un error en los parentesis\n"); } NOTA: el cdigo anterior fue elaborado por : Nelson Eduardo Najarro Alvarez, para la Asignatura de Programacin II, de la Carrera de Ingeniera de Sistemas Informticos de la Universidad de El Salvador. El ejemplo anterior es baste complejo y muy largo, pero decid colocarlo, por que en muchos libros slo colocan las funciones o trozos del cdigo, pero como aqu queremos hacer las cosas bien, hemos decidido colocar el cdigo completo. Adems que en muchas universidades o colegios, dejan como tarea ste cdigo, as creo que te servir mucho. Cuestionario 1. Qu es un TAD?_________________________________________________ ____________________________________________________ ________________________________________
29 2.
Cul es la importancia del TAD?_________________________________________________ __________________________________________ 3. Para que se usan las pilas?________________________________________________ ____________________________________________________ ______________________________________ 4. Cmo funcionan las pilas?________________________________________________ ____________________________________________________ ______________________________________ 5. Mencione y explique las implementaciones de Pilas en C:___________________________________________________ ___________________________________________ En las siguientes funciones, descubre donde hay errores, identifcalos y corrgelos. 1. void push ( ptrNodoPila *ptrCima, int info ) { ptrNodoPila ptrNuevo; /* apuntador al nuevo nodo */ ptrNuevo = malloc( sizeof( NodoPila ) ); /* inserta el nodo en la cima de la pila */ if ( ptrNuevo != NULL ) { ptrNuevo->dato = dato; ptrNuevo->ptrSiguiente = *ptrCima; *ptrCima = ptrNodoPila; } /* fin de if */ else { /* no queda espacio disponible */ printf( "%d no se inserto. Memoria insuficiente.\n", info ); } /* fin de else */ } /* fin de la funcin empujar */ 2. /* Elimina un nodo de la cima de la pila */ int pop( ptrNodoPila *ptrCima ) { ptrNodoPila ptrTemp; /* apuntador a un nodo temporal */ ptrTemp = *ptrCima; valorElim = ( *ptrCima )->dato; *ptrCima = ( *ptrCima )->ptrSiguiente; Ing. Alberto Moreno Cueva
Ejercicios
30. Un vector en fsica, puede representarse mediante sus componentes x, y, z; de la siguiente forma: V=2i + 4j 6k. Cuando una de las componente est ausente, simplemente no se escribe (o la podemos representar con un cero: V= 0i + 4j + 6k.) Cree un TAD que lea un vector y luego calcule: -Su magnitud (||V||=sqrt(a^2+b^2+c^2)). Donde a,b y son los coeficientes -Su vector unitario: U=a/||V|| + b/||V|| + c/||V|| 31. los nmeros radicalesse componen de una base y un signo radical, disee un programa que sea capaz de implementar un TAD llamado radical y permita: -sumarlos, restarlos o dividirlos; segn lo desee el usuario. 32. Dise un TAD que represente un tipo cadena (string), y que permita las siguientes operaciones: leer la cadena, imprimirla, copiarla, determinar el tamao de la cadena y buscar un carcter especfico en la cadena. 33. se desea transformar un nmero base10, a binario; utilizando una pila, en la cual se guarden los residuos de las divisiones. A partir de las impresiones generadas por la pila, muestre el nmero binario equivalente. 34. A partir de un prrafo ingresado por el usuario, disee un programa que, determine el nmero de consonantes y vocales que estn presentes en dicho prrafo. 35. Disee un programa que lea una cadena de caracteres y luego la imprima en forma inversa 36. Se desea crear una pila en c, que lea cierta cantidad de nmeros enteros y luego muestre: -La suma de todos los nmeros y el producto de ellos, cuntos son mayores que cero. 37. una palabra es polindromo si se lee igual por la derecha que por la izquierda, disee un programa que lea una palabra, luego imprim esa misma palabra al revs y con un mensaje indique si es o no palndromo. 38. En una tienda de repuestos llevan su control de inventarios, mediante el sistema UEPS (ltimos en entrar, primeros en salir), el cual puede ser controlado mediante una estructura del tipo Pila; en sta tiendo necesitan que se registren sus productos, los cuales tendrn los siguientes datos: cdigo, descripcin, precio unitario, fecha de ingreso (del sistema). Adems de registrar las rdenes de salida y mostrar los siguientes reportes: ventas por fecha, ventas por producto (ingresando el cdigo), cantidad de productos que exceden un precio determinado. El cual ser ingresado por el usuario.
31
Captulo Colas
En ste capitulo hablaremos de una esructura muy utilizada e importante en el rea de la programacin, nos referimos a las estructuras de datos tipo Colas. Por ejemplo cuando mandamos a impresin un documento, ste acta en forma de cola, es decir; primera en entrar, primera en salir, o por sus siglas en ingls (First in, first out), ya que el primer documento que llega a la "Cola de Impresin", es el primer documento que es impreso. Pero las colas, no slo son usadas por las impresoras, sino tambin en la vida cotidiana tienen otras muchas aplicaciones, por ejemploel celular, cuando recibimos un mensaje de texto, ste es almacenado en un "lugar" (dentro del chip) que se comporta como cola; otro ejemplo son las colas de tareas en la pc, las colas de prioridades,etc. Claro, estos ejemplosson muy complejos y exigen que tengamos conocimientos de sistemas operativos (uso y creacin), por tanto y para resguardar nuestra salud mental, no vamos a entrar en tanto detalle respecto a las aplicaciones complejas de las colas, sin embargo trataremos algunas abstracciones que nos ayudarn a comprender el funcionamiento de sta estructura. Concepto de Cola Una cola, es una estructura en la cual se almacenan elementos (en orden de llegada), es decir que, se ingresan los elementos por la parte final de la estructura y se eliminan (o se sirven) por la parte del frente.
Como puede observarse, sta estructura cuenta con dos apuntadores, uno que apunta al ltimo elemento y otro que apunta hacia el primer elemeto (o el elemento del frente). Se debe tener en cuenta que, una cola, almacena los datos en ella, manteniendo cierto orden, ya que sus elementos se aaden por el final de la cola y se extraen o se eliminan por la parte de frente. El lector dispernsar el por que la insistencia de ello, pero cuando uno inicia este estudio, al momento de programar, se cunfe fcilmente, por que las sentencias de las funciones son muy parecidas a la de una pila, y en algunas ocaciones me pasaba que empezaba programando una cola, pero terminaba funcionando como pila. Las operaciones con las colas son: -insert (q, x) Inserta el elemento x en la parte posterior de la cola q -remove(q) Suprime el elemento delantero de la cola q Ing. Alberto Moreno Cueva
32
-empty(q) Retorna True o false, si la cola tiene elementos o no. Las colas pueden implementarse, al igual que las pilas, mediante dos formas:
La figuara de arriba, muestra la forma de implementar una cola, como arreglo, en la que cada casilla, representa una estructura compuesta por el tipo de dato a guardar (o bien otra estructura). Las variables q.rear y q.front, se van modificando cada vez que aadimos o eliminamos datos de nuestra cola. Para determinar la cantidad de elementos en cualquier momento es: Cant=q.rear-q.front+1 Ahora vemos un ejemplo del funcionamiento de las colas, implementadas como arreglos: Supongamos que en una cola vamos a almacenar elementos de tipo carcter. Insert(&q, A);
33 remove(&q);
q.rear=4 q.front=2 Como se puede ver, al manejar una cola en forma de arreglolineal, resulta complicado y poco eficiente, por que al eliminar elementos quedan nodos vacos y cuando se llega al ltimo elemento de la cola, aparecer un mensaje de error, (o al menos debera aparecer), que indioque que ya no hay ms espacios, sin embargo, eso sera una total mentira, ya que tenemos elementos sin utilizar; una solucin para ello podra ser que cada vez que se eliminen un elemento mover todos los datos hacia la izquierda, pero, te imaginas la cantidad de cdigo para realizar esa accin???... eso es muy complejo (y no resuelve el problema de la eficiencia), entonces es donde surge, el considerar la cola, como un arreglo circular.
34
Pero como puede verse, el manero de los subndices, resulta bastante complejo, poco accesible y, tampoco se resuelve el problema de la eficiencia; es decir que sta solucin tampoco resulta eficiente para el problema que se intenta resolver, por esas consideraciones no trataremos acerca de esta estructura, en forme de arreglo, por que no nos resulta viable, nos concentraremos en la implementacin, usando memoria dinmica, la cual, si resulta ms eficiente y hasta cierto punto menos compleja. Colas implementadas con Memoria Dinmica Para hacer uso de las colas, debemos declarar el nodo y los apuntadores de la cola, as: typedef struct _nodo { int dato; struct _nodo *siguiente; } tipoNodo; typedef tipoNodo *pNodo; typedef tipoNodo *Cola; Donde, es evidente que, tipoNodo es el tipo de los nodos que compondrn la cola. pNodo es el tipo para declarar punteros a un nodo. Cola es el tipo para declarar colas
Las operaciones, siguen siendo las mismas: Aadir Eliminar Algoritmo Para Aadir elementos en la cola Si la cola est vaca: 2. Puntero primero y puntero ltimo deben apuntar a NULL 3. Creamos el nuevo nodo (con ayuda de malloc() ) Ing. Alberto Moreno Cueva
35
4. Luego la parte siguiente del nuevo nodo, debe apuntar a NULL 5. Tanto, primero y ultimo deben apuntar, al nuevo nodo.
Si la cola, tiene elementos: 6. Creamos el nuevo nodo, ya sea en la misma funcin o con ayuda de otra funcin 7. Hacemos que la parte siguiente del nodo apunte a NULL 8. Luego, la parte siguiente de ultimo, deba apuntar al nodo 9. Y ultimo, ahora debe apuntar al nodo. Algoritmo Para eliminar 10. Guardar el elemento dato nodo en una variable temporal 11. colocar un apuntador temporal hacia el nodo primero de la cola 12. cambiar el puntero (hacia el nodo) primero, hacia el nodo hacia el cual apunta el nodo, que estaba al frente de la cola 13. si despus de eso el apuntador primero es NULL entonces no hay ms datos en la cola y el apuntador ultimo tambin debe apuntar a NULL 14. Liberar memoria apuntada por el apuntador temporal 15. devolver el valor guardado en la variable temporal
Ejemplo 11.1 Se desea almacenar cierto nmero de enteros en una estructura de tipo Cola, disee una solucin que permita, leer, eliminar datos de la cola. #include <stdio.h> #include <conio.h> #include <stdlib.h>
36 /*declaracion de la cola*/ struct nodo { int elemento; struct nodo *siguiente; }; typedef struct nodo Nodo; typedef struct { Nodo *frente; Nodo *final; }Cola; /*declaracion de las funciones*/ void CrearCola(Cola *cola); void insert (Cola *cola, int x); int remover(Cola *cola); int empty(Cola cola); main() { int x, opc=8, j=0; Cola cola; CrearCola(&cola); clrscr(); while(opc!=3) { printf("\t\t\tMENU PRINCIPAL\n\n\n"); printf("\t 1. Insertar\n"); printf("\t 2. Eliminar\n"); printf("\t 3. Salir\n"); scanf("%d", &opc); switch(opc) {
37 case 1: printf("Ingrese el numero a introducir:\n"); scanf("%d", &x); insert(&cola, x); ++j; break;
case 2: printf("%d fue eliminado de la cola\n", remover(&cola)); --j; getch(); break; } clrscr(); } getch(); return 0; } /*definicion de las funciones*/ void CrearCola(Cola *cola) { cola->frente=cola->final=NULL; } /*funcion que inserta el dato en la parte final de la cola*/ void insert (Cola *cola, int x) { Nodo *nuevo; nuevo=(Nodo*)malloc(sizeof(Nodo)); nuevo->elemento=x; nuevo->siguiente=NULL; if(empty(*cola)) { cola->frente=nuevo; } else Ing. Alberto Moreno Cueva
38 cola->final->siguiente=nuevo; cola->final=nuevo; }
/*elimina el elemento que esta aL frente de la cola*/ int remover (Cola *cola) { int temp=NULL; if(!empty(*cola)) { Nodo *nuevo; nuevo=cola->frente; temp=cola->frente->elemento; cola->frente=cola->frente->siguiente; free(nuevo); } else printf("ERROR, cola vacia, se puede eliminar\a\n"); return (temp); } int empty(Cola cola) { return (cola.frente==NULL); } Explicacin Como puede notarse, hemos implementado, de una manera muy sencilla, los algoritmos para ingresar y eliminar datos en una cola, note que hemos declarado dos estructuras para la cola, es decir que, una de ellas contiene la parte entera de los datos que vamos a guardar y el apuntador hacia el siguiente nodo; mientras que la otra estructura, cuenta con los apuntadores del frente y del final. Algo importante que hay que resaltar es el hecho que, en la zona de declaracin de variables, debemos declarar la varible de tipo Cola que es el parmetro que le pasaremos a las diferentes funciones; muchas veces se nos olvida hacer eso y por lo cual, intentamos, erradamente, mandarle la direccin del tipo de dato, es decir; que en vez de mandarle la direccin de la variable cola (&cola), le mandamos la direccin del TAD Cola (&Cola), lo cual no sera correcto. Ing. Alberto Moreno Cueva
39
Apartir de ello, creamos la cola, como lo explicamos, haciendo que cola->frente=cola>final=NULL; con lo cual nos aseguramos que la cola est vaca, y lista para agregar valores. Las dems funciones, slo son la implementacin rigurosa de los algoritmos planteados con anterioridad. No es importante aprenderse al pi de la letra, cada una de las funciones, ya sea para la pila o para las colas, si no que, es importante, aprenderse lo que hace cada funcin, tener presente el algoritmo e implementarlo segn convenga al problema que estamos resolviendo. Ejemplo 11.2 Cree una cola en C, que permita introducir y realizar un suceso por el usuario, el cual debe ser una arreglo unidimensional; sin embargo, la cola debe ser implementada dinmicamente. #include <stdio.h> #include <conio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> typedef struct datos elemento; struct datos { char suceso[81]; elemento *siguiente; }; void error (void) { printf("Error, insufuciente espacio en memoria\n\a"); exit(1); } elemento *nuevoelemento (void) { elemento *q=(elemento*)malloc(sizeof(elemento)); if(!q)error(); return q; } void menu (void); void introducir (elemento**, elemento**, char[]); Ing. Alberto Moreno Cueva
40 char *realizar (elemento**, elemento**); main() { elemento *principio, *final; char opcion, suceso[81]; principio=final=NULL; while(1){ do{ clrscr(); menu(); opcion=toupper(getche());
}while(opcion!='I' && opcion !='R' && opcion != 'S'); clrscr(); switch(opcion){ case 'I': printf("\nIntroduzca un suceso:\n"); gets(suceso); introducir(&principio, &final, suceso); break; case 'R': strcpy(suceso, realizar(&principio, &final)); if(*suceso) printf("\realizando el suceso %s", suceso); printf("Pulse una tecla para continuar:\n"); getch(); break; case 'S': exit(0); } } } void menu(void) { printf("\n\tIntroducir suceso"); printf("\n\t realizar el suceso"); Ing. Alberto Moreno Cueva
41 printf("\n\t salir"); printf("\n\t elija la opcion deseada (I, R, S)"); } /*A$adir a la cola */
void introducir (elemento **p, elemento **f, char suceso[]) { elemento *pc, *fc, *q; pc=*p; /*principio de la cola */ fc=*f; /*final de la cola */ q=nuevoelemento(); strcpy(q->suceso, suceso); q->siguiente=NULL; if(fc==NULL) pc=fc=q; else fc=fc->siguiente=q; *p=pc; *f=fc; } /*Recuperar dato de la cola */ char *realizar (elemento **p, elemento **f) { elemento *pc, *fc, *q; char *suceso; pc=*p; /*principio de la cola */ fc=*f; /*final de la cola*/ if(pc!=NULL) { q=pc; suceso=(char*)malloc(strlen(q->suceso)+1); strcpy(suceso, q->suceso); pc=pc->siguiente; Ing. Alberto Moreno Cueva
42 if(pc==NULL) fc=NULL; free(q); *p=pc; *f=fc; } else { printf("no hay sucesos\n\n\a"); suceso[0]='\0'; } return suceso; } Cuestionario
16. Por qu las Colas se consideran estructuras del tipo FIFO?____________________________________________________ ________________________________________________________ _________________________________ 17. Cules son las diferencias entre Pilas y Colas?____________________________________________________ ________________________________________________________ _________________ 18. En informtica, cules son las aplicaciones de las Colas?____________________________________________________ ________________________________________________________ _________________ 19. Mencione y explique las formas en las que podemos implementar las estructuras tipo Cola:_____________________________________________________ ________________________________________________________ ________________________________________________________ ___________________________ 20. Puede una cola, en algn momento comportarse como una Pila?Por qu? Mencione al menos un ejemplo:__________________________________________________ ________________________________________________________ ________________________________________________________ ________________________________________________________ _____________________________________ Ejercicios Ing. Alberto Moreno Cueva
43
21. Escribir un programa en C, que lea cierca cantidad de enteros y luego determine: Cul es el valor mayor, el valor menor y el promedio de todos los datos. 22. Disee un programa que sea capaz de leer dos colas y mediante un mensaje indicar si son iguales. Nota: los elementos constitutivos de las colas son caracteres. 23. En un supermercado, se tiene slo una caja habilitada para que los clientes puedan cancelar sus compras, se pide que, el sistema muestren la cantidad de productos comprados, el monto total de la venta. 24. Una tienda dispone de 10 repartidores, para las entregas a domicilio, genere un programa que simule: el despacho de cada repartidor, sabiendo que si la entrega se realiza despus de 30 minutos de realizada la orden, al cliente se le aplica un 30% sobre la compra. El programa debe mostrar: el total de entregas por repartidor, el monto de la ganancia, y las prdidas, en concepto de entregas tardas. 25. En la empresa "La Bodeguita", se lleva el control de los inventarios, por el mtodo PEPS, (Primeros en entrar, Primeros en Salir). Y se desea mecanizar este proceso, para ello, se deben ingresar los productos, y para registrar la venta, se necesitan los siguientes datos: Cdigo, correlativo de orden, descripcin, cantidad y precio. El sistema debe generar: el informe de todas la ventas, el artculo que ms se ha vendido, y el que menos, as como la ganancia de la empresa. Identifique, y corriga, los posibles errores que estn presentes en las siguientes funciones: int empty(Cola cola) { return (cola.frente); } Nodo *CrearNodo(int x) { aux=(Nodo*)malloc(sizeof(Cola)); aux->elemento=x; aux->siguiente=NULL; return aux; }
44
Es una coleccin de elementos dispuestos uno detrs del otro, en la que cada elemento se conecta al siguiente por un "Enlace" o "Puntero".
Como se observa en la imagen, los nodos de las listas al igual que las colas y pilas, est compuesta por una parte de informacin (que pude ser datos enteros, flotantes, caracteres, estructuras..) y el puntero que mantiene el enlace entre un nodo y otro. Existen varios tipos de Listas, pero para efectos de comprensin y sintetizacin, hablaremos de cutro tipos esenciales de listas: Tipos De Listas 26. Lista simplemente enlazada: Cada nodo, contiene un nico apuntador hacia el siguiente nodo, por lo cual hace de l una estructura muy eficiente, ya que el ltimo de la lista apunta hacia null, por ello, es fcil hacer recorridos directos.
27. Listas Doblemente enlazada: Esta lista se caracteriza por que sus nodos contienen dos punteros, uno hacia el nodo siguiente y otro hacia el nodo anterior.
28. Listas Circulares: Este tipo de lista, es slo una extencin de las lista simplemente enlazada, con la diferencia que el ltimo elemento se enlaza al primer elemento de la lista, lo cual permite el recorrido en forma de anillo
45
29. Lista Circular Doblemente enlazada: Quiz este tipo de lista, sea la ms compleja, ya que es la combinacin de las lista circular y las doblemente enlazadas, ya que es una lista doblemente enlazada donde el primer elemento se conecta con el ltimo y viceversa.
Ahora el lector comprende, el por que, si hablamos de estos tpicos al inicio, a lomejor, hubiera desistido de leer ste manual, y es que, al tener la experiencia de haber trabajado con estructuras como pilas y colas, antes de listas, hace que uno comprenda mucho mejor, los conceptos y algoritmos de ste tipo de estructuras. El TAD Lista En una lista podemos almacenar datos del mismo tipo, con la caracterstica que puede contener un nmero indeterminado de elementos y que, mantienen un orden explcito, por que cada elemento, se une a otro mediante un puntero, como ya se ha dicho anteriormente, los elementos constitutivos de las listas se denominan nodos. Las listas son estructuras de datos dinmicos, por tanto, pueden cambiar de tamao durante la ejecucin del programa, aumentando o disminuyendo el nmero de nodos. Un aspecto importante de las listas es que las inserciones, las podemos hacer por el frente, al final, en medio, despus de..., etc, etc, etc; es decir que, no existen reglamentos que nos restringan aadir datos a una lista, en la posicin que nosotros querramos. De igual manera, para las eliminaciones de nodos, podemos hacerlo como nosotros lo querramos, si embagargo, se acostumbra ingresando el campo de informacin o dato que se desea eliminar. Operaciones con las listas P: puntero a un nodo Ing. Alberto Moreno Cueva
46 L: puntero a la lista
ListaVacia(L): Iniciliza la lista L, como lista vaca empty(L): determina si la lista est vaca o no Insertar(L, x, p): Inserta al dato x, en un nuevo nodo de la lista L, despus del nodo apuntado por p eliminar(L, x): elimina, de la lista L, el nodo que contiene a x Nodo(p): Hace referencia la nodo que apunta p Info(p): hace referencia al info del nodo next(p): siguiente direccin si p no es NULL Info(next(p)): info del nodo que sigue a nodo (p) en la lista Se puede decir que, estas son las operaciones bsicas para una lista; sin embargo, como ya se ha insistido, eso depender del programador y de la complejidad del problema que se est resolviendo, adems del tipo de lista que se haya elegido. Para ello, acontinuacin hablaremos, por separado, de cada uno de los tipos de listas. Listas Simplemente Enlazadas
Una estructura como sta, requiere, que se tengan en cuenta, las operaciones bsicas que, se realizarn: Estructura del Nodo Por ejemplo, la podemos definir as: struct nodo{ int x; struct nodo *sig; }; typedef struct nodo *Lista; /* Sinnimo para el tipo de dato*/ Lista p; /* Aqu guardaremos la direccin del primer nodo */ p=getnodo(); Ing. Alberto Moreno Cueva
47 Funcin getnodo()
Esta funcin, se utiliza para pedirle memoria a la computadora, lo cual puede realizarse en las misma funcin de insertar, pero para tener un mekor orden, es mejor hacerlo por aparte. Por tanto, es evidente que, sta funcin lo que devuelve es una direccin de memoria. Lista getnodo() { Lista p; p=(Lista)malloc(sizeof(struct nodo)); return p; } Lo que devuelve, es la direccin del nuevo nodo, que se guard, en la variable p. Funcin Insertar despus del nodo apuntado por p Las inserciones en las Listas, no siempre se hacen al principio (pila) o al final (como las colas), las listas nos permiten insertar, entre dos nodos, por ejemplo en una lista, tenemos: B, Q, M, Y D. Y queremos insertar el elemento E, entre Q y M:
El algoritmo sera el siguiente: 30. Si P apunta a NULL, mostrar un mensaje de error y terminar la ejecucin. 31. sino, genere otro puntero, q, en el cual guarde la informacin. 32. luego, la parte siguiente del nuevo nodo, debe apuntar a al siguiente nodo, del apuntado por P. 33. p->siguiente, debe apuntar al nuevo nodo . el cdigo, sera as: void insafter (Lista p, char x) { Ing. Alberto Moreno Cueva
48 Lista q; If(p==NULL) Printf("Error, lista vaca\a\n"); Else { q=getnode(); q->x=x; q->sig=p->sig; p->sig=q; } } Funcin Borrar despus de...
sta funcin es muy similar a la funcin de eliminar de las pilas y colas, con la diferencia que debemos enlazar el nodo anterior con el siguiente nodo:
Algoritmo: 34. Crear un nodo auxiliar apuntado por q. 35. si p, apunta a nullo p->sig apunta a NULL, imprima mensaje de error 36. sino; q, en suparte de siguiente, debe tener la direccin a la que apuntaba, p->sig. 37. p->sig debe apuntar a q en su parte de siguiente. 38. Liberar de memoria el nodo apuntado por q. void delafter(Lista p, char *px) { Lista q; If(p==NULL || p->sig==NULL) Printf("ERROR, lista vaca\a\n");
49 Else { q->sig=p->sig; p->sig=q->sig; free(q); } } Funcin de Lista Vaca Int empty(Lista p) { int r; if(p==NULL) r=1; else r=0; return r; } /* Para limpiar la lista*/ void limpiar (Lista L) { L=NULL; }
Con sta funcin, lo que hacemos es inicializar la lista a NULL, por lo que se pierden los elementos que habamos guardado en los nodos. Pero Ojo, eso no significa que hayamos liberado memoria que ocuparon, los nodos, esa memoria ser liberada, cuando se deje de ejecutar el programa, o si hubisemos, utilizado la funcin free(), para cada nodo. Funcin Buscar sta funcin, nos devuelve, la direccin de memoria de un valor que deseamos buscar en la lista. Lista buscar(Lista frente, char x) { /* frente: puntero que indica la cabeza de una lista. X: carcter que deseamos buscar Ing. Alberto Moreno Cueva
50 */ Lista dir; For(dir=frente; dir!=NULL; dir=dir->sig) If(x==dir->x) Return dir; Return NULL; } Ejemplo 12.1
Se pide que, cree una agenda, donde pueda almacenar el nombre, telfono y correo electrnicode sus amigos; hacindo uso de una lista enlazada. Dicha agenda, debe permitirle: aadir un nuevo registro, eliminar y Mostrar la lista de todos los registros. #include <stdio.h> #include <conio.h> #include <stdlib.h> struct nodo{ int corre; char nom[80]; char tel[9]; char email[50]; struct nodo *sig; }; typedef struct nodo *Lista; Lista p, cabeza; Lista getnodo(); void insafter(Lista p, char nom[80], char tel[9], char email[50], int i); void eliminar (Lista p, int k); void imprimir(Lista p); main() { char nom[80], tel[9], email[50]; int k, opc=8, i=0; clrscr(); p=getnodo(); Ing. Alberto Moreno Cueva
51 cabeza=p; while(opc!=4) { printf("\t\t\nMENU PRINCIPAL\n\n\n"); printf("\t\t1. Registrar Nuevos Datos\n"); printf("\t\t2. Imprime todos los registros\n"); printf("\t\t3. Eliminar Datos\n"); printf("\t\t4.Salir\n"); scanf("%d", &opc); switch(opc) { case 1: printf("Ingrese el Nombre:"); scanf("%s", &nom); printf("Telefono:"); scanf("%s", &tel); printf("e-mail:"); scanf("%s", email); i++; insafter(&p, nom, tel, email, i); break; case 2: printf("Listado de todos los registros\n\n"); imprimir(&p); break;
case 3: printf("A quien desea eliminar?(ingrese el correlativo)\n"); scanf("%d", &k); eliminar(&p, k); break; } clrscr(); } return 0; } Ing. Alberto Moreno Cueva
void insafter(Lista p, char nom[80], char tel[9], char email[50], int i) { Lista q; if(p==NULL) printf("ERROR, lista vaca\n\a"); else { q=getnodo(); strcpy(q->nom, nom); strcpy(q->tel, tel); strcpy(q->email, email); q->corre=i; q->sig=p->sig; p->sig=q; p=p->sig; } } void imprimir(Lista p) { Lista dir; p=p->sig; for(dir=p; dir!=NULL; dir=dir->sig) { printf("\n\t***********************************\n"); Ing. Alberto Moreno Cueva
53 printf("\t correlativo: %d\n", dir->corre); printf("\t Nombre %s\n", dir->nom); printf("\t Telefono: %s\n", dir->tel); printf("\t e-mail: %s\n", dir->email);
printf("\n\t***********************************\n"); getch(); } } void eliminar(Lista p, int k) { Lista indice; cabeza=p; for(indice=cabeza; indice!=NULL; indice=indice->sig) {
if(indice->corre==k) { cabeza=cabeza->sig; printf("%s est hiciendo eliminado\n", indice->nom); getch(); if(p==NULL || p->sig==NULL) printf("ERROR, ya no hay m s datos\n"); else { cabeza->sig=indice->sig; free(indice); } } } } Listas Doblemente Enlazadas
54
Hata ahora, los recorridos que hemos realizado en las listas; han sido en sentido directo, pero existen muchos casos en los que es necesario acceder a los elementos de las estructuras en ambos sentidos (adelante y por detrs), de ah es donde se deriva la importancia de esta estructura. La declaracin de la estructura puede ser: typedef struct nodo{ int elemento; struct nodo *sig, *ant }Lista; /*Note la declaracin de dos punteros, uno hacia el nodo siguiente y el otro hacia el nodo anterio */ typedef Lista *tPosicion; typedef Lista *tLista Las operaciones bsicas, siguen siendo las mismas; aunque clara con sus variantes, por que recordemos que, en ste tipo de estructuras estamos manejando dos punteros, en un solo nodo. Insertar Para insertar en un lista, existen algunos mecanismos, casos, formas, etc. Por ejemplo: INSERTAR AL FRENTE DE LA LISTA 39. si lista est vaca 1. Crear un nuevo nodo 2. Asignar el valor a la parte dato del nodo 3. Hacer que nuevo nodo, en su parte de anterior apunte a NULL 4. Y en su parte de siguiente a la lista 5. El puntero del elemento de l frente de la lista, debe apuntar al nuevo nodo. 40. si la lista No est vaca Ing. Alberto Moreno Cueva
55 0. 1. 2. 3.
Agregar un nuevo nodo Asignar el valor a la parte dato del nodo Hacer que nuevo nodo, en su parte de anterior apunte a NULL El nuevo nodo en su parte de siguiente, debe apuntar al primer elemento de la lista 4. Si la Lista!=NULL, entonces Lista->ant=p 5. Luego el apuntador a la lista (Lista), debe apuntar al nuevo nodo. Void inserfrente (tPosicion Lista, int x) { tPosicion p; if(empty==1) { p=getnodo(); p->elemento=x; p->ant=NULL; p->sig=Lista; Lista=p; } else { p=getnodo(); p->elemento=x; p->ant=NULL; p->sig=Lista; if(Lista!=NULL) Lista->ante=p; Lista=p; } } INSERTAR AL FINAL DE LA LISTA Para hacer este tipo de operacin, necesitamos un puntero (q), que apunte al ltimo elemento de la lista. El algoritmo sera, entonces, el siguiente: 41. Crear el nuevo nodo Ing. Alberto Moreno Cueva
56 42. hacer que p->elemento, sea igual al valor 43. hacemos que p->ant apunte al ultimo nodo 44. p->sig ser igual a lo que tenga q->sig 45. q->sig debe apuntar al nuevo nodo void inserfinal (tPosicion q, int valor) { tPosicion p; p=getnodo(); p->elemento=valor; p->ant=q; p->sig=q->sig; q->sig=p; } Funcin getnodo() tLista getnodo() { tLista nuevo; nuevo=(tLista)malloc(sizeof(Lista)); if(nuevo==NULL) printf("Memoria insuficiente\a\n"); nuevo->sig=nuevo->ant=NULL; return nuevo; } Funcin Eliminar
Esta funcin, se encarga de borrar, el nodo apuntado por "p", encontrado con la funcin posicin y considere eliminacin al inicio, en medio y al final. Algoritmo: 46. Busque el nodo que contiene el dato que desea eliminar , teniendo el cuidado de guardar la direccin del nodo a eliminar y la direccin del nodo anterior a ste. 47. la parte siguiente del nodo anterior debe apuntar al puntero sifguiente del nodo a eliminar. 48. la parte anterior del nodo siguiente a eliminar debe apuntar a la parte a lo que apuntaba la parte anterior del nodo a eliminar. 49. en caso de que el nodo a eliminar sea el primero en la lista, se modifica la cabeza para que tenga la direccin del nodo siguiente. 50. finalmente liberamos la memoria ocupada. Ing. Alberto Moreno Cueva
57 Void eliminar (tPosicion Lista, int x) { tPosicion actual; int encontrado=0; actual=Lista; /*empezamos a buscar el nodo*/ while((actual!=NULL) && (!econtrado)) { encontrado=(actual->elemento==x); if(!encontrado) actual=actual->sig; }
/*Enlazamos el nodo anterior con el diguiente nodo*/ if(actual!=NULL) { if(actual==Lista) { lista=actual->sig; if(actual->sig!=NULL) actual->sig->ant=NULL; } else if(actual->sig!=NULL) /*No es el ultimo nodo*/ { actual->ant->sig=actual->sig; actual->sig->ant=actual->ant; } else actual->ant->sig=NULL; free(actual); } } Ejemplo 12.2 Ing. Alberto Moreno Cueva
58
/******************************************************************* * LISTA.C * * Objetivo del programa: Realizar un programa que de de altas, * * busque y liste una lista de tipo estructura dinamica * * doblenmente ligada * * Versin: 2.1 * * Autor: JOSE LUIS SANCHEZ FERRUSCA * * Fecha: 6/04/2005 * *******************************************************************
/********************* Inclusin de libreras **********************/ #include <stdio.h> #include <malloc.h> /********************* Prototipos **********************************/ void altas(void); void busqueda(void); void listado(void); void baja(void); /********************* Variables Globales **************************/ struct lista *nuevo,*primero,*recorre, *anterior; int i,op,num,bus,opcion; typedef struct lista; struct lista /* Crea una lista de tipo struct con dos campos, numero (entero) y sig (apuntador de tipo struct lista)*/ { int numero; struct lista *sig, *ant; }; void main() { op=1; nuevo=NULL; /* El apuntador esta vacio */ Ing. Alberto Moreno Cueva
printf ("\n\n \t *********************************\n"); printf (" \t *** ***\n"); printf (" \t *** PROGRAMA DE ESTRUCTURAS ***\n"); printf (" \t *** ***\n"); printf (" \t *********************************\n"); printf (" \n\n\n \t 1.- ALTAS \n \t 2.- BUSQUEDA \n \t 3.- LISTADO \n\t 4.- Baja \n\t 5.- SALIR \n\n"); printf (" SELECCIONE UNA OPCION DEL MENU \n"); scanf ("%d",&opcion); switch(opcion) { case 1: altas(); break; /*case 2: busqueda(); break;*/ case 3: listado(); break; case 4: baja(); break; } }while (opcion!=5); scanf ("\n"); } /********************* Declaracion de Funciones ********************/ /******************************************************************** * Funcin:Alta * * Argumentos: void - No recibe argumentos * Ing. Alberto Moreno Cueva
* Comentario: Esta funcin va a dar de alta los datos en la lista * ** ********************************************************************/ void altas(void) { int flag; nuevo=primero; printf ("\n INGRESE EL NUMERO PARA DARLO DE ALTA\n "); scanf ("%d",&num); nuevo=malloc(sizeof(struct lista)); /* Busca un espacio de memoria del tamao de struct lista */ nuevo->numero=num; /* Vuevo en su campo numero asignale el valor de num */ nuevo->sig=NULL; /* Ya no hay ms espacios de memoria para ligar */ nuevo->ant=NULL; recorre=primero; if (primero==NULL) { primero=nuevo; recorre=nuevo; } else { do { if (primero==recorre) { if (nuevo->numero<primero->numero) { primero=nuevo; primero->sig=recorre; Ing. Alberto Moreno Cueva
61 recorre->ant=nuevo; } else { primero->sig=recorre; recorre->ant=primero; } } else if (recorre->sig!=NULL) { if (nuevo->numero<recorre->numero) { anterior=recorre->ant; nuevo->ant=anterior; nuevo->sig=recorre; anterior->sig=nuevo; recorre->ant=nuevo; } } else { recorre->sig=nuevo; nuevo->ant=recorre; } }while(recorre!=NULL); } }
/******************************************************************** * Funcin: Busqueda * * Argumentos: void - No recibe argumentos * *-** * Valor de Retorno: Void -> No regresa valores * Ing. Alberto Moreno Cueva
62
* Comentario: Esta funcin va a hacer una busqueda en la lista * ** ********************************************************************/ void busqueda() { int bus; recorre=primero; printf ("\nINGRESE EL NUMERO A BUSCAR\n"); scanf ("%d",&bus); do { if (bus==recorre->numero) /* El dato a buscar se encuentra en recorre en su campo numero ?*/ { printf ("\n SE HA ENCONTRADO EL NUMERO %d\n ",bus); recorre=recorre->sig; } else recorre=recorre->sig; }while (recorre!=NULL); } /******************************************************************** * Funcin: listado * * Argumentos: void - No recibe argumentos * *-** * Valor de Retorno: Void -> No regresa valores * * Comentario: Esta funcin va a imprimir la lista * ** ********************************************************************/ void listado() { recorre=primero; Ing. Alberto Moreno Cueva
/******************************************************************** * Funcin:Baja * * Argumentos: void - No recibe argumentos * *-** * Valor de Retorno: Void -> No regresa valores * * Comentario: Esta funcin va a dar de baja los datos en la lista * ** ********************************************************************/ void baja() { recorre=primero; anterior=primero; printf ("\nINGRESE EL NUMERO A BUSCAR\n"); scanf ("%d",&bus); do { if (bus==recorre->numero) /* El dato a buscar se encuentra en recorre en su campo numero ?*/ { if (recorre==nuevo) { nuevo=nuevo->ant; free(recorre); nuevo->sig=NULL; } else if (primero!=recorre) /* Estan primero y recorre en la misma posicin? */ Ing. Alberto Moreno Cueva
64 { anterior->sig=recorre->sig; free(recorre); recorre=anterior->sig; recorre->ant=anterior; else { anterior->sig=recorre->sig; recorre=anterior->sig; free(primero); primero=recorre; anterior=primero; } } else if (recorre==primero) recorre=recorre->sig; else { recorre=recorre->sig; anterior=anterior->sig; } }while (recorre!=NULL); }
NOTA: Este cdigo ha sido elaborado por JOSE LUIS SANCHEZ FERRUSCA, aunque, por razones de didctica, he hecho algunas modificaciones. Listas Circulares
65
Se puede afirmar que, las listas circulares, son un caso especial de las listas simples, con la variante que el ltimo nodo, en su parte de siguiente, apunta al primer nodo de la lista. La parte de dato, de la lista circular, puede estar compuesta de enteros, punto flotante, caracteres, arreglos o estructuras.
Declaracin de la estructura Typedef struct elemento{ Int dato; Struct nodo*sig; }nodo; typedef nodo* lc; lc *Lista=NULL; Funcin getnodo() lc getnodo() { lc nuevo; nuevo=(lc)malloc(sizeof(nodo)); nuevo->dato=x; nuevo->sig=nuevo; /* para que sea circular debe apuntar a s mismo*/ return nuevo; } Funcin Ingresar Ing. Alberto Moreno Cueva
66 Void insertar (lc *Lista, int x) { lc p; p=getnodo(x); if(*Lista==NULL) /*si hay elementos en la lista*/ { p->sig=(*Lista)->sig; (*Lista)->sig=p; } *Lista=p; } Funcin Eliminar
ste algoritmo es muy parecido al de una lista simple, ya que sta estructura, como ya se ha dicho, es un caso especial de la lista lineal, sin embargo, existen unas pequeas consideraciones a tener en cuenta. Algotitmo 51. Se debe buscar el nodo que contiene el dato que desea eliminar 52. luego se debe enlazar el nodo anterior con el siguiente 53. si el nodo a eliminar est apuntado por "Lista", es decir el puntero de acceso, se modifica "Lista" para que contenga la direccin del nodo anterior a ste. 54. finalmente se libera el nodo de la memoria void eliminar (lc *Lista, int x) { lc *actual; int encontrado=0; if((*Lista)==NULL) printf("No hay elementos en la lista\n"); else { actual=*Lista; /*empezamos a buscar*/ while((actual->sig!=Lista) && (!encontrado)) { encontrado=(actual->sig->dato==x); Ing. Alberto Moreno Cueva
/*enlazamos el nodo abterior con el nodo siguiente*/ if(encontrado) { lc=p; p=actual->sig; /*nodo a eliminar*/ if(*Lista==(*Lista)->sig) *Lista=NULL; else { if(p==*Lista) *Lista=actual; actual->sig=p->sig; } free(p); } } } Ejemplo 12.3 Las reglas de la divisibilidad indican que, si un nmero termina en cero o cifra par, es divisible por dos; y si la suma de sus elementos es tres o mltiplo de tres, entonces, ese nmero es divisible por tres. Adems que, si un nero es divisible por dos y por tres al mismo tiempo, entonces es divisible por seis. (ejemplo 12. Termina en cifra par, 2+1=3, es divisible por 2 y por tres, entonces tambin es divisible por 6), disee un programa que, que almacene en una lista circular, y muestre por cual de esos tres nmeros (2 , 3 y 6) es divisible. /*Ejemplo de listas *.C*/ #include <stdio.h> #include <conio.h> #include <ctype.h> typedef struct elemento{ int x; Ing. Alberto Moreno Cueva
68 struct elemento *sig; }nodo; typedef nodo* lc; lc *Lista; int k=0; void inser (lc *Lista, int x); void divi(lc* Lista); main() { int num[80], pos=0, i=0; clrscr(); printf("\t\t\tINGRESE EL NUMERO:\n\n\n"); while((num[pos++]=getchar())!='\n'); num[--pos]='\0'; for(i=0; i<pos; i++) inser(Lista, num[i]); divi(Lista); getch(); return 0; } void inser(lc *Lista, int x) { lc nuevo; nuevo=(lc)malloc(sizeof(nodo)); nuevo->x=x; nuevo->sig=nuevo; if(*Lista!=NULL) { nuevo->sig=(*Lista)->sig; (*Lista)->sig=nuevo; } *Lista=nuevo;
69 k++; } void divi (lc *Lista) { int div2=0, div3=0, sum=0, i=1; lc aux; aux=(*Lista)->sig;
while(i<=k) { sum=sum+aux->x; aux=aux->sig; i++; } if(sum%3==0) { div3=1; printf("El numero es divisible entre tres\n"); } aux=(*Lista); if(aux->x%2==0) { div2=1; printf("El numero es divisible entre Dos\n"); } if(div2==1 && div3==1) printf("Tambien es divisible entre 6\n"); getch(); } Explicacin Lo primero que hacemos, es almacenar el nmero en un arreglo, auxiliar, ya que cada elemento del nmero lo guardamos en una casilla del arreglo, luego, vamos pasando cada nmero como parmetro a la funcin insert(), ya que en ella creamos los nodos y Ing. Alberto Moreno Cueva
70
en s, la lista circular. Una vez que, hemos llenado la lista, pasamos el puntero de acceso a la funcin divi(), en la cual determinamos los nemeros por los cuales es divisible. Listas Circulares Doblemente Enlazadas
ste tipo de listas, es una combinacin de las listar cicular y la lista doblemente enlazada, puesto que cada nodo est conectado con el siguiente nodo y el anterior a l, adems que el primer nodo est conectado al ltimo, y el ltimo al primero. Es por esa razn que, particularmente consideto que, sta estructura es una de las ms complejas de manejar, por las consideraciones que debemos tener. Declaracin de la estructura Typedef struct celda{ Int elemento; Struct nodo*sig, ant; }tipocelda; typedef tipocelda *tPosicion; typedef tipocelda* tLista; Funcin getnodo() tLista getnodo() { tLista L; L=(tLista)malloc(sizeof(tipocelda)); If(L==NULL) Printf("ERROR: Memoria Insuficiente\a\n"); L->sig=L->ant=L; Return L; } Funcin Insertar Algoritmo: 55. Crear el nuevo nodo 56. Guardar el dato en el nuevo nodo Ing. Alberto Moreno Cueva
71
57. Hacer que el nuevo nodo, en su parte de siguiente apunte al nodo anterior (que est siendo apuntado por p) 58. Luego copiar en nuevo->ant, lo que hay en p->ant 59. hacer que en la parte de siguiente del nodo anterior apuntado por p, contenga la direccin del nuevo nodo 60. hacer que p->ant apunte anuevo 61. guardar la direccin de nuevo en p void insertar (int x, tPosicion p) { tPosicion nuevo; nuevo=(tPosicion)malloc(sizeof(tipocelda)); if(nuevo==NULL) printf("ERROR: memoria insuficiente\a\n"); nuevo->elemento=x; nuevo->sig=p; nuevo->ant=p->ant; p->ant->sig=nuevo; p->ant=nuevo; p=nuevo; } Funcin Buscar Esta funcin recibe como argumento un dato a buscar, dentro de la lista y devuelve el nodo que contenga dicho dato. tPosicion buscar (int x, tLista L) { tPosicion p; int ban=0; p=L->sig; while((p!=L) && (!ban)) if(p->elemento==x) ban=1; else p=p->sig; return p; Ing. Alberto Moreno Cueva
72 } Ejemplo 12.4
Disee una lista circular doblemente enlazada, que gaurde enteros, y luego permita determinar cuantas veces se encuentra un nmero ingresado por el usuario. #include <stdio.h> #include <conio.h> #include <string.h> /*Version Circular doblememente enlazada*/ typedef struct tipoNodo{ int x; struct tipoNodo *adelante; struct tipoNodo *atras; }Nodo; /*Declaracion de los sinonimos para referirnos al tipo de dato*/ typedef Nodo *tLista; typedef Nodo *tPosicion; int cont=0; /*Declaracin de las funciones que utilizaremos*/ void insertarPrim (tLista cabeza, int entrada); tLista CrearNodo(); void ImprimeLista(Nodo *ptr); int buscar(int busca, Nodo *cabeza, Nodo *ptr); main() { /*inicio del programa principal*/ Nodo *ptr; tPosicion cabeza; int entrada, opc, busca; char ban; /*cabeza contiene la direccin del primer nodo creado*/ cabeza=CrearNodo(); ban='S'; Ing. Alberto Moreno Cueva
73 clrscr(); printf("\n\n\n\n");
printf("\n\t "); printf("\n\t "); printf("\n\t PROGRAMA QUE CALCULA LOS VALORES REPETIDOS EN UNA LISTA "); printf("\n\t DOBLEMENTE ENLAZADA "); printf("\n\t "); printf("\n\t "); while(ban=='S' || ban=='s') { printf("\n\nIngrese un elemento para la lista:\n"); scanf("%d", &entrada); cont++; /*le enviamos a la funcion de insertar, le enviamos la direccin del primer nodo y el valor que vamos a introducir*/ insertarPrim(cabeza, entrada); printf("Desea Introducir un nuevo elemento a la lista? (S/N)\n"); ban=getch(); } printf("Los Valores Guardados en la Lista son:\n"); /*la funcion de imprimir, recibe un puntero hacia el primer nodo para iniciar con la impresion*/ clrscr(); ImprimeLista(cabeza); getch(); clrscr(); printf("\n\t\tQue desea Hacer?\n"); printf("\t\t1.Buscar un valor en la lista\n"); printf("\t\t2.Salir\n"); scanf("%d", &opc); Ing. Alberto Moreno Cueva
printf("Ingrese el valor que desea buscar en la lista:\n"); scanf("%d", &busca); printf("El valor %d se encuentra %d veces en la lista\n\n", busca,buscar(busca,cabeza, cabeza)); break; case 2:exit(1); default:printf("Error, el comando no es v lido\n"); break; } getch(); return 0; } /*definicin de las funciones*/ void insertarPrim(tPosicion cabeza, int entrada) { tPosicion nuevo; /*creamos un nuevo nodo y le asignamos la direccion de memoria*/ nuevo=(tPosicion)malloc(sizeof(Nodo)); if(nuevo==NULL) printf("ERROR\n"); nuevo->x=entrada; /*la parte de adelante del nuevo nodo, apunta al primer nodo*/ nuevo->adelante=cabeza; nuevo->atras=cabeza->atras; cabeza->atras->adelante=nuevo; cabeza->atras=nuevo; } tLista CrearNodo() { Ing. Alberto Moreno Cueva
75
/*creamos un nuevo nodo, el cual sera la "cabeza" de la lista*/ tLista L; L=(tLista)malloc(sizeof(Nodo)); if(L==NULL); printf("Error, memoria Insuciente\n"); L->adelante=L->atras=L; return L; } void ImprimeLista(Nodo *ptr) { Nodo *p; int k=0; if(ptr!=NULL) { printf("Lista de Nmeros Guardados:\n"); p=ptr->adelante; do{ k++; if(k<=cont) printf("\t\t\t* %d *\n", p->x); p=p->adelante; }while(p!=ptr->adelante); } else { printf("No Hay elementos en la Lista\n"); } } int buscar(int busca, Nodo *cabeza, Nodo *ptr) { int k=0; if(ptr!=NULL) Ing. Alberto Moreno Cueva
76 { cabeza=ptr->adelante; do{ if(cabeza->x==busca) k++; cabeza=cabeza->adelante; }while(cabeza!=ptr->adelante); } else { printf("No Hay elementos en la Lista\n"); } return k; } Cuestionario
62. Qu son y para que sirven las listas?____________________________________________________ ________________________________________________________ ________________________________________________________ ___________________ 63. Cul es la diferencia entre una lista circular y una doblemente enlazada?_________________________________________________ ________________________________________________________ ________________________________________________________ _________________ 64. Una lista, Puede comportarse como una cola?_____________________________________________________ ________________________________________________________ ________________________________________________________ __________________ 65. Por qu se afirma que una lista circular, no tiene ni primer y ltimo elemento?_________________________________________________ ________________________________________________________ ________________________________________________________ _________________ 66. La funcin getnodo() e insertar(), se diferencian en:______________________________________________________ ________________________________________________________ ____________
77 Ejercicios
67. En una lista simple, que almacena enteros, mostrar cual es el dato mayor y cual es el dato menor. 68. Disee un registro para n alumnos de una Universidad, con sus respectivas notas de Programacion II y Estructuras de Datos, dichos datos, se deben guardar en una Lista lineal. Se sabe que, en sta universidad, existe la poltica que si, un alumno ha reprodado estas dos materias, es dado de baja en la universidad. (Nota mnima 6.00) 69. Se desea guardar cierta cantidad de caracteres en una lista doble, y luego imprimir los caracteres de izquierda a derecha y viceversa. 70. Disee un programa que, le permita al usuario, almacenar en una lista doblemete enlazada, los registros de las personas que han adquirido un seguro de vida, adems que permita eliminar registros, y adicionar nuevos datos. 71. En una lista circular se desean guardar, cadenas de caracteres, y luego imprimir la cadena de mayor longitud. 72. Disee un programa queopere con nmeros complejos (tienen parte real e imaginaria), y permita, sumarlos, restarlos, multiplicarlos, y determinar la magnitud de cada uno de ellos. 73. Escribir un programa en C, que apartir de una lista doble circular, ordene alfabticamente, los caracteres contenidos en ella y luego los imprima. 74. Disee un programa en C, que contenga una lista circular, cuyos elementos sean enteros largos, luego imprimir todos los elementos y la suma de ellos. 75. El aeropuerto internacional de El Salvador, desea controlar el flujo de pasajeros, y de aerolneas que circulan por l. Disee un programa que de soporte a las salidas y entradas de los aviones, mediante una lista doblemente enlazada cuya informacin sera la siguiente: Destino, compaa, hora de salida y pasajeros. Luego, y apartir de ese ltimo dato, es que se eliminarn los datos de la lista de pasajeros. 76. Un punto en el espacio, est compuesto por coordenadas x, y, z. Disee un programa que apartir de una lista circular doble, determine la distancia entre el primer punto y el ltimo. (Nota: D2=(x1-x2)2+(y1-y2)2+(z1-z2)2).
Nota Final
Del lenguaje C, hace falta por hablar mucho, con estas insignificantes pginas, no he agotado el estudio de ste interesante y til, lenguaje de programacin. Sin embargo, yo concluyo hasta aqu, por que algunas cosas ya no me compete, hablarlas a m. No me queda mas que, desearte suerte, en sta etapa como programador. Y nimo!!! Sigue siempre adelante.... Recuerda que puedes hacer cualquier comentario, sugerencia, observacin, etc, a mi correo electrnico: memeboi27[arroba]hotmail.com
Bibliografa
78
-"Aprenda Lenguaje ANSI C Como si estuviera en Primero". De jaln de la Fuente, Javier Garca. Rodriguez Garrido, Jos Ignacio. Escuela Superior de Ingenieros Industriales, Universidad de Navarra. 1998 -"Curso de C". Urrutia, Gorka. http://www.elrincondelc.com -"Introduccin al Lenguaje de Programacin C/C++". Pacho, Sergio. -"Ejercicios de Practicas de C". Ledesma Muoz, Fernando. http://ledesma.f2o.org -"Curso de armado y reparacin de PC en 10 clases. Primera Parte". Boselli, Gustavo. gb100m[arroba]yahoo.com -"Tutorial sobre apuntadores y arreglos en C". Jensen, Ted. Ao 2000. http://www. netcom.com/~tjensen/ptr/cpoint.htm -"Algoritmos y Estructuras de Datos, una perspectiva en C". Joyanes Aguilar, Luis. Zahonero Martnez, Ignacio. Mc Graw Hill, ao 2004. Madrid, Espaa. -"Estructuras dinmicas de datos algoritmos, acceso, propiedades, ejemplos". Pozo, Salvador. Julio de 2001. http://www.conclase.net/c/edd/ -"Guines de Clase: Introduccin a la Informtica, programacin I y Programacin II". Gonzlez, Csar. Castillo, Milagro. Vzquez, Rodrigo, (Respectivamente). Universidad de El Salvador, Facultad de Ingeniera y Arquitectura, Escuela de Sistemas Informticos.