Pilha Estática
Uma pilha é um conjunto ordenado de itens no qual novos itens podem ser inseridos e a
partir do qual podem ser eliminados itens em uma extremidade chamada topo da pilha.
Podemos ilustrar uma pilha como a Figura 1. (PLT, pág86).
Ao contrário do que acontece com o vetor, a definição da pilha compreende a inserção e
a eliminação de itens, de modo que uma pilha é um objeto dinâmico, constantemente
mutável. Por conseguinte, surge então a pergunta: como uma pilha muda? A definição
especifica que uma única extremidade da pilha é designada como o topo da pilha.
Novos itens podem ser colocados no topo da pilha (em cujo caso este topo será
deslocado para cima, de modo a corresponder ao novo primeiro elemento), ou os itens
que estiverem no topo da pilha poderão ser removidos (em cujo caso esse topo será
deslocado para baixo, de modo a corresponder ao novo primeiro elemento). Para
responder à pergunta qual é o lado de cima?, precisamos determinar que extremidade da
pilha será designada como topo, isto é, em que extremidade serão incluídos ou
eliminados itens.
Desenhando a Figura 1 de modo que
F
esteja fisicamente em cima na página em relação
aos outros itens na pilha, estaremos implicando que
F
é o atual elemento superior da
pilha. Se forem incluídos novos itens na pilha, eles serão colocados acima de F e, se
forem eliminados alguns itens,
F
será o primeiro a ser eliminado. Isso é também
indicado pelas linhas verticais que se estendem além dos itens da pilha, na direção do
topo da pilha. (PLT, pág87).
Figura 1. Uma pilha contendo letras
A Figura 2 é um filme de uma pilha conforme ela se expande e se reduz com o passar
do tempo. A Figura 2a mostra o instantâneo da pilha da Figura 1. Na Figura 2b, o item
G
é incluído na pilha. De acordo com a definição, só existem um local na pilha onde ele
pode ser incluído – no topo. Agora, o primeiro elemento da pilha é
G
. Com a
movimentação da imagem pelos quadros
c
,
d
e
e
, os itens
H
,
I
e
J
são sucessivamente
incluídos na pilha. Entretanto, a partir do quadro
f
, a pilha começa a diminuir, quando
primeiro
J
, depois
I
,
H
e
G
são sucessivamente removidos. Em cada etapa, o elemento
superior é removido, uma vez que uma eliminação só pode ser feita a partir do topo. O
item
G
não poderia ser removido da pilha antes dos itens
J
,
I
e
H
. Isso ilustra o atributo
A
B
C
D
F
mais importante de uma pilha, em que o último elemento inserido numa pilha é o
primeiro elemento eliminado. Sendo assim,
J
é eliminado antes de
I
porque
J
foi
inserido depois de
I
. Por essa razão, ocasionalmente uma pilha é chamada lista last-in,
first-out (LIFO ou UEPS, o último a entrar é o primeiro a sair). (PLT, pág87)
Entre os quadros
j
e
k
, a pilha parou de diminuir e começou a crescer novamente, com a
inclusão do item
K
. Entretanto, esse crescimento tem vida curta, porque a pilha se reduz
a apenas três itens no quadro
n
.
Observe que não há como distinguir entre o quadro
a
e o quadro
i
, examinando o estado
da pilha nas duas ocorrências. Em ambos os casos, a pilha contém os mesmos itens, na
mesma ordem, e apresenta o mesmo topo. Não existe um registro do fato de que quatro
itens tenham sido incluídos e eliminados na pilha, nesse ínterim. De modo semelhante,
não há como distinguir entre os quadros
d
e
f
, ou
j
e
l
. Se for necessário um registro dos
itens intermediários que passaram pela pilha, esse registro deverá ser mantido em outro
lugar; ele não existe dentro da própria pilha.
Na realidade, apresentamos uma visão estendida do que é realmente observado numa
pilha. A verdadeira imagem de uma pilha é dada por uma visualização de cima para
baixo, em vez de por uma visão em perfil, de fora para dentro. Sendo assim, na Figura
2, não existe uma diferença perceptível entre os quadros
h
e
o
. Em cada caso, o
elemento posicionado no topo é
G
. Embora a pilha no quadro
h
e a pilha no quadro o
não sejam iguais, a única maneira de determinar esse fato é removendo todos os
elementos das duas pilhas e comparando-os individualmente. Mesmo que tenhamos
observado perfis laterais de pilhas para simplificar nosso entendimento, deve-se
observar que o fizemos arbitrariamente e que não há uma possibilidade real de existir tal
imagem. (PLT, pág88)
A
B
C
D
E
F
topo
A
B
C
D
E
F
G
A
B
C
D
E
F
G
A
B
C
D
E
F
G
A
B
C
D
E
F
G
H
A
B
C
D
E
F
G
H
A
B
C
D
E
F
G
H
I
A
B
C
D
E
F
G
H
I
J
H
I
Figura 2. Um Filme de uma pilha (PLT, pág89)
Operações Primitivas
As duas mudanças que podem ser introduzidas numa pilha recebem nomes especiais.
Quando um item é incluído numa pilha, ele é
empilhado
sobre a pilha e, quando um
item é removido, ele é
desempilhado
. Em função de uma pilha
s
e um item
i,
executar a
operação
push(s, i)
incluirá o item
i
no topo da pilha
s
. De modo semelhante, a operação
pop(s)
removerá o elemento superior e o retornará como valor da função. Assim a
operação de atribuição (PLT, pág88):
i = pop(s);
remove o elemento posicionado no topo de
s
e atribui seu valor a
i
.
Por exemplo, se s for a pilha da Figura 2, executaremos a operação push(s, G), ao passar
do quadro a para o b. Em seguida, executamos sucessivamente as seguintes operações:
push (s, H); quadro(c)
push (s, I); quadro(d)
push (s, J); quadro(e)
pop(s); quadro(f);
pop(s); quadro(g);
pop(s); quadro(h);
pop(s); quadro(i);
pop(s); quadro(j);
push (s,K); quadro(k);
pop(s); quadro(l);
A
B
C
D
E
F
A
B
C
D
E
A
B
C
D
A
B
C
A
B
C
G
(i)
A
B
C
D
E
(j)
A
B
C
D
E
K
pop(s); quadro(m);
pop(s); quadro(n);
push(s, G); quadro(o);
Devido à operação push que adiciona elementos a uma pilha, uma pilha é as vezes lista
pushdown.
Não existe um limite máximo para o número de itens que podem ser mantidos numa
pilha porque a definição não especifica quantos itens são permitidos no conjunto.
Empilhar outro item numa pilha simplesmente produz um conjunto maior de itens.
Entretanto, se uma pilha contiver um só item e ele for desempilhado, a pilha resultante
não conterá itens e será chamada
pilha vazia.
Embora a operação
push
seja aplicável a
qualquer pilha, a operação pop não pode ser aplicada à pilha vazia porque essa pilha não
tem elementos para desempilhar. Portanto, antes de aplicar o operador pop a uma pilha,
precisamos verificar se ela não está vazia (PLT, pág90).
Representando Pilhas em C
Uma pilha é um conjunto ordenado de itens, e C já contém um tipo de dado que
representa um conjunto ordenado de itens: o vetor. Portanto, sempre que a solução de
um problema exigir o uso de uma pilha, é tentador iniciar um programa declarando uma
variável pilha como um vetor. Contudo, uma pilha e um vetor são duas entidades
totalmente diferentes. O número de elementos num vetor é fixado e atribuído pela
declaração feita para o vetor. Em termos gerais, o usuário não pode alterar esse número.
Por outro lado, uma pilha é fundamentalmente um objeto dinâmico cujo tamanho está
sempre mudando à medida que os itens são desempilhados e empilhados (PLT, pág98).
Entretanto, mesmo que um vetor não seja uma pilha, ele pode ser a casa de uma pilha.
Ou seja, um vetor pode ser declarado suficientemente grande para armazenar o tamanho
máximo da pilha. Durante a execução do programa, a pilha pode aumentar e diminuir
dentro do espaço reservado para ela. Uma extremidade do vetor é o final fixo da pilha,
enquanto o topo da pilha se desloca constantemente, com a eliminação e a inclusão de
itens. Dessa forma, é necessário outro campo que, em cada ponto da execução do
programa, rastreie a atual posição do topo da pilha.
Implementação de uma Pilha de Números Inteiros
O programa a seguir, implementa uma pilha de números inteiros, implementando as
operações
push()
,
pop()
,
imprime_pilha1()
,
imprime_pilha2()
e
busca().
A operação
push
insere elementos no topo da pilha, a função
pop
remove o elemento do topo, a
função
imprime_pilha1()
imprime os elementos da base até o topo da pilha, a função
imprime_pilha2()
imprime os elementos do topo até a base da pilha e a função busca,
procura os elementos na pilha.
#include <stdio.h> #include <conio.h> #include <stdlib.h> #define MAX 5
int valor[MAX]; int topo;
int inicio; }; struct pilha p;
void push() {
int x;
if(p.topo == MAX) {
printf("\nPilha cheia!"); exit(1);
} else {
printf("\nDigite uma valor: "); scanf("%i",&x);
p.valor[p.topo] = x; p.topo++;
printf("Elemento %i inserido com sucesso!",x); }
getch(); }
void pop() {
if(p.topo == 0) {
printf("\nPilha Vazia!"); exit(1);
} p.topo--;
printf("Elemento %i removido com sucesso!",p.valor[p.topo]); getche();
}
void imprime_pilha1() {
int v; int i; i = p.inicio; while(i != p.topo) {
v = p.valor[i];
printf("\nElemento %i da pilha eh: %i",i,v); i++;
} getche(); }
void imprime_pilha2() {
int v; int i; i = p.topo-1; while(i != -1) {
v = p.valor[i];
} getche(); }
void busca() {
bool encontrou; int valor_procurado; int v;
int i; i = p.inicio;
printf("Entre com o valor que deseja buscar: "); scanf("%i",&valor_procurado);
while(i != p.topo) {
v = p.valor[i];
if(v == valor_procurado) {
printf("Elemento %i encontrado na posicao %i",p.valor[i],i); encontrou = 1;
} i++; }
if(encontrou != 1)
printf("Elemento %i nao encontrado",valor_procurado); getche();
}
main() {
p.inicio = p.topo = 0; int op;
while(op != 6) {
system("cls");
printf("Manipulacao de Pilha Estatica"); printf("\nDigite 1 para Insercao (PUSH)");
printf("\nDigite 2 para Imprimir a Pilha (BASE AO TOPO)"); printf("\nDigite 3 para Imprimir a Pilha (TOPO A BASE)"); printf("\nDigite 4 para Remover (POP)");
printf("\nDigite 5 para Buscar Elemento"); printf("\nDigite 6 para Sair");
printf("\nDigite a opcao desejada: "); scanf("%i",&op);
switch(op) {
case 1: push(); break; case 2: imprime_pilha1(); break; case 3: imprime_pilha2(); break; case 4: pop(); break; case 5: busca(); break; case 6: exit(1);
default: printf("\nEntre com uma opcao valida!"); }
Implementação de uma Pilha de Números Inteiros (com ponteiros)
A implementação abaixo, é a mesma apresentada anteriormente, com o uso de
ponteiros.
#include <stdio.h> #include <conio.h> #include <stdlib.h> #define MAX 5
struct pilha {
int valor[MAX]; int topo;
int inicio; };
void inicializaPilha(struct pilha *p) {
p->inicio = p->topo = 0; }
void push(struct pilha *p, int x) {
if(p->topo == MAX) {
printf("\nPilha cheia!"); exit(1);
} else {
p->valor[p->topo] = x; p->topo++;
printf("Elemento %i inserido com sucesso!",x); }
getch(); }
int pop(struct pilha *p) {
if(p->topo == 0) {
printf("\nPilha Vazia!"); exit(1);
}
p->topo--;
return p->valor[p->topo]; getche();
}
void imprime_pilha1(struct pilha *p) {
int v; int i;
i = p->inicio; while(i != p->topo) {
v = p->valor[i];
i++; } getche(); }
void imprime_pilha2(struct pilha *p) {
int v; int i;
i = p->topo-1; while(i != -1) {
v = p->valor[i];
printf("\nElemento %i da pilha eh: %i",i,v); i--;
} getche(); }
void busca(struct pilha *p) {
bool encontrou; int valor_procurado; int v;
int i;
i = p->inicio;
printf("Entre com o valor que deseja buscar: "); scanf("%i",&valor_procurado);
while(i != p->topo) {
v = p->valor[i];
if(v == valor_procurado) {
printf("Elemento %i encontrado na posicao %i",p->valor[i],i); encontrou = 1;
} i++; }
if(encontrou != 1)
printf("Elemento %i nao encontrado",valor_procurado); getche();
}
main() {
struct pilha p; inicializaPilha(&p); int op;
int x;
int num_recuperado; while(op != 6) {
system("cls");
printf("Manipulacao de Pilha Estatica"); printf("\nDigite 1 para Insercao (PUSH)");
printf("\nDigite 2 para Imprimir a Pilha (BASE AO TOPO)"); printf("\nDigite 3 para Imprimir a Pilha (TOPO A BASE)"); printf("\nDigite 4 para Remover (POP)");
printf("\nDigite 6 para Sair"); printf("\nDigite a opcao desejada: "); scanf("%i",&op);
switch(op) {
case 1:
printf("\nDigite uma valor: "); scanf("%i",&x);
push(&p, x); break;
case 2:
imprime_pilha1(&p); break;
case 3:
imprime_pilha2(&p); break;
case 4:
num_recuperado = pop(&p);
printf("\nElemento %i recuperado!",num_recuperado); getch();
break; case 5:
busca(&p); break;
case 6: exit(1); default:
printf("\nEntre com uma opcao valida!"); }
} }
Implementação de uma Pilha de Livros (com Ponteiros)
O programa abaixo implementa as funções push() e pop() para uma Pilha de Livros.
/* Pilha de Livros */
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <string.h>
#define MAX 5
struct no {
char nome[100]; };
struct pilha {
struct no nos[MAX]; int inicio;
int topo; int quantos; };
{
p->inicio = p->quantos = 0; p->topo = -1;
}
void push(struct pilha *p, char nome[30]) {
if(p->quantos == MAX) {
printf("\nPilha Cheia"); exit(1);
} else {
p->topo++; }
strcpy(p->nos[p->topo].nome, nome); p->quantos++;
printf("\n%s inserido com sucesso!",nome); getche();
}
void pop(struct pilha *p, char nome[30]) {
if(p->quantos == 0) {
printf("\nFila vazia"); exit(1);
} else {
strcpy(nome, p->nos[p->topo].nome); p->quantos--;
p->topo--; }
printf("\n%s removido com sucesso!"); getche();
}
main() {
struct pilha p; inicializaPilha(&p); char nome[100];
int op; while(op != 5) {
system("cls");
printf("Manipulacao de Pilha Estatica de Livros"); printf("\nDigite 1 para Insercao (PUSH)");
printf("\nDigite 2 para Remover (POP)"); printf("\nDigite 3 para Sair");
printf("\nDigite a opcao desejada: "); scanf("%i",&op);
getc(stdin);
case 1:
printf("Digite o nome de um livro: "); gets(nome);
push(&p,nome); break; case 2:
pop(&p, nome); break;
case 3: exit(1);
default: printf("\nEntre com uma opcao valida!"); }
} }
Implementação Pilha Tenembaum
#include <stdio.h> #include <conio.h> #include <stdlib.h>
#define STACKSIZE 100
struct stack {
int top;
int items[STACKSIZE]; };
void inicializaPilha(struct stack *ps) {
ps->top = -1; }
int empty(struct stack *ps) {
if(ps->top == -1) return (1); else
return (0); }
void push(struct stack *ps, int x) {
if(ps->top == STACKSIZE-1) {
printf("%s","Estouro e Pilha"); exit(1);
} else {
ps->items[++(ps->top)] = x; }
}
int pop(struct stack *ps) {
if(empty(ps)) {
exit(1); }
return (ps->items[ps->top--]); }
main() {
struct stack ps; inicializaPilha(&ps); int x;
int num_retorno; int op;
while(op != 3) {
system("cls");
printf("Manipulacao de Pilha Estatica Tenembaum"); printf("\nDigite 1 para Insercao (PUSH)");
printf("\nDigite 2 para Remover (POP)"); printf("\nDigite 3 para Sair");
printf("\nDigite a opcao desejada: "); scanf("%i",&op);
getc(stdin);
switch(op) {
case 1:
printf("Digite um valor inteiro: "); scanf("%i",&x);
push(&ps,x); break; case 2:
num_retorno = pop(&ps);
printf("O numero retornado eh %i",num_retorno); getch();
break; case 3: exit(1);
default: printf("\nEntre com uma opcao valida!"); }