Você está na página 1de 13

Estruturas de Dados

Pilhas
Prof. Ricardo J. G. B. Campello

Crditos
Parte dos slides a seguir so adaptaes,
extenses e tradues para C dos originais:


disponveis em http://ww3.datastructures.net/

cedidos pela Profa. Maria Cristina F. de Oliveira

Pilhas


Pilha: lista linear em que insero e eliminao de


elementos s ocorrem em uma das extremidades


Tal extremidade denominada TOPO da pilha

D
C
B
A


TOPO

BASE

Dada uma Pilha P = (a1, a2, ..., an), dizemos que a1


o elemento na base, an o elemento no topo, e
ai+1 est acima de ai na pilha
3

O TAD PILHA
Uma Pilha armazena elementos
de um ou mais tipos

Operaes auxiliares:


Inseres e Remoes seguem


o esquema Last-In First-Out
Pense nela como uma pilha de
pratos ou de livros
Operaes principais:


push(x, P): insere um elemento


x no topo da pilha P.

top(P): retorna o ltimo


elemento inserido, sem
retir-lo da pilha P.
size(P): retorna o nmero
de elementos armazenados
na pilha P.
pilha_vazia(P): indica se a
pilha P est vazia ou no.
...

pop(P): remove e retorna o


elemento que est no topo.

Aplicaes de Pilhas
Aplicaes diretas:


Histrico de pginas visitadas em um navegador na Web

Controle de Desfazer/Refazer aes em um editor de textos

Encadeamento de chamadas a mtodos ou funes em


ambientes de execuo, como em Pascal, C ou Java

Aplicaes indiretas:


Estrutura auxiliar para algoritmos

Componente de outras estruturas de dados

Exemplo: Pilha de Chamadas


Um programa executvel mantm
controle da cadeia de chamadas
ativas atravs de uma Pilha:


Por exemplo, pilha de recurso

Quando uma rotina chamada,


insere-se na pilha uma frame com:



Variveis locais e valor de retorno.


Contador de programa (PC) que
mantm a trilha das declaraes
sendo executadas.

Quando uma rotina encerra sua


frame removida da pilha e o
controle passado rotina no
topo da pilha.

main() {
int i = 5;
foo(i);
}
foo(int j) {
int k;
k = j+1;
bar(k);
}
bar(int m) {

bar
PC = 1
m=6
foo
PC = 3
j=5
k=6
main
PC = 2
i=5
6

Implementao Baseada em Arranjo


Uma forma simples de
implementar o TAD Pilha
usar arranjos.

Algoritmo pop(P):
se pilha_vazia(P) ento
retorne nulo
seno
P.topo P.topo 1
retorne P.S[P.topo + 1]

Adicionamos elementos a
partir do incio do arranjo.
Uma varivel topo guarda
informao sobre a posio
do elemento do topo :


Algoritmo push(x, P)
se pilha_cheia(P) ento
retorne false
seno
P.topo P.topo + 1
P.S[P.topo] x
retorne true

Coincide com o tamanho


da Pilha se arranjo for
indexado a partir de 1.

S
1

topo

Implementao Baseada em Arranjo


#define
#define
#define
#define

MAX 100 /* Max. Tamanho da Pilha */


TRUE 1
FALSE 0
bool int

typedef struct {
Tipo_1 chave;
Tipo_2 info;
} tipo_elem;

/* P. ex. int chave;


*/
/* P. ex. char info[50] */
/* Tipo do Elemento
*/

typedef struct {
int topo;
tipo_elem S[MAX+1]; } Pilha;
Pilha P;

/* Tipo da Pilha */

/* Exemplo de Declarao */
8

Implementao Baseada em Arranjo


void define(Pilha *P){
P->topo = 0;
P->S[0].chave = 0;

/* Clula no utilizada */

P->S[0].info[0] = '\0';

/* Clula no utilizada */

} /* O(1) */
bool pilha_vazia(Pilha *P){
return (P->topo == 0);
} /* O(1) */
int size(Pilha *P){
return P->topo;
} /* O(1) */
9

Implementao Baseada em Arranjo


bool push(tipo_elem x, Pilha *P){
if (P->topo == MAX)
return FALSE;

/* pilha cheia! */

else {
P->topo++;
P->S[P->topo] = x;
return TRUE;
}
}

/* O(1) */

10

Implementao Baseada em Arranjo


tipo_elem top(Pilha *P){
tipo_elem x;
if (pilha_vazia(P)) {
x.chave = 0;

/* elemento invlido */

x.info[0] = '\0';

/* elemento invlido */

}
else x = P->S[P->topo];
return x;
}

/* O(1) */

11

Implementao Baseada em Arranjo


tipo_elem pop(Pilha *P){
tipo_elem x;
if (pilha_vazia(P)) {
x.chave = 0;

/* elemento invlido */

x.info[0] = '\0';

/* elemento invlido */

}
else {
x = P->S[P->topo];
P->topo--; }
return x;
}

/* O(1) */
12

Desempenho e Limitaes
Desempenho:


Seja n o nmero de elementos na pilha


 O espao utilizado (memria) O(MAX)
 Cada operao roda em tempo O(1)


Apenas inseres e remoes no final!

Limitao:


O tamanho mximo da pilha deve ser definido a


priori e no pode ser alterado a no ser copiando
toda a pilha para uma outra, de capacidade maior.
13

Implementao Encadeada
Para eliminar a necessidade de prever o tamanho mx.
da pilha, utiliza-se uma implementao dinmica.
Encadeamento simples suficiente:


Apenas inseres e remoes no incio

topo
A

O espao utilizado (memria) O(n)

Cada operao roda em tempo O(1)

14

Implementao Encadeada
Por simplicidade, implementaremos a pilha usando a
implementao simplesmente encadeada do TAD Lista


Logo, assume-se que foram predefinidos os tipos:


 nodo, tipo_elem, Lista.
 p. ex. via #include arquivo .h (header) da lista

typedef struct {
Lista *Lis_din;
} Pilha;

15

Implementao Encadeada
Pilha *define(void){
Pilha *P;
P = malloc(sizeof(Pilha));
(P->Lis_din) = Definir();
return P;
}
/* O(1), pois Definir O(1) */

16

Implementao Encadeada
int size(Pilha *P){
return Tamanho(P->Lis_din);
} /* O(1), pois Tamanho O(1) */
bool pilha_vazia(Pilha *P){
return Lista_vazia(P->Lis_din);
} /* O(1), pois Lista_vazia O(1) */

* Como reescrever pilha_vazia usando size ... ?


17

Implementao Encadeada
void push(tipo_elem x, Pilha *P){
Inserir_frente(x, P->Lis_din);
}

/* O(1), pois Inserir_frente O(1) */

tipo_elem pop(Pilha *P){


if (!pilha_vazia(P))
return Remover_frente(P->Lis_din);
else printf("Pilha Vazia!!!");
}

/* O(1), pois Remover_frente O(1) */

18

Implementao Encadeada
tipo_elem top(Pilha *P){
if (!pilha_vazia(P))
return Elemento(P->Lis_din->head);
else printf("Pilha Vazia!!!");
}

/* O(1), pois Elemento O(1) */

19

Implementao Esttica vs Dinmica




Ambas realizam todas as ops. em tempo O(1).

Implementao esttica seqencial:




mais simples

Implementao dinmica:


mais apropriada para pilhas cujo tamanho




no pode ser antecipado ou

muito varivel

20

10

Exemplo de Aplicao


Avaliao de Expresses Aritmticas:




Uma representao conveniente do ponto de


vista computacional de interesse


Por exemplo, para o desenvolvimento de compiladores

A notao tradicional (infixa) ambgua




Por exemplo: A * B - C / D = ?

Demanda regras de prioridade ou uso de parnteses

Outras notaes so mais convenientes


21

Exemplo de Aplicao


Notao Polonesa (prefixa):







Operadores aparecem imediatamente antes dos operandos.


Especifica quais operadores devem ser calculados e a ordem.
Por esse motivo, dispensa o uso de parnteses.
Exemplo: * A B / C D = (A*B) (C/D)

Notao Polonesa Reversa (posfixa):





Operadores aparecem aps os operandos.


Exemplo: A B * C D / = (A*B) (C/D)

22

11

Exemplo de Aplicao
Algoritmo (Avaliao de Expresses)


Para Notao Polonesa Reversa:




Percorre a expresso seqencialmente




empilhando operandos at encontrar um operador

Quando encontra um operador




desempilha o nmero correspondente de operandos

calcula e empilha o valor resultante

23

Exemplo de Aplicao
Expresso: A B / D E * + A -

24

12

Exerccios
1.

Implemente um procedimento recursivo que remova todos os


elementos de uma pilha. Esse procedimento s pode acessar
a pilha atravs das operaes definidas no TAD Pilha.

2.

Implemente a seguinte funo:


Pilha *copia(Pilha *P);
que receba um ponteiro para uma Pilha P1 e retorne um
ponteiro para outra Pilha P2 alocada dinamicamente em
memria e cujos elementos so cpias de P1, na mesma
ordem da base para o topo. Essa funo deve usar, como
variveis locais, apenas 2 pilhas (nenhuma outra varivel).

25

Bibliografia
A. M. Tenembaum et al., Data Structures Using C,
Prentice-Hall, 1990
M. T. Goodrich & R. Tamassia, Data Structures and
Algorithms in C++/Java, John Wiley & Sons,
2002/2005
N. Ziviani, Projeto de Algoritmos, Thomson, 2a.
Edio, 2004
J. L. Szwarcfiter & L. Markenzon, Estruturas de
Dados e seus Algoritmos, LTC, 1994
Schildt, H. "C Completo e Total", 3a. Edio,
Pearson, 1997
26

13

Você também pode gostar