Trabajo de Pilas[1]

22
Álvarez, María Fajardo, Daniel Sendín, Alba 1

description

Estructuras de Datos

Transcript of Trabajo de Pilas[1]

  • lvarez, Mara Fajardo, Daniel Sendn, Alba

    1

  • INCIDE: Definicin de Pilas

    Concepto de Pila.3 Operaciones fundamentales3 Otras operaciones...4

    Utilidades de las Pilas

    Llamadas a subprogramas..5 Paso de programas recursivos a iterativos..6 Equilibrado de smbolos.7 Tratamiento de expresiones aritmticas.9

    Transformacin de notacin infija a postfija.10 Evaluacin de la notacin postfija.12

    Implementacin de las Pilas. Implementacin mediante vectores14

    Implementacin mediante listas enlazadas.16 Programa Demo. Referencias.

    2

  • DESCRIPCIN DE PILA

    DEFINICION: Una pila (stack) es un tipo fundamental de lista (Tipo de dato abstracto fundamental) en la que todas las inserciones y supresiones de elementos solo se pueden realizar desde una nica posicin, el extremo, la cima o tope de la pila (TOP).

    El modelo intuitivo de una pila es precisamente una pila de monedas

    puestas sobre una mesa, o de cajas sobre el piso, o de bandejas en una estantera, situaciones todas en las que solo es conveniente quitar o agregar un objeto del extremo superior de la pila, al que se denominara en lo sucesivo tope.

    Dado que las operaciones de aadir solo se realizan por el extremo superior de la pila, los elementos solo se pueden eliminar en orden inverso a como han sido insertados en la pila. Por esta razn a las pilas se las conoce como listas LIFO (last input, first output), ya que el ltimo elemento en entrar ser el primero en salir.

    Las tres operaciones ms importantes un una pila son:

    PUSH: Meter, poner, apilar. Operacin que inserta un elemento en la sima de la pila.

    POP: Sacar, quitar, desapilar. Operacin que elimina el elemento que

    ocupaba la posicin cima. El elemento que haba sido insertado inmediatamente antes que el eliminado pasara a ha ser ahora la nueva posicin cima.

    TOPE: Operacin que devuelve el elemento que ocupa en ese instante la

    posicin cima pero sin extraerlo.

    A aparte de estas operaciones, que son las fundamentales, cuando queremos trabajar con pilas tendremos que utilizar ms operaciones, sobre todo necesarias cuando se trata de pilas usando listas enlazadas. Dichas operaciones son las siguientes:

    3

  • CREAR: Lo que hace esta operacin es inicializar una pila como pila vaca.

    BORRAR: Esta operacin lo que hace es convertir una pila P en una pila

    vaca.

    VACIA?: Devuelve verdadero si la pila no tiene elementos, y falso en caso contrario. No podremos hacer POP ya que se producira un desbordamiento negativo (underflow) al no tienen ningn elemento que eliminar.

    LLENA?: Ocurre lo mismo que con el caso VACIA? Solo que en este

    caso te devuelve verdadero si la pila esta llena y no podemos insertar ningn elemento ms a no ser que eliminemos alguno antes. Si tratsemos de insertar un elemento ms se producir un error a causa de un desbordamiento (overflow).

    Las pilas pueden representarse grficamente de varias maneras, entre las

    cuales destacan las siguientes.

    A partir de ahora, para seguir dando propiedades de las pilas y sus operaciones, tendremos que distinguir entre pilas definidas mediante vectores o mediante listas enlazadas, pero eso lo veremos ms adelante.

    UTILIDADES DE LAS PILAS

    Las pilas, adems de simplificar algoritmos complejos y permitir acceso rpido a otros programas, son utilizadas ampliamente para solucionar una gran variedad de problemas. Se utilizan en compiladores, sistemas operativos y en programas de implementacin. Veamos alguna aplicacin interesante de las pilas.

    Llamadas a subprogramas:

    4

  • Cuando dentro del programa principal tienes subrutinas o funciones a las

    que tienes que llamar, el programa principal tiene que recordar el lugar donde hizo la llamada y guardar el estado en el que se encontraba el programa en ese momento, con sus variables y valores previos a la llamada para poder retomar cuando el subprograma haya finalizado, ya que de otra forma el procedimiento sobrescribir en ellas. Todo ellos se guarda en una pila.

    Cuando, adems, se trata de programas con llamadas recursivas es de

    gran utilidad, ya que al hacer tantas paradas unas dentro de otras, si no se controla el tamao de la pila, se puede producir un desbordamiento.

    Veamos con ms claridad como funciona una pila para las llamadas a los

    subprogramas mediante un ejemplo.

    Tenemos el programa principal con los subprogramas A, B, C, donde el programa principal llama al subprograma A, y este, una vez ejecutndose, llama al subprograma B. El programa B tiene una llamada al subprograma C, entonces el PPABC. B no continua la ejecucin hasta que termina el subprograma C, y A no termina la suya hasta que no termina el B. Lo mismo ocurre con el programa principal. Luego:

    Esta operacin se consigue mediante una pila que en la que se guardan las direcciones de retorno.

    5

  • Cuando un programa o subprograma llama a otro, la direccin se

    introduce en la pila, por supuesto en la cima, y cuando un subprograma termina, vuelve a la direccin siguiente a la instruccin en la que se llamo, y de este modo, la pila se va vaciando y el puntero de la pila queda libre siempre apuntando a la siguiente direccin de retorno, de la siguiente forma:

    Paso de programas recursivos a iterativos.

    La recursin es un mtodo muy utilizado y una herramienta muy valiosa

    y poderosa a la hora de crear algoritmos claros y concisos que se utiliza para problemas que se resuelven resolviendo ese mismo problema pero en una dimensin ms pequea una y otra vez hasta llegar al problema base y luego dar marcha atrs, es decir, problemas que se definen en trminos de s mismos, que se repiten una y otra vez a ellos mismos para calcular una solucin. Pero el uso de la recursin es costoso en trminos de consumo de memoria. Si adems tenemos en cuenta que muchos lenguajes de programacin no cuentan con la facilidad de implementar programas recursivos, seria bueno encontrar un procedimiento alternativo que permita simularlo.

    Pero para simular un programa recursivo es necesario la utilizacin de

    pilas, ya que se esta llamando continuamente a subprogramas que a la vez vuelven a llamarse a si mismo. Cada vez que un subprograma hace una llamada, hay que guardar la direccin a la cual debe regresar cuando acabe de ejecutar el subprograma llamado y las variables y valores actuales antes de la llamada, pues de lo contrario estos valores podran ser sobrescritos.

    Cada coleccin de variables que se guarda antes de hacer una llamada se

    llama registro de activacin.

    Veamos como se utiliza esta eliminacin de la recursin mediante un ejemplo sencillo hecho en clase. El clculo del nmero factorial.

    El programa principal es de la forma:

    main ( ) {

    6

  • int n, factorial (); scanf (%d, &n); printf (Este es el factorial de %d: %d, n, factorial(n)); }

    int factorial (int n) { /*funcin recursiva que calcula el factorial*/ if (n == 1 or n == 0) return 1; /*caso base*/ else return (n*factorial (n-1)); }

    Cuando le damos un valor a n, al llamar al subprograma por primera vez tendremos que guardar esa n en alguna parte. Este valor lo guardo en la pila, que para este tipo de informacin es una estructura muy adecuada, ya que sta no va a poder ser utilizada hasta que termine la llamada al subprograma. La forma de guardar los datos es la siguiente:

    A medida que se van realizando llamadas, se van guardando los valores

    de n (guardados en los registros de activacin) en la pila; as, los valores correspondientes a llamadas ms externas estarn ms abajo en la pila, y los correspondientes a llamadas ms internas, ms arriba.

    Una vez que haya concluido este proceso, lo que hace el programa es

    sacar el tope de la pila, sacar el nuevo tope y multiplicarlos, y luego ir sacando iterativamente los topes y multiplicndoles por el producto anterior.

    Equilibrado de smbolos.

    Tambin pueden utilizarse las pilas para revisar programas en busca de errores, como por ejemplo en el caso de los smbolos.

    En cada compilador se utilizan las pilas para comprobar si se han

    producido errores, para que cada parntesis, llave o corchete de apertura tenga su correspondiente cierre. Es decir, que si un programa presenta ms smbolos de apertura que de clausura, el programa tendra errores y no seria vlido.

    Tambin tenemos que tener en cuenta el orden en el que estn dichos

    smbolos, porque puede que aunque tenga los mismos smbolos de apertura que de clausura, tenga errores, ya que dichos smbolos no estn colocados correctamente. Por ejemplo, si nos encontramos en este caso: ([{])} el programa dara un error, ya que la segunda llave no esta colocado en su lugar y trastocara toda la estructura interna del programa.

    7

  • Para ello puede crearse un programa que dado un fichero en el lenguaje del compilador correspondiente nos diga si hay algn tipo de error en la anidacion de los smbolos mediante la utilizacin de pilas. El programa funcionaria de la siguiente forma:

    Creamos un pila vaca de caracteres y se abre el fichero en el que se

    encuentra el programa. Se leen uno a uno los caracteres, pero solo nos quedamos con aquellos que sean parntesis, corchetes o llaves. Cuando nos encontremos con un carcter de apertura lo metemos en la pila y seguimos leyendo caracteres hasta que lleguemos al siguiente. Mientras sea un carcter de apertura, se mete en la pila.

    Cuando nos encontremos con un carcter de clausura, lo que tenemos que hacer es mirar a la cima de la pila. Si lo que nos encontramos es el smbolo de apertura correspondiente al smbolo que estamos mirando, lo sacamos de la pila, en caso contrario, se mete en la pila. Y as sucesivamente hasta que hayamos ledo todo el fichero.

    Una vez finalizada la lectura del fichero sabremos si estn bien anidados, y por lo tanto si el programa es aparentemente correcto si y solo si la pila esta vaca, ya que cada smbolo que hemos abierto, lo habremos cerrado correctamente.

    Pero este programa tiene una pega, ya que si el fichero que estamos

    leyendo con el contenido del programa tiene comentarios en los que escribe smbolos no anidados o errneamente colocados, no afectara al programa que queremos revisar ya que es un comentario, pero si que afectara al nuestro, ya que la pila no quedara vaca. Es decir, que un trozo de cdigo bien hecho puede interpretarse como un trozo con errores. Algn ejemplo:

    /*Con un comentario as ( [ ) ] el programa nos dara un error*/

    Printf (con una expresin as tambin nos dara un error %c:, })

    Por lo tanto si queremos utilizar este programa para depurar errores un nuestro programa, tendremos que asegurarnos previamente de que los comentarios que hemos puesto son correctos y que no pueden inducir a error al

    8

  • igual que los smbolos que utilizamos como escritura tampoco nos van a dar ningn problema.

    Para un programa como este emplearemos listas enlazadas, pues no

    sabemos cual es la longitud del fichero y tampoco cual es la cantidad de smbolos que este contiene, por lo que un vector podra quedarse corto o pasarse de largo.

    Tratamiento de expresiones aritmticas:

    Una expresin aritmtica esta formada por operandos y operadores, como por ejemplo (a+b) - c*d. En este caso +, -, * son los operadores y a, b, c, d los operandos. Los operandos pueden ser valores, variables o incluso otras expresiones, mientras que los operadores son los conocidos de las expresiones matemticas, por lo que el resultado puede ser de tipo numrico o variables.

    La forma habitual que tenemos de escribir las operaciones matemticas

    es poniendo el operador entre dos operando, y que puede llevar parntesis para encerrar subexpresiones con mayor prioridad en cada operacin, al igual que los operadores tienen cada uno una prioridad diferente, ya que, por ejemplo, la multiplicacin * tienen prioridad sobre la suma +.Veamos el grado de prioridad de estos operadores.

    1. Parntesis ( ) 2. Potencial ^ 3. Producto/cociente * / 4. Suma/resta + -

    Tambin hay que tener en cuenta que cuando se evala una operacin se

    hace de izquierda a derecha, excepto en el caso de las potencias, que se hace de derecha a izquierda.

    Esta forma de escribir una expresin, se denomina notacin usual o

    infija.

    Existen otras formas de escribir expresiones aritmticas, en el que se diferencian por la situacin de los operadores respecto de los operandos. La forma en la que los operadores se colocan delante de los operandos es conocida como notacin polaca o prefija.

    Vemos un ejemplo:

    Notacin infija: a*b/(a+c) Notacin polaca: */ab+ac

    Adems de estas existe otro tipo de notacin, el que a nosotros ms nos

    interesa, que es la notacin postfija, en la que se colocan los operadores a

    9

  • continuacin de los operandos, y en la cul no existe jerarqua en las operaciones.

    Las diferentes formas de escribir una misma expresin algebraica

    dependen de la ubicacin de los operadores respecto a los operandos. Es importante tener en cuenta que tanto en la notacin prefija como en la postfija no son necesarios los parntesis para cambiar el orden de evaluacin. Veamos algunos ejemplos de notacin infija respecto de la notacin postfija

    Notacin infija Notacin postfija 2*(3+8/(6-4)) 23864-/+*

    3+2*7-1 327*+1-

    1*2*3*4+5 12*3*4*5+

    Vemos que hacemos lo mismo que haramos en notacin infija y no hemos tenido que acudir a parntesis ni a jerarquas de operaciones. Por eso la evaluacin de expresiones postfijas es muy fcil de implementar.

    A la hora de evaluar una expresin aritmtica de notacin infija,

    tendremos que realizar dos pasos:

    Transformacin de notacin infija a notacin postfija. Evaluacin de la notacin postfija.

    Para ello tendremos que emplear un tipo TDA pila. Veamos que ocurre

    en cada uno de los casos.

    Transformacin de notacin infija a notacin postfija

    Partimos de una expresin con notacin infija que tiene operadores y operandos, que queremos transformar en una notacin postfija.

    La transformacin se realiza mediante la utilizacin de una pila en la que

    se van metiendo los operadores y los parntesis izquierdos. La expresin aritmtica se va leyendo carcter a carcter y va guardndose en una pila o en un array, segn de lo que se trate, de la siguiente forma:

    Si es un operando, se guardara directamente en el array o en un

    fichero.

    Si es un operador y la pila est vaca, lo meteremos en la pila. Si la pila no esta vaca, tendremos que distinguir el grado de prioridad de dicho operador. Por lo tanto:

    Si la cima de la pila es un operador de menor prioridad, entonces lo meteremos en la pila.

    10

  • Sin embargo si la cima de la pila es un operador de mayor o igual prioridad, entonces tendremos que sacar los operadores de la pila uno a uno y los escribiremos en el array o fichero hasta que en la cima haya en operador de menor prioridad, un parntesis de apertura o hasta que la pila quede vaca. Ser entonces cuando metamos el operador. De esta forma nos aseguramos de que las operaciones con mayor prioridad se realizan anteriormente, pues sus operadores son los que antes salen de la pila

    Si es un parntesis tendremos que distinguir los dos casos existentes:

    Si es un parntesis de apertura se mete en la pila, se considerara de menor prioridad para todo.

    Cuando se lee el otro parntesis de clausura hay que sacar todos los operadores de la pila que pasaran a formar parte de la notacin postfija hasta llegar al parntesis de apertura, que se eliminara, ya que los parntesis no forman parte de la notacin postfija.

    De esta forma aseguramos que las operaciones contenidas en un parntesis van a ser agrupadas.

    El proceso se termina cuando ya no hay mas tems que leer, y es entonces

    cuando sacamos uno a uno los operadores que pudieran quedar en la pila y los escribimos al final de nuestro array o fichero. Todo habr concluido cuando no haya nada ms que leer y la pila este vaca.

    En estos casos tambin es conveniente utilizar pilas implementadas

    mediante listas enlazadas, ya que no sabemos cual va a ser la longitud de la pila y si utilizamos un vector podemos quedarnos cortos o pasarnos de largo.

    Veamos algn ejemplo que nos aclare las cosas:

    a*(b+c-(d/e^f)-g)

    a el operando a pasa a un fichero o array, y * a la pila ab el ( pasa a la pila y el operando b pasa al fichero abc el + pasa a la pila y el operando c se escribe en el fichero

    La pila tiene la siguiente forma:

    + ( *

    - ( *

    Se nos presenta el problema del -, que como tiene igual prioridad que el + se saca +, se escribe en el fichero y se mete en la pila.

    abc+ el ( se escribe en la pila abc+de el operando d pasa al array, el / a la pila, y e pasa al array abc+def ^ lo metemos en la pila, y f lo escribimos en el fichero.

    11

  • Ahora se cierra un parntesis y tenemos la siguiente pila:

    ^ / ( - ( *

    Luego nuestra expresin quedar, tras haber sacado los operadores hasta parntesis y eliminndolo despus de haberlo sacado as: abc+def^/

    abc+def^/-g el se compara con la cima de la pila, que al ser de igual prioridad se escribe en el array o fichero y en se mete en la pila.

    abc+def^/-g- al terminar el otro parntesis, escribimos todo lo que hay en la

    pila hasta llegar al parntesis de apertura. La pila ser ahora de la forma:

    *

    Como ya no hay mas tems escribimos el contenido de la pila al final de la notacin postfija, y la pila quedar vaca, y el resultado ser: abc+def^/-g-*

    Evaluacin de la notacin postfija:

    Cuando tenemos una expresin aritmtica en notacin postfija, con valores reales, y queremos evaluarla, lo que tendremos que hacer ser utilizar una pila de operandos, es decir, de nmeros reales.

    Tendremos un algoritmo que evaluar la expresin, leyendo los datos de

    la expresin uno a uno y tratndolos segn su tipo.

    Si es un nmero real, lo meteremos en la pila. Si es un operador, lo que haremos ser sacar dos nmeros reales de la

    pila y les aplicaremos el operador sobre ellos. El resultado lo meteremos en la pila. Hay que tener en cuenta a los operadores resta y cociente (- y /) ya que en ocasiones no nos es indiferente el orden de los nmeros. Para ellos, el elemento que antes hubiese entrado en la pila, es decir, el que sacamos en segundo lugar, ser el que aparezca a la izquierda del operador.

    Resumidamente, se trata de recorrer la expresin y cada vez que

    encontremos un operador, se lo aplicamos a los dos ltimos nmeros que

    12

  • hayamos introducido en la pila. Entonces el nmero real que quede en la pila ser el resultado.

    Tanto en este caso, como en el anterior, como no sabemos el tamao de

    la expresin, ser mejor utilizar pilas implementadas mediante listas enlazadas.

    Veamos un ejemplo de la evaluacin de la notacin postfija:

    Evaluemos la expresin postfija: 327*+1-

    Tendremos una pila de la forma:

    Y nos encontramos con un operador *, y lo que hacemos es: 7 2 3

    TOPE (Pila) = 7 POP (Pila) TOPE (Pila):=2 POP (Pila) 7*2=14 PUSH (pila, 14)

    14 3

    Ahora nos encontramos con el operador +, y procedemos de igual

    manera:

    TOPE (Pila)=14 POP (Pila) TOPE (Pila)=3 POP (Pila) 14+3=17 PUSH (Pila, 17) PUSH (Pila, 1)

    1 17

    Nos encontramos con el operador - . Lo que hacemos es sacar los dos valores de la pila con y resolver, y ese

    ser el resultado: 17 1= 16

    Por lo tanto 327*+1- = 16

    13

  • IMPLEMENTACIN DE LAS PILAS:

    Mediante vectores:

    Una pila puede implementarse mediante vectores, en cuyo caso la dimensin

    es fija. En este caso se dir que es una implementacin esttica. Cuando lo implementamos mediante un vector hay que tener en cuenta que el tamao de la pila no puede exceder el nmero de elementos del array.

    Definiremos, antes de implementar una pila mediante vectores, el nmero

    mximo de elementos que podremos meter en el apila. Ser n

    La declaracin de pila es:

    Elemento = E; Pila = registro de

    cima: numrico; arreglo: vector [1n] de elemento:

    fin registro;

    Luego la pila ser:

    Donde cima corresponde a la posicin en el vector del ltimo elemento insertado en la lista, o sea que a de apuntar en todo momento al elemento tope. As si pila.cima=01 entenderemos que la pila esta vaca, mientras que si pila.cima = n la pila estar llena.

    Esta implementacin no es apropiada cuando no se conoce el nmero

    mximo de elementos que puede tener una pila ya que podra quedarse corta por faltarle posiciones, y se producira un error, o por pasarse de larga, es decir, utilizar mucha ms memoria de la estrictamente necesaria y desaprovecharla. De todas formas, esta implementacin tiene una gran ventaja, que es la sencillez y rapidez con la que se programa y se realizan las operaciones.

    Veamos cuales son las operaciones bsicas:

    #defina tam_max 20 /*este ser el tamao mximo (20), se puede cambiar*/ Typedef int elemento; /*ser una pila de enteros*/ Typedef struct {

    int cima; elemento v[tam_max];

    14

  • }pila; /*El tipo elemento variar, al igual que el tam_mx, dependiendo del

    programa*/

    Crear_Pila (PILA *P){ /*Creamos una pila vaca*/ Pila.cima = tam_max; }

    Borrar_Pila (PILA *P){ /*Borramos una pila, la dejamos vaca*/ while(!VACIA(P)) POP(P); }

    Vacia? (PILA *P){ /*Preguntamos si la pila est vaca*/ if (pila.cima == tam_max){

    return 1; }

    else { return 0; }

    }

    Llena? (PILA *P){ /*Comprobamos si la pila esta llena*/ if (pila.cima == 0){

    return 1; }

    else { return 0; }

    }

    PUSH (PILA *P, elemento x){ /*Inserta un elemento en la pila(si puede)*/ int copia_cima, valor_llena; valor_llena = llena?(P); if (valor_llena == 1) {

    return 0; }

    else { copia_cima = *P.tope; *P.v[copia_cima-1] = x; *P.cima = copia_cima-1; return 1; }

    }

    15

  • POP (PILA *P){ /*Elimina el primer elemento del vector, la cima*/ int valor_vacia; valor_vacia = Vacia?(P); if (valor_vacia == 1){

    return 0; }

    else{ *P.cima = *P.cima+1; return 1; }

    }

    TOPE (PILA *P){ /*Te devuelve el tope de la pila*/ int copia_cima; if ( vacia?(P) == 0){

    copia_cima = P.cima; return P.v[copia_cima]; }

    else{ printf(\nError. Has aplicado la funcin tope a una pila vacia\n); }

    }

    Mediante listas enlazadas:

    La realizacin dinmica de una pila se hace almacenando los elementos como nodos de una lista enlazada, con la particularidad de que siempre que se desee hacer una operacin sobre ella se hace por el mismo extremo que se extrae.

    Esta realizacin tiene la ventaja de que el tamao se ajusta exactamente a

    los elementos de la pila, no hay un mximo de elementos, por lo tanto tampoco puede haber una lista llena. Sin embargo, para cada elemento es necesaria ms memoria ya que hay que guardar el campo de enlace.

    Una pila realizada con listas enlazadas crece y decrece dinmicamente.

    En tiempo de ejecucin se reserva memoria segn se ponen los elementos en la pila y se libera memoria segn se extraen elementos de la pila.

    A diferencia de la cabecera de una lista usual, la cabecera de una pila no

    va a ser un registro que incluya el nmero de nodos y punteros al primer y ltimo elemento, sino que va a ser simplemente un puntero que apunta al primer nodo.

    La declaracin de la pila ser:

    16

  • Elemento = E; Nodo = registro de

    info: elemento; sgte: puntero a Nodo;

    fin registro;

    Pila = puntero a NODO.

    Las operaciones principales sern las siguientes:

    Crear_pila(PILA *P){ /*Creaciones de la pila*/ P->longitud=0; P->prim=NULL; }

    Borrar_Pila (PILA *P){ /*libera la pila*/ while(!VACIA(P)) POP(P); }

    PUSH (PILA *P,elemento *x){ /*Apila un elemento ms*/ POSICION temp; temp = crea_nodo(x); temp->info=*x; if(VACIA(P)){

    P->prim=temp; temp->sgte=NULL; }

    else{ temp->sgte=P->prim; P->prim=temp; }

    P->longitud++; }

    POP (PILA *P){ /*Elimina el tope de la pila*/ NODE *q; if (VACIA(P)) printf("No existe tope,ya que la pila est vaca.\n"); else {

    q = P->prim; P->prim = q->sgte; free(q); P->longitud--; }

    }

    17

  • TOPE (PILA *P){ /*Devuelve el elemento tope de la pila*/ if (VACIA(P)) printf("No existe tope.\n"); else return(P->prim->info); }

    PROGRAMA DEMO: #include #include #include /*Declaraciones*/ typedef int elemento; struct NODE{ elemento info; struct NODE *sgte; }; typedef struct NODE nodo; typedef NODE *POSICION; typedef struct { int longitud; POSICION prim; } PILA; /*Creaciones de la pila*/ void crear_pila(PILA *P) { Plongitud=0; Pprim=NULL; } /* Creacin de un nodo a partir de un elemento dado */ NODE * crea_nodo (elemento *i) { static NODE *p; p = (NODE *) malloc (sizeof(NODE)); if (p == NULL) printf ("\nError. No puedo crear puntero a estructura\n"); else{ pinfo= *i; /* Copio datos originales, en campo info de nodo creado */ psgte = NULL; }

    18

  • Return (p); } /*la pila est vaca?*/ int VACIA (PILA *P) { int resp,tam; tam = Plongitud; resp = (tam == 0)?1:0; return resp; } /*Devuelve el elemento tope de la pila*/ elemento TOPE (PILA *P) { if (VACIA(P)) printf ("No existe tope.\n"); else return (P prim info); } /*Elimina el tope de la pila*/ void POP (PILA *P) { NODE *q; if (VACIA (P) ) printf ("No existe tope,ya que la pila est vaca.\n" ); else { q = Pprim; Pprim = qsgte; free(q); Plongitud--; } } /*libera la pila*/ void DESTRUIR (PILA *P) { While (!VACIA(P)) POP (P); } /*Apila un elemento ms*/ void PUSH (PILA *P,elemento *x) { POSICION temp; temp = crea_nodo(x); tempinfo =*x;

    19

  • if(VACIA(P)){ P prim = temp; Temp sgte = NULL; } else{ temp sgte = Pprim; P prim = temp; } P longitud++; } /*Da la vuelta a la pila*/ PILA GIRA (PILA *P) { PILA S; crear_pila (&S); elemento r; do{ r = TOPE (P); PUSH (&S, &r); POP (P); }while (VACIA(P) == 0); return S; } /*Mostrar el contenido de la pila*/ void contenido_pila(PILA *P) { PILA S; elemento r; crear_pila (&S); /*Con dos pilas, muestra la pila inicial correctamente*/ S = GIRA (P); printf("El contenido de la pila es:\n"); do{ r = TOPE (&S); printf ("%d\n",r); PUSH (P,&r); POP (&S); }while (VACIA(&S) == 0); } /* Empezamos nuestro programa principal en el utilizaremos todos los subprogramas anteriores, cada uno para una cosa*/ main (){ PILA P,S;

    20

  • FILE *in; elemento x; int opcion; int resp; char nombre[20]; char linea[10]; do{ /*Bucle do para que puedas realizar varias operaciones al mismo tiempo*/

    printf("Elije una de las siguientes opciones:\n1. Crear una pila con los datos de un fichero.\n2. Crear una pila con los datos por teclado.\n3. Guardar una pila en un fichero.\n4. Borrar una pila.\n5. Insertar un elemento en una pila.\n6. Eliminar un elemento en una pila.\n7. Mostrar el contenido de una pila.\n8. Terminar.\n"); scanf("%d",&opcion); if (opcion == 1){ /*Abre un archivo, lee los datos y los mete en una pila*/ crear_pila (&P); printf("dame el nombre del fichero del que sacar los datos(con extension .txt)"); scanf("%s",nombre); if ((in = fopen(nombre, "r")) != NULL){ do{ fscanf (in,"%d",&x); PUSH (&P,&x); }while (fgets(linea,10,in) != NULL); fclose(in); } else printf ("No se pudo abrir el fichero "); } if (opcion == 2){ /*Crea una pila mediante los datos que le das por teclado*/ crear_pila(&P); do{ /*El usuario elige cuantos datos quiere darle a la pila*/ printf ("\nQuieres introducir un elemento?(s=1/n=2)"); scanf ("%d",&resp); if (resp == 1){ printf ("\nDame el elemento que quieres introducir"); scanf ("%d", &x); PUSH (&P, &x); } }while(resp==1); } if (opcion == 3){ /*Dada una pila la gira, para que al meterla este en orden*/ crear_pila(&S); S = GIRA(&P); printf("Dame el nombre del fichero en que quieres guardar la pila(con extension.txt)"); scanf("%s",nombre); if((in = fopen(nombre, "w")) != NULL){ /*Abre un fichero y guardara la pila*/

    21

  • do{ fprintf(in,"%d\n",TOPE(&S)); POP (&S); Resp = VACIA(&S); }while (resp==0); } else printf("No se pudo abrir el fichero"); } if (opcion == 4){ /*Elimina la pila*/ DESTRUIR (&P); } if (opcion == 5){ /*En esta funcin mete un elemento a la pila*/ printf("\nDame el elemento que quieres introducir"); scanf("%d", &x); PUSH (&P, &x); } if (opcion == 6){ /*En este otro caso saca un elemento de la pila*/ POP (&P); } if (opcion == 7){ /*Muestra los datos de la pila por pantalla*/ contenido_pila (&P); } }while(opcion!=8); } REFERENCIAS: Libros:

    9 Estructuras de datos y algoritmos. Mark Allen Weiss 9 Estructuras de datos. Aho, Hopcroft, Ullman 9 Estructuras de datos. Cairo, Guardati 9 Fundamentos de programacin. Algoritmos, estructurasde datos. Una

    perspectiva en C. Joyanes Aguilar 9 Fundamentos de programacin. Algoritmos, estructurasde datos y objetos.

    Joyanes Aguilar Paginas web: 9 www.fcad.uner.edu.ar/C_LicSistemas/

    Materias/est_datos/MartinezQuiroga_06PilasyFilas.pdf - 9 www.politeca.ing.ula.ve/Contenido/Digiteca/ProyectosTesisGrado/Pregrado/Uni

    versidaddelosAndes/IngenieriaSistemas/DepartamentoComputacion/2005/RodriguezJose.pdf

    22