You are on page 1of 13

1

Estruturas de Dados
Pilhas
Prof. Ricardo J. G. B. Campello
2
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
2
3
Pilhas
Pilha: lista linear em que insero e eliminao de
elementos s ocorrem em uma das extremidades
Tal extremidade denominada TOPO da pilha
Dada uma Pilha P = (a
1
, a
2
, ..., a
n
), dizemos que a
1
o elemento na base, a
n
o elemento no topo, e
a
i+1
est acima de a
i
na pilha
A
B
C
D TOPO
BASE
4
O TAD PILHA
Uma Pilha armazena elementos
de um ou mais tipos
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.
pop(P): remove e retorna o
elemento que est no topo.
Operaes auxiliares:
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.
...
3
5
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
6
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
4
7
Implementao Baseada em Arranjo
Uma forma simples de
implementar o TAD Pilha
usar arranjos.
Adicionamos elementos a
partir do incio do arranjo.
Uma varivel topo guarda
informao sobre a posio
do elemento do topo :
Coincide com o tamanho
da Pilha se arranjo for
indexado a partir de 1.
Algoritmo pop(P):
se pilha_vazia(P) ento
retorne nulo
seno
P.topo P.topo 1
retorne P.S[P.topo + 1]
Algoritmo push(x, P)
se pilha_cheia(P) ento
retorne false
seno
P.topo P.topo + 1
P.S[P.topo] x
retorne true
S
1 2 3
topo

8
#define MAX 100 /* Max. Tamanho da Pilha */
#define TRUE 1
#define FALSE 0
#define bool int
typedef struct {
Tipo_1 chave; /* P. ex. int chave; */
Tipo_2 info; /* P. ex. char info[50] */
} tipo_elem; /* Tipo do Elemento */
typedef struct {
int topo;
tipo_elem S[MAX+1]; } Pilha; /* Tipo da Pilha */
Pilha P; /* Exemplo de Declarao */
Implementao Baseada em Arranjo
5
9
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) */
Implementao Baseada em Arranjo
10
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) */
Implementao Baseada em Arranjo
6
11
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) */
Implementao Baseada em Arranjo
12
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) */
Implementao Baseada em Arranjo
7
13
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.
14
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
O espao utilizado (memria) O(n)
Cada operao roda em tempo O(1)
A B C D
topo
8
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
15
Implementao Encadeada
typedef struct {
Lista *Lis_din;
} Pilha;
16
Implementao Encadeada
Pilha *define(void){
Pilha *P;
P = malloc(sizeof(Pilha));
(P->Lis_din) = Definir();
return P;
} /* O(1), pois Definir O(1) */
9
17
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 ... ?
18
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) */
10
19
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) */
20
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
11
21
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
22
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)
Exemplo de Aplicao
12
23
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
Exemplo de Aplicao
24
Expresso: A B / D E * + A -
Exemplo de Aplicao
13
25
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).
26 26
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