Estruturas de Dados
Listas dinâmicas
1
28/01/2016
Listas dinâmicas
Quando o TAD Lista é implementado de forma estática,
corre-se o risco de sub/superdimensionamento do uso
da memória (arranjo alocado).
Para melhor gerenciar o uso de memória, ou seja, alocar
apenas a memória que for de fato utilizada, lança-se mão
do recurso de alocação dinâmica para implementar o
TAD lista, resultando nas chamadas listas dinâmicas.
Assim, quando for necessário inserir um elemento na
lista, basta alocar a quantidade de memória necessária e
referenciar a região alocada através de ponteiros. Sob o
mesmo raciocínio, ao remover um elemento da lista, a
região de memória ate então utilizada deve ser
devidamente desalocada.
Prof. Luciana Rocha Cardoso
3
Listas dinâmicas
O encadeamento da lista será feito, portanto,
por ponteiros. No caso de listas simplesmente
encadeadas, cada elemento referencia a região
de memória onde se encontra seu sucessor.
A seguir, é dada uma estrutura de dados em C++
para representar uma lista dinâmica de números
inteiros simplesmente encadeada.
Note que agora adicionaremos as funções
criaNodo e destroi para alocar espaço para um
nodo e desalocar todo o espaço ocupado pela
lista, respectivamente.
4 Prof. Luciana Rocha Cardoso
2
28/01/2016
struct NodoLista {
int info;
NodoLista* prox;
};
struct Lista {
NodoLista* primeiro;
int tam;
};
3
28/01/2016
4
28/01/2016
5
28/01/2016
6
28/01/2016
7
28/01/2016
...
// Inserir o elemento 6 depois do 4
insereFim( l1, criaNodo(6) );
// Inserir o elemento 0 na primeira posicao
insereInicio( l1, criaNodo(0) );
// Inserir o elemento 5 depois do 4
insere( l1, localiza(l1,4), criaNodo(5) );
imprime(l1);
cout<<"\nTamanho: "<<tamanhoLista(l1)<<"\n\n";
...
8
28/01/2016
Exercícios
1) Acrescente a implementação vista uma função
para inserir ordenadamente.
2) Faça as funções que faltam.
9
28/01/2016
LSEDD
Mostrar códigos .
Pilhas dinâmicas
10
28/01/2016
Pilha dinâmica
O conceito de pilha na implementação a seguir será de
um ponteiro que sempre aponta para o nodo no topo da
pilha.
Alem disto, cada nodo terá um apontador que indicara o
nodo imediatamente abaixo na pilha.
Pilha dinâmica
Ao empilhar um novo
nodo, o topo passará a
apontar para este nodo e
o sucessor do novo nodo
será o antigo topo:
Ao desempilhar, o topo
passará a apontar para o
nodo imediatamente
abaixo do antigo topo.
11
28/01/2016
Pilha dinâmica
Passemos agora para uma implementação em C++
de uma pilha dinâmica de inteiros.
struct NodoPilha {
int info;
NodoPilha* prox;
};
struct Pilha {
NodoPilha* topo;
};
Pilha dinâmica
// Inicia a pilha como vazia
void fazPilhaVazia(Pilha& p) {
p.topo = NULL;
}
12
28/01/2016
Pilha dinâmica
// Aloca memoria para um nodo e retorna apontador
// para este. Se memoria cheia, retorna NULL
NodoPilha* criaNodo(int e) {
NodoPilha* aux;
aux = new NodoPilha;
if ( aux )
aux->info = e;
return aux;
}
void destroiNodo(NodoPilha* p) {
if ( p )
delete p;
}
Pilha dinâmica
// Empilha o nodo n na pilha
int empilha(Pilha& p, NodoPilha* n) {
if ( n != NULL ) {
n->prox = p.topo;
p.topo = n;
return 1;
}
return 0;
}
13
28/01/2016
Pilha dinâmica
// Retira o elemento que se encontra no topo
// da pilha e retorna um ponteiro para o
// mesmo
NodoPilha* desempilha(Pilha& p) {
// *** Fica como exercicio ***
}
// Retorna o ponteiro para o topo,
// sem desempilhar.
NodoPilha* obtemTopo(const Pilha& p) {
// *** Fica como exercicio ***
}
Pilha dinâmica
void imprime(Pilha* p) {
// *** Fica como exercicio ***
}
// Desaloca toda a memoria ocupada pelos
// nodos da pilha
void destroi(Pilha* p) {
// *** Fica como exercicio ***
}
14
28/01/2016
Pilha dinâmica
// Um pequeno programa para demonstrar o uso
void main () {
Pilha p;
NodoPilha* n;
fazPilhaVazia(p);
n = criaNodo(1); // Empilha o elemento 1
empilha(p,n);
n = criaNodo(2); // Empilha o elemento 2
empilha(p,n);
n = criaNodo(3); // Empilha o elemento 3
empilha(p,n);
imprime(p); // Resultado 3 2 1
...
29 Prof. Luciana Rocha Cardoso
Pilha dinâmica
...
n = desempilha(p);
if ( n ) {
cout<<"\nAntigo topo = "<<n->info<<"\n\n";// 3
destroiNodo(n);
}
imprime(p); // Resultado 2 1
n = obtemTopo(p);
if ( n != NULL )
cout<<"\nTopo = "<<n->info<<"\n\n";// Topo = 2
imprime(p); // Resultado 2 1
cout << "\n\n";
...
15
28/01/2016
Pilha dinâmica
...
n = criaNodo(4); // Empilha o elemento 4
empilha(p,n);
imprime(p); // Resultado 4 2 1
destroi(p);
}
Exercícios
Utilize a pilha que acabamos de ver para resolver os
exercícios abaixo:
1) Faca um programa em C++ para converter um numero
decimal em binário, utilizando uma pilha dinâmica de
inteiros para empilhar os restos das divisões por dois
necessárias para a conversão.
2) Escreva um programa que utilize uma pilha dinâmica
para verificar se expressões aritméticas estão com a
“parentetização” correta. Seu programa deve checar as
expressões para ver se cada "abre parênteses" possui um
"fecha parênteses" correspondente.
16
28/01/2016
Filas dinâmicas
Filas dinâmicas
Na versão dinâmica, o tipo que representa fila será
composto por um ponteiro para o inicio da fila e
outro para o final. Cada nodo terá um ponteiro que
referencia seu sucessor na fila.
17
28/01/2016
Filas dinâmicas
Ao enfileirar um novo nodo,
o ponteiro fim passará a
apontar para este nodo e o
sucessor do novo nodo será
NULL:
Ao desenfileirar, o ponteiro
inicio passara a apontar para
o sucessor do nodo
desenfileirado:
Filas dinâmicas
Passemos agora para uma implementação em C++
de uma fila dinâmica de inteiros.
struct NodoFila {
int info;
NodoFila* prox;
};
struct Fila {
NodoFila* inicio;
NodoFila* fim;
};
18
28/01/2016
Filas dinâmicas
// Inicia a fila como vazia
void fazFilaVazia(Fila& f) {
f.inicio = NULL;
f.fim = NULL;
}
// retornaV se fila vazia e F c.c.
int filaVazia(const Fila& f) {
return ( f.inicio == NULL && f.fim == NULL);
}
Filas dinâmicas
// Aloca memoria para um nodo e retorna apontador
// para este. Se memoria cheia, retorna NULL
NodoFila* criaNodo(int e) {
NodoFila* aux = new NodoFila;
if ( aux != NULL )
aux->info = e;
return aux;
}
void destroiNodo(NodoFila* p) {
if( p ) delete p;
}
19
28/01/2016
Filas dinâmicas
// Enfileira nodo apontado por n
int enfileira(Fila& f, NodoFila* n) {
if ( n != NULL ) {
n->prox = NULL;
// Verifica se a fila esta vazia
if ( filaVazia(f) ) {
f.inicio = f.fim = n;
}
else {
f.fim->prox = n;
f.fim = n;
}
return 1;
}
return 0;
}
39 Prof. Luciana Rocha Cardoso
Filas dinâmicas
// Retorna o apontador para o elemento que esta
// na frente da fila, sem desenfileira-lo
NodoFila* frenteFila(const Fila& f) {
return f->inicio;
}
NodoFila* desenfileira(Fila& f) {
// *** Fica como exercicio ***
}
void destroi(Fila& f) {
// *** Fica como exercicio ***
}
20
28/01/2016
Filas dinâmicas
void main () {
Fila f;
NodoFila* n;
fazFilaVazia(f);
n = criaNodo(1);
enfileira(f,n); // Enfileira 1
n = criaNodo(2);
enfileira(f,n); // Enfileira 2
n = criaNodo(3);
enfileira(f,n); // Enfileira 3
imprime(f); // Resultado 1 2 3
...
Filas dinâmicas
...
n = frenteFila(f);
if ( n != NULL ) {
cout<<"\nFrente="<<n->info<<"\n";//Frente = 1
}
n = desenfileira(f);
if ( n != NULL ){
cout<<"\nFrente antiga="<<n->info<<"\n"; // 1
destroiNodo(n);
}
imprime(f); // Resultado 2 3
...
21
28/01/2016
Filas dinâmicas
...
n = criaNodo(4);
enfileira(f,n); // Enfileira 4
imprime(f); // Resultado 2 3 4
n = frenteFila(f);
if ( n != NULL ) {
cout<<"\nFrente="<<n->info<<"\n";// Frente
=2
}
destroi(f);
}
Exercícios
1) Desenvolva um programa em C++, utilizando fila
dinâmica, que permita gerir uma pista para decolagem
de aviões de um aeroporto. Para o correto
funcionamento desta pista e necessário que sejam
implementadas as seguintes funcionalidades:
• No de aviões a espera de decolar.
• Decolagem de um avião.
• Entrada de um novo avião para decolar.
• Listar todos os aviões (nome e numero) a espera de
decolar.
• Listar as características (nome e numero) do próximo
avião a decolar.
22
28/01/2016
Exercícios
2) Faca o exercício abaixo, ja solicitado quando vimos
filas e pilhas estáticas, mas desta vez utilize fila e
pilha dinâmicas.
Suponha que tenhamos um programa em C++ para
armazenar uma fila de pessoas (nome das pessoas).
Tendo em vista o ditado "os últimos serão os primeiros",
crie uma função que pegue a fila e a inverta, ou seja,
quem estava no início da fila vai passar a estar no final e
quem estava no final passará a estar no início. Utilize
uma pilha para esta inversão. Veja, portanto, que você
terá que adaptar as filas e pilhas que vimos para
acomodarem strings (os nomes).
Exercícios
3) Pesquise e descreve a estrutura de dados hash.
23