O documento apresenta uma discussão sobre implementação de pilhas e filas dinâmicas utilizando listas encadeadas. É explicado como utilizar a estrutura de lista encadeada para representar pilhas e filas de forma dinâmica, codificando as operações necessárias como empilhar, desempilhar, enfileirar e desenfileirar.
2. Sobre mim
Sérgio Souza Costa
Professor - UFMA
Doutor em Computação Aplicada (INPE)
prof.sergio.costa@gmail.com
https://sites.google.com/site/profsergiocosta/home
http://www.slideshare.net/skosta/presentations?order=popular
https://twitter.com/profsergiocosta
http://gplus.to/sergiosouzacosta
3. Pilha Dinâmica
• A pilha que codificamos anteriormente era estática,
dado que utilizava vetores.
• Agora que já codificamos a lista encadeada,
podemos utiliza-la para codificar nossa pilha
dinâmica.
• Antes de prosseguir, pense como seria este código.
4. Pilha Dinâmica
• A estrutura da pilha é bem simples, precisando
apenas de uma lista para armazenar os elementos.
Como a lista é dinâmica, a pilha também é dinâmica.
typedef struct {
Lista* l;
} Pilha;
5. Pilha dinâmica
• Agora precisamos codificar o tipo abstrato lista,
codificando as mesmas operações que foram
codificadas para a pilha estática.
–
–
–
–
–
–
Pilha* criaPilha ();
int pilhaVazia();
void empilha (Pilha *p, int x);
int desempilha();
int topo();
int pilhaCheia (Pilha *p);
Não é necessária. Por que ?
6. Operações da Pilha
1.
2.
3.
Alocamos a área de memória da pilha.
Inicializamos a lista da pilha com lista vazia.
Retornamos a pilha.
Pilha* criaPilha (){
1.
Pilha* p =
(Pilha*)malloc (sizeof(Pilha));
2.
p->l = Vazia();
return p;
3.
}
7. Operações da pilha
• Verificar se a pilha esta vazia é verificar se a lista esta
vazia.
int pilhaVazia (Pilha* p) {
return p->l == Vazia();
}
8. Operações da pilha
• Empilhar um elemento X na pilha é adicioná-lo na
lista.
void empilha (Pilha *p, int x) {
p->l = Cons (x, p->l);
}
9. Operações da pilha
• Retornar o elemento do topo é retornar o elemento
que está na cabeça da lista, ou seja, o último
adicionado.
int topo (Pilha* p) {
return primeiro(p->l);
}
10. Operações da pilha
• A operação desempilha, além de retornar o
elemento do topo da pilha, precisa removê-lo.
int desempilha (Pilha* p) {
int x = topo (p);
p->l = resto(p->l);
return x;
}
Remove o
elemento da
cabeça da pilha
11. Será que posso codificar uma fila dinâmica usando a lista
encadeada que já tenho pronta? O que vocês acham ?
12. A fila difere da pilha pelo fato de que na pilha inserimos e
removemos de uma mesma extremidade. Na fila eu insiro
em uma extremidade e remove em outra.
14. Então, preciso criar mais uma operação para a lista.
Qual seria ?
InsereFim, que irá inserir o elemento no fim da lista.
15. Codificando
• Adicionando a operação que insere um elemento no
fim da lista.
Lista* insereFim (int x, Lista* l) {
Lista* aux;
if (l == Vazia()) return Cons (x, l);
aux = l;
while (aux ->resto != Vazia())
aux = aux ->resto;
aux->resto = Cons (x, Vazia());
return l;
}
16. Codificando
• Adicionando a operação que insere um elemento no
fim da lista.
Lista* insereFim (int x, Lista* l) {
Lista* aux;
if (l == Vazia()) return Cons (x, l);
aux = l;
while (aux ->resto)
aux = aux ->resto;
aux->cauda = Cons (x, Vazia());
return l;
}
Se minha lista é
vazia, então já estou
no fim da lista.
17. Codificando
• Adicionando a operação que insere um elemento no
fim da lista.
Lista* insereFim (int x, Lista* l) {
Lista* aux;
if (l == Vazia()) return Cons (x, l);
aux = l;
while (aux ->resto)
aux = aux ->resto;
aux->cauda = Cons (x, Vazia());
return l;
}
Ou preciso percorrer
a lista até o fim.
18. Codificando
• Adicionando a operação que insere um elemento no
fim da lista.
Lista* insereFim (int x, Lista* l) {
Lista* aux;
if (l == Vazia()) return Cons (x, l);
aux = l;
while (aux ->resto)
aux = aux ->resto;
aux->resto = Cons (x, Vazia());
return l;
}
Então posso
adicioná-lo ao fim da
lista.
19. Não entendi muito bem, este código, ele é iterativo, os
que tinha feito até então era todos recursivo.
20. Vou agora usar uma
representação gráfica
comum para lista. Ela pode
te ajudar a entender este
código
28. L
5
6
7
cauda, é eferido também como
próximo
Adicionar no fim é
adicionar um novo nó
neste ponto
Ponteiro nulo,
representa lista
vazia.
29. L
5
6
7
resto, referido também como
próximo
Adicionar no fim é
adicionar um novo nó
neste ponto
Ponteiro nulo,
representa lista
vazia.
Então, percorremos a lista até que o
resto seja nula, ou seja, não tenha
mais nó. Então adicionamos um novo
nó neste ponto.
30. L
5
6
7
Volte ao código e releiao buscando entender
melhor o seu
funcionamento antes de
prosseguir.
.
Ponteiro nulo,
representa lista
cauda, referido também como
vazia.
próximo
Adicionar no fim é
adicionar um novo nó
neste ponto
Então, percorremos a lista até que a
cauda seja nula, ou seja, não tenha
mais nó. Então adicionamos um novo
nó neste ponto.
32. Codificando
• A estrutura vai ser similar a da pilha, apenas com um
atributo que é a lista:
typedef struct {
Lista* l;
}Fila;
33. Codificando
• O construtor também é similar ao da pilha.
Fila* criaFila () {
Fila* f =
(Fila*) malloc (sizeof(Fila));
f->l = Vazia();
return f;
}
34. Codificando
• A desenfileira é similar a desempilha.
int desenfileira (Fila* f) {
int x = primeiro (f->l);
f->l = resto (f->l);
return x;
}
35. Codificando
• Na enfileira chamamos a operação que insere um
elemento no fim da lista.
void enfileira (Fila* f, int x) {
f->l = insereFim(x,f->l);
}