Escolar Documentos
Profissional Documentos
Cultura Documentos
.......................................
Universidade Federal do Semiárido – Mossoró, RN
Ciência da Computação, 2011.1
.......................................
Tibérius O. Bonates – tbonates@ufersa.edu.br
1 Introdução
Pilhas estão entre as estruturas de dados mais simples, e provavelmente mais frequentes, em Com-
putação, juntamente com filas e listas. Uma estrutura de pilha oferece as operações de empilhar
(adicionar) e desempilhar (remover) um elemento, análogas às operacoes de empilhar um livro sobre
uma pilha de livros, ou desempilhar o livro que se encontra na posição mais alta da pilha. Conforme
veremos nos exemplos e exercı́cios deste capı́tulo, pilhas surgem naturalmente em diversas aplicações.
Seja E um conjunto de elementos quaisquer (números inteiros, por exemplo), alguns dos quais
desejamos armazenar para posterior acesso ou modificação. Uma pilha de elementos de E é uma
estrutura que armazena uma sequência de objetos provenientes de E. A ideia de sequência entre os
objetos é essencial na definição de uma pilha, pois a ordem dos elementos nesta sequência determina
a ordem em que os elementos poderão ser acessados posteriormente: os elementos inseridos na pilha
só podem ser recuperados de acordo com a ordem inversa de sua inserção, tal como na pilha de livros
utilizada como analogia. É importante destacar que, de acordo com nossa definição, uma pilha pode
conter elementos repetidos.
Seja P uma estrutura de dados pilha. Se P não for vazia, o elemento que foi adicionado mais
recentemente a P é denominado de topo de P . Caso contrário, dizemos que P não possui topo.
Durante uma operação empilhar aplicada sobre P , um novo elemento x é adicionado a P e passa
a ser o novo topo da pilha. Durante uma operação desempilhar aplicada sobre P , três objetivos
principais são atingidos: (i) o elemento y que era o topo da pilha é removido de P ; (ii) caso P ainda
possua algum elemento, aquele que foi adicionado mais recentemente a P passa a ser o novo topo
de P ; e (iii) o elemento y é retornado ao código que invocou a operação desempilhar.
Em resumo, podemos dizer que o seguinte conjunto de regras define as operações de empil-
har/desempilhar sobre uma pilha P :
(ii) ao empilhar um elemento x, este elemento passa a ser o topo da pilha;
(ii) ao desempilhar o topo da pilha (assumindo que a pilha não se encontra vazia), o elemento
(topo) é removido de P e retornado ao código que requisitou a operação de desempilhar, e a
informação sobre o topo de P é atualizada;
(iii) uma vez que o elemento x foi inserido na pilha, ele somente será removido se uma operação
de desempilhar for realizada enquanto x for o topo de P .
1
Exemplo 1.1 Considere uma pilha de números inteiros P contendo três elementos, conforme mos-
trado na Figura 1(a). Cada elemento é representado por um retângulo que contém o número inteiro
em questão. O topo da pilha é apontado por uma seta. A Figura 1(b) ilustra o resultado da operação
de desempilhar sobre a pilha da Figura 1(a). Similarmente, a Figura 1(c) mostra o resultado das
aplicações sucessivas das operações de empilhar o elemento 5 e empilhar o elemento 8 sobre a pilha
da Figura 1(b).
(a) Pilha original (b) Após operação de desempilhar (c) Após operações de empilhar
É importante reforçar a ideia de que apenas um dos objetos armazenados na pilha está realmente
acessı́vel em um determinado momento, e pode ser obtido prontamente por meio de uma operação de
desempilhar. Este fato pode parecer uma limitação artificial e desnecessária, mas a realidade é que a
estrutura de pilha pode ser muito conveniente para assegurar que o acesso a um determinado conjunto
de dados aconteça de acordo com uma ordem bastante especı́fica, garantindo que o processamento
dos dados armazenados se dará na ordem desejada. Como exemplo, considere a funcionalidade tı́pica
de um editor de texto, discutida a seguir no Exemplo 1.2.
2
struct Pilha {
int tamanho;
int topo;
int * dados;
};
O seguinte código pode ser utilizado para se iniciar uma variável do tipo Pilha, passada como
parâmetro, por referência:
void iniciar(Pilha &p, int tamanho) {
p.tamanho = tamanho;
p.topo = -1; // convencao: topo -1 significa que a pilha esta’ vazia
p.dados = new int[p.tamanho]; // vetor de dados alocado dinamicamente
}
3
uma pilha vazia (ou seja, topo é diferente de −1). Como a função deve retornar o elemento que
ocupava o topo da pilha, é preciso definir o valor que será retornado caso a pilha esteja vazia. Uma
convenção bastante utilizada em tais casos é a de retornar um valor que não esteja no domı́nio dos
valores possı́veis para a pilha. Em nossa implementação, iremos convencionar um valor de retorno
igual a -1 para sinalizar que a pilha estava vazia e nada foi desempilhado.
Caso a pilha possua algum elemento armazenado, a função deve remover o elemento do topo
e atualizar a informação sobre a posição do elemento que se encontrará no topo após a operação
ser concluı́da. Em nossa implementação por vetor, a remoção do elemento no topo é desnecessária,
sendo suficiente atualizar o valor da variável topo. É possı́vel que a pilha se torne vazia após a
operação.
if (! vazia(P)) {
int valor = desempilhar(P);
// processamento do dado...
}
Outra maneira, talvez mais elegante, de se implementar a função desempilhar seria conforme
descrito a seguir. A função retornaria um valor booleano, informando se houve ou não o desempi-
lhamento. Além disso, a função receberia um parâmetro inteiro por referência, o qual seria utilizado
para armazenar o valor que se encontrava no topo da pilha antes do desempilhamento. O seguinte
código ilustra um uso seguro desta implementação alternativa:
int valor;
if (desempilhar(P, valor)) {
// processamento do dado...
}