Anda di halaman 1dari 42

PILHAS

TELMA SOARES
Pilhas são listas onde a inserção de um novo item ou a remoção
de um item já existente se dá em uma única extremidade, no topo.

… … Pilha vazia

topo

A … … Insere(A)

topo

A B … … Insere(B)

topo
A … … Retira()= B

topo

A C … … Insere(C)

topo

A … … Retira()= C

topo

… … Retira()= A

topo
Definição (Pilha)

Dada uma pilha P=( a(1), a(2), ..., a(n) ), dizemos que a(1) é o
elemento da base da pilha; a(n) é o elemento topo da pilha; e
a(i+1) está acima de a(i).

Pilhas são também conhecidas como listas

LIFO (last in first out).


Exercício

Fazer a definição do TAD pilha !!


Operações Associadas
1. criar (P) - criar uma pilha P vazia

2. inserir (x, P) - insere x no topo de P (empilha): push(x,P)

3. vazia (P) - testa se P está vazia

4. topo (P) - acessa o elemento do topo da pilha (sem eliminar)

5. elimina (P) - elimina o elemento do topo de P (desempilha):


pop(P)
6. destruir(P) - destrói a estrutura e libera o espaço ocupado por ela.
Implementação de Pilhas
Como lista Seqüencial ou Encadeada ?

No caso geral de listas ordenadas, a maior vantagem da alocação


encadeada sobre a seqüencial - se a memória não for problema -
é a eliminação de deslocamentos na inserção ou eliminação dos
elementos.
No caso das pilhas, essas operações de deslocamento não ocorrem.

Portanto, pode-se dizer que a alocação seqüencial é mais vantajosa


na maioria das vezes.

Um outro modo de se implementar pode ser feito utilizando pilhas


múltiplas.
Exemplo do Uso de Pilhas
Chamadas de procedimentos

Suponha a seguinte situação:


PROC P1 PROC P2 PROC P3 PROC P4
-------------- -------------- -------------- --------------
P2 P3 P4 ----
e1: ---------- e2: ---------- e1: ---------- e1: ----------
-------------- -------------- -------------- --------------
end end end end
Exemplo do Uso de Pilhas em C
Quando o procedimento A1 é executado, ele efetua uma chamada
a A2, que deve carregar consigo o endereço de retorno e1.
Ao término de A2, o processamento deve retornar ao A1, no
devido endereço.
Situação idêntica ocorre em A2 e A3.

Assim, quando um procedimento termina, é o seu endereço de


retorno que deve ser consultado. Portanto, há uma lista implícita de
endereços (e0, e1, e2, e3) que deve ser manipulada como uma
pilha pelo sistema, onde e0 é o endereço de retorno de A1.
Exemplo do Uso de Pilhas em C

No caso de processamento recursivo - por exemplo uma chamada a


A2 dentro de A4 - o gerenciamento da lista como uma pilha resolve
automaticamente a obtenção dos endereços de retorno na ordem
apropriada (e0, e1, e2, e3, e4).
Alocação Seqüencial de Pilhas
Definição da Estrutura de Dados e C
#define Maxp 100;
typedef tipo_elem Pilha[Maxp];
typedef int indice;

Pilha P;
indice topo;
… …

topo Pilha vazia


Refazer as operações abaixo, para o caso da pilha ser definida
da seguinte estrutura:

typedef Tipo_Elem aloc_pilha[Maxp];


typedef struct {
aloc_pilha info;
indice topo;
}Pilha;

Pilha P;
Operações

1. criar (P) - criar uma pilha P vazia

void criar (Pilha *p)


{
p->topo=0;
}
2. inserir (x, P) - insere x no topo de
P(empilha): push (x, P).

void push (Tipo_Elem x, Pilha *P)


{
if P->topo == Maxp
printf(“PILHA CHEIA\n“);
else {
P->topo++;
P->info[P->topo] := x;
}
}
3. vazia (P) - testa se P está vazia

int vazia (Pilha p)


{
return p.topo==0;
}
4. topo (P) - acessa o elemento do topo da pilha
(sem eliminar)

void top (TipoElem *x, Pilha P)


{
if (vazia(P))
printf("Pilha esta vazia \n");
else *x = P.info[P.topo-1];
}
5. elimina (P) - elimina o elemento do topo de P
(desempilha): pop (P)

void pop (Pilha *P, TipoElem *x)


{ if (vazia(*P))
printf("Pilha Vazia \n");
else {
*x = P->info[P->topo-1];
P->topo--;
}
}
Devolve elemento eliminado
TipoElem pop_up (Pilha *P)
{
if (vazia(*P))
{
printf("PILHA VAZIA \n");
return '/';
}
else { P->topo--;
return (P->info[P->topo]);
}
}
Lembre o exercício
Refazer as operações anteriores (criar pilha vazia, inserir(x,P),
testar lista vazia, acessar elemento topo, eliminar elemento topo)
para o caso da pilha ser definida da seguinte estrutura:

#define Maxp 100;


typedef tipo_elem
Pilha[Maxp];
typedef int indice;

Pilha P;
indice topo;
Exercício
typedef Tipo_Elem aloc_pilha[Maxp];
#define Maxp 100; typedef struct {
typedef tipo_elem aloc_pilha info;
Pilha[Maxp]; indice topo;
typedef int indice; }Pilha;

Pilha P; Pilha P;
indice topo;

Responda: do ponto de vista do TAD, qual das duas organizações de


pilha exemplificadas acima é a mais adequada? Justifique.
Pilhas Encadeadas
Alocação Encadeada de Pilhas
Definição da Estrutura de Dados
typedef char TipoElem;
struct cx
{
TipoElem info;
struct cx *prox;
};
typedef struct cx *Ponteiro;
typedef struct cx Caixa;
typedef struct {
Ponteiro topo; Obs: p aponta o topo.
int n;
} Pilhae;
Ponteiro p;

….

topo
Operações em Pilhas Encadeadas
Fazer a documentação de cada operação, incluindo
pré e pós-condições.

1. criar (P) - criar uma pilha P vazia

void criape (Pilhae *P) void criatepv (Pilha *p)


{ P->topo=NULL; {
P->n = 0; p->topo=0;
} }
2. inserir (x, P) - insere x no topo de P (empilha):
push(x,P)
void push (Pilhae *P, TipoElem x)
{ Ponteiro aux;
aux= (Caixa*) malloc(sizeof(Caixa));
aux->info=x;
aux->prox=NULL;
if (vazia (*P))
P->topo=aux;
else { aux->prox=P->topo;
P->topo=aux;
}
P->n++;
} // Push procedimento que empilha o elemento x na
pilha
3. vazia (P) - testa se P está vazia

int vazia(Pilhae p)
{
return p.topo==NULL;
} //vazia Função que verifica se a Pilhae está
vazia.
4. topo (P) - acessa o elemento do topo da pilha
(sem eliminar), supondo que existe pelo menos
um elemento na pilha.

TipoElem top (Pilhae *P)


{
return P->topo->info;
}
5. elimina (P) - elimina o elemento do topo de P
(desempilha) se não estiver vazia: pop(P)
void pop (Pilhae *P, TipoElem *x)
{ Ponteiro aux;
if (vazia(*P))
{printf("Pilha Vazia - nao tem mais elemento pra
remover \n");
*x=-1;
}
else {
aux=P->topo;
*x=aux->info;
P->topo=P->topo->prox;
P->n--;
free(aux);
}
} // pop desempilha o elemento x da pilha e retorna
para o meio externo
6. INVERTE A ORDEM DA PILHA

void inverte_pilha(Pilhae *P, Pilhae *S)


{ Ponteiro a;
TipoElem x;
if (vazia(*P))
printf("Pilha vazia - inverte \n");
else while (vazia(*P)!=1)
{ pop(P,&x);
printf("%d - ",x);
push(S,x);
}
printf("\n");
}
MAIN ()
int main()
{ Pilhae P, S;
TipoElem x;
int op=0;
criatepe (&P);
criatepe (&S);
do { system("CLS");
printf(" MENU USO DE PILHA \n");
printf("=============================================== \n");
printf(" 1- Empilhar \n");
printf(" 2- Desempilhar \n");
printf(" 3- Inverter Pilha \n");
printf(" 4- Imprimir elemento topo \n");
printf(" 5- Sair \n");
printf("=============================================== \n");
printf(" Opcao: ");
scanf("%d",&op);
printf("\n");
printf("=============================================== \n");
MAIN () - CONT...
switch (op) {
case 1: { printf("Empilhar o elemento: ");
scanf("%d",&x);
push(&P, x);
printf("\n");
system("PAUSE");
break;}
case 2: { pop(&P, &x);
printf("Elemento desempilhado : %d \n",x);
system("PAUSE");
break;}
case 3: { printf("INVERTENDO A PILHA \n");
printf("================== \n");
inverte_pilha(&P,&S);
P=S;
S.topo=NULL;
system("PAUSE");
break;}
MAIN () - CONT...
case 4: { printf("ELEMENTO DO TOPO : %d \n",P.topo->info);
system("PAUSE");
break;}
case 5: { printf("Obrigado por utilizar nossos Sistems \n");
printf("D E S C O N E C T A D O \n");
system("PAUSE");
break;
}
default :{printf("Opcao Incorreta digite novamente \n");
system("PAUSE");
break;
}
}
}
while (op!= 5);
return 0;
}
Exercícios

1. Codifique a operação de destruição da pilha.

2. Incluir operações que tratem possíveis condições de exceções.


Depois disso, responda: Quais operações estariam 'visíveis' para o
usuário num TAD corretamente implementado?
Aplicações de Pilhas
Aplicação de Pilha: Notação Polonesa
Uma representação para expressões aritméticas que seja conveniente
do ponto de vista computacional é assunto de interesse, por exemplo,
na área de compiladores.

A notação tradicional é ambígua e, portanto, obriga o


pré-estabelecimento de regras de prioridade.

Isso torna a tarefa computacional menos simples.

Outras notações são apresentadas a seguir, considerando apenas


operações binárias (com dois operandos):
•Notação completamente Parentizada: acrescenta-se sempre um
parênteses a cada par de operandos e seu operador.
Exemplo:
tradicional: A * B - C / D
parentizada: ((A*B)-(C/D))

•Notação Polonesa: os operandos aparecem imediatamente antes dos


operandos. Esta notação especifica quais operadores, e em que
ordem, devem ser calculados. Por esse motivo dispensa o uso de
parênteses, sem ambiguidades.
Exemplo:
tradicional: A * B - C / D
polonesa: - * A B / C D
•Notação Polonesa: os operandos aparecem imediatamente antes
dos operandos. Esta notação especifica quais operadores, e em
que ordem, devem ser calculados. Por esse motivo dispensa o uso
de parênteses, sem ambiguidades.
Exemplo:
tradicional: A * B - C / D
polonesa: - * A B / C D

•Notação Polonesa Reversa (ou posfix): é como a polonesa na


qual os operandos aparecem após os operandos.
Exemplo:
tradicional: A * B - C / D
polonesa reversa: A B * C D / -
Avaliação de expressões aritméticas
programa fonte - notação infix: x := A / B + D * E - A
objetivo- notação posfix: x := A B / D E * + A -

Um algoritmo para a avaliação de Expressões PosFix:

•empilha operandos até encontrar um operador


•retira o número de operandos; calcula e empilha o valor resultante
•até que chegue ao final da expressão
Exemplo: A B / D E * + A -
Operador: / A B … …
topo
A/B … …
topo

Operador: * A/B D E … …
topo
Operador: + A/B D*E … …
topo

A/B + D*E … …
topo

Operador: - A/B + D*E A … …


topo
V … …
function valor ( E: expressão): TipoValor;
var x : TipoOperador;
begin
topo := 0;
while not acabou(E) do
begin
x := proxsimb(E);
if x é operando then push(x,pilha)
else
begin
remove o # de operandos (dois) para o
operador x da pilha;
calcule o resultado da operação; empilhe
resultado;
end;
valor := P[topo];
end;
Exercícios de Pilha

1) Seja a função esvazie( ) tal que, recebendo uma pilha como entrada,
esvazie a pilha descartando todos os seus elementos.
Escreva a função esvazie( )

2) Escreva um programa que verifique que expressões aritméticas


estão com a parentização correta. Guarde o resultado numa pilha
também. Seu programa deve checar expressões para ver se cada
"abre parênteses" tem u m "fecha parênteses" correspondente.

3) Escreva um algoritmo que converta uma expressão escrita na


notação parentizada no seu equivalente na notação polonesa reversa.
4) Uma palavra é uma palíndrome se a seqüência de letras que a
forma é a mesma seja ela lida da esquerda para a direita ou
vice-versa.

Exemplos: arara, rairar, hanah.

Escreva a função palíndrome que, dada uma palavra, retorne true


caso a palavra seja uma palíndrome, e false caso contrário.
5)Sobre pilhas múltiplas:
a) Escreva os algoritmos para push e pop para o caso acima, isto é,
duas pilhas alocadas num mesmo array.

b) Escreva um programa que implementa múltiplas pilhas.


Utilize inicialização equilibrada. Utilize também uma das técnicas
para "adiamento" de overflow. Faça um editor interativo de pilhas
o qual permite ao usuário especificar como opções:

• push na pilha i
• pop na pilha i
• imprimir o conteúdo da pilha i
• imprimir o conteúdo de todas as pilhas

Anda mungkin juga menyukai