SlideShare uma empresa Scribd logo
1 de 75
Baixar para ler offline
TAD Listas Estáticas
Encadeadas
Profa. Maria Carolina Monard
Implementações C de Ígor Assis Braga
Material Parcial do Prof. Gustavo Batista
2
Listas Estáticas Encadeadas
Vamos apresentar uma outra possibilidade de
implementação do TAD Listas.
Essa implementação é chamada de estática
encadeada
◼ Estática por utilizar vetores;
◼ Encadeada por manter uma estrutura de
encadeamento que difere da estrutura seqüencial.
Essa implementação é menos comum do que as
demais, mas bastante interessante por motivos
didáticos.
3
Listas Estáticas Encadeadas
Listas Estáticas Encadeadas simulam o conceito
de ponteiros:
◼ Esses “ponteiros” armazenam posições do vetor ao
invés de endereços de memória;
◼ Chamamos esses “ponteiros” de cursores.
A princípio, todas as posições do vetor estão
disponíveis, isso é representado da seguinte
maneira usando o cursor dispo em listas estáticas
simplesmente encadeadas...
4
Lista Dispo
2
?
1 2 3 4
Primeiro: -1 Dispo: 1
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
A operação de criar a lista
é responsável por realizar
essa inicialização.
Qual é a complexidade
dessa operação?
5
Lista Dispo
2
?
1 2 3 4
Primeiro: -1 Dispo: 1
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
A operação de criar a lista
é responsável por realizar
essa inicialização.
Qual é a complexidade
dessa operação?
6
Lista Dispo
2
?
1 2 3 4
Primeiro: -1 Dispo: 1
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
A operação de criar a lista
é responsável por realizar
essa inicialização.
Qual é a complexidade
dessa operação? O(n).
7
Definição de Tipos
#define MAX_TAM 300
#define NAO_ENCONTRADO -1
typedef int TipoChave;
typedef struct {
TipoChave chave;
/* Outros Campos */
} TipoItem;
typedef struct {
TipoItem item;
int prox;
} TipoNo;
8
Definição de Tipos
typedef struct TipoLista {
TipoNo no[MAX_TAM];
int primeiro;
int dispo;
} *TipoLista;
9
Observar...
Lembrar que na estrutura de dados o
primeiro elemento da lista encontra-se
inicialmente na posião 0 (zero)
10
Cria lista
/* Pré-condição: nenhuma;
Pós-condição: retorna uma lista
vazia. */
TipoLista IniciaLista() {
.......
}
11
Cria lista
/* Pré-condição: nenhuma;
Pós-condição: retorna uma lista
vazia. */
TipoLista IniciaLista() {
int i;
TipoLista L = malloc(sizeof(struct
TipoLista));
if(L != NULL) {
L->primeiro = -1;
L->dispo = 0; /* segue... */
12
Cria lista
for(i = 0; i < MAX_TAM - 1; i++) {
L->no[i].prox = i + 1;
}
assert(i == MAX_TAM - 1); /* não é
realmente necessária. Útil para
debug */
L->no[i].prox = -1;
}
return L;
}
13
assert(<exp> )
assert(), definida em assert.h, aborta a
execução do programa se a expressão
<exp> vale 0 (zero). Caso contrário,
assert() não faz nada
Caso <exp> valer 0 (zero), escreve
informação do erro -- o formato dessa
informação depende do compilador
14
assert(<exp> )
assert() geralmente é usada para ajudar a
verificar se um programa está operando
corretamente. A expressão <exp> deve
ser planejada de forma a que ela seja
verdadeira (diferente de 0) somente
quando não ocorre nenhum erro
Não é necessário remover assert() do
código fonte após o programa ter sido
depurado
15
Destroi lista
/* Pré-condição: a lista já está
iniciada;
Pós-condição: libera memória
ocupada pela lista. */
void DestroiLista(TipoLista L) {
free(L);
}
16
Inserção na primeira posição
A operação de inserção deve ser realizada
em dois passos:
◼ Recuperar a posição disponível;
◼ Inserir o elemento, atualizando os cursores
primeiro e prox.
Vamos simular a inserção do valor 7...
17
Inserção na primeira posição
2
?
1 2 3 4
Primeiro: -1 Dispo: 1
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção do valor 7 no
início da lista (vazia).
Qual é a complexidade da
operação de inserção no
início da lista?
18
Inserção na primeira posição
2
?
1 2 3 4
Primeiro: 1 Dispo: 1
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção do valor 7 no
início da lista (vazia)..
Qual é a complexidade da
operação de inserção no
início da lista?
19
Inserção na primeira posição
2
?
1 2 3 4
Primeiro: 1 Dispo: 2
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção do valor 7 no
início da lista (vazia).
Qual é a complexidade da
operação de inserção no
início da lista?
20
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 1 Dispo: 2
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção do valor 7 no
início da lista (vazia).
Qual é a complexidade da
operação de inserção no
início da lista?
21
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 1 Dispo: 2
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção do valor 7 no
início da lista (vazia).
Qual é a complexidade da
operação de inserção no
início da lista? O(1)
22
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 1 Dispo: 2
3
? 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção de um segundo
valor, 4, no início da lista
(não vazia).
23
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 2 Dispo: 3
1
4 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção de um segundo
valor, 4, no início da lista
(não vazia).
24
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 2 Dispo: 3
1
4 4
? 5
? -1
?
5
Legenda:
Chave Prox
Inserção de um segundo
valor, 4, no início da lista
(não vazia).
Qual é a complexidade da
operação de inserção no
início da lista com n
elementos? O(1)
25
Inserção na primeira posição
Uma situação especial é a inserção de um
elemento quando a lista somente possui
uma posição livre.
Vamos ver um exemplo disso...
26
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 4 Dispo: 5
1
4 2
3 3
9 -1
?
5
Legenda:
Chave Prox
Inserção do valor 3
quando somente existe
uma posição livre.
27
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 5 Dispo: -1
1
4 2
3 3
9 4
3
5
Legenda:
Chave Prox
Inserção do valor 3
quando somente existe
uma posição livre.
28
Inserção na primeira posição
-1
7
1 2 3 4
Primeiro: 5 Dispo: -1
1
4 2
3 3
9 4
3
5
Legenda:
Chave Prox
Inserção do valor 3
quando somente existe
uma posição livre.
29
Lista Cheia e Vazia
Dessa forma, podemos estipular regras
para verificar se uma lista está cheia ou
vazia:
◼ Lista Vazia: Primeiro = -1;
◼ Lista Cheia: Dispo = -1.
30
Lista cheia
/* Pré-condição: a lista já está
iniciada;
Pós-condição: retorna 1 se a
lista estiver cheia e 0 caso-
contrário. */
int ListaCheia(TipoLista L) {
.............
}
31
Lista cheia
/* Pré-condição: a lista já está
iniciada;
Pós-condição: retorna 1 se a
lista estiver cheia e 0 caso-
contrário. */
int ListaCheia(TipoLista L) {
if(L->dispo == -1) {
return 1;
} else {
return 0;
}
}
32
Lista vazia
/* Pré-condição: a lista já está
iniciada;
Pós-condição: retorna 1 se a
lista estiver vazia e 0 caso-
contrário. */
int ListaVazia(TipoLista L) {
.............
}
33
Lista vazia
/* Pré-condição: a lista já está
iniciada;
Pós-condição: retorna 1 se a
lista estiver vazia e 0 caso-
contrário. */
int ListaVazia(TipoLista L) {
if(L->primeiro == -1) {
return 1;
} else {
return 0;
}
}
34
Inserir elemento (primeira
posição)
/* Pré-condição: a lista já está iniciada
e não está cheia;
Pós-condição: insere um elemento na
primeira posição. */
void InserePrimeiroLista(TipoLista L,
TipoItem elem) {
.................
}
35
Inserir elemento (primeira
posição)
/* Pré-condição: a lista já está iniciada
e não está cheia;
Pós-condição: insere um elemento na
primeira posição. */
void InserePrimeiroLista(TipoLista L,
TipoItem elem) {
int dispo = L->dispo;
L->no[dispo].item = elem;
L->dispo = L->no[dispo].prox;
L->no[dispo].prox = L->primeiro;
L->primeiro = dispo;
}
36
Inserção na última posição
3
7
1 2 3 4
Primeiro: 2 Dispo: 4
1
4 -1
10 5
? -1
?
5
Legenda:
Chave Prox
Deve percorrer a lista
para achar o último
elemento, inserir após ele
o novo elemento (seja 12)
e atualizar a estrutura
37
Inserção na última posição
3
7
1 2 3 4
Primeiro: 2 Dispo: 5
1
4 4
10 -1
12 -1
?
5
Legenda:
Chave Prox
Após inserir o novo
elemento 12
38
Inserir elemento (última posição)
/* Pré-condição: a lista já está iniciada
e não está cheia;
Pós-condição: insere um elemento na
última posição. */
void InsereUltimoLista(TipoLista L,
TipoItem elem) {
.................
}
39
Inserir elemento (última posição)
/* Pré-condição: a lista já está iniciada
e não está cheia;
Pós-condição: insere um elemento na
última posição. */
void InsereUltimoLista(TipoLista L,
TipoItem elem) {
int dispo = L->dispo;
int i = L->primeiro;
L->no[dispo].item = elem;
L->dispo = L->no[dispo].prox;
L->no[dispo].prox = -1; /* Segue... */
40
Inserir elemento (última posição)
if(i == -1) {/* lista de entrada vazia*/
L->primeiro = dispo;
} else {
do {
if(L->no[i].prox == -1) {/* ultimo
elemento da lista de entrada */
L->no[i].prox = dispo;
i = -1; /* para fim do loop*/
} else {
i = L->no[i].prox;
}
} while(i != -1);
}
}
41
Observação
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
4 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Esta instância da
estrutura representa a
lista (3, 4, 7, 9)
42
Observação
5
3
1 2 3 4
Primeiro: 1 Dispo: 4
3
7 -1
9 -1
? 2
4
5
Legenda:
Chave Prox
Essa lista (3, 4, 7, 9)
também é representada
por esta outra instância
da estrutura...
43
Observação
Nessa lista (3, 4, 7, 9) convencionamos que o
elemento 3 está na posição 0, 4 na
posição 1, 7 na posição 2 e assim por
diante
44
Observação
Após diversas inserções e remoções a lista
não estará com os elementos na seqüência
das posições do vetor.
Dessa forma, a pesquisa deve seguir a
partir do cursor Primeiro (elemento na
posição 0) e seguir os cursores Prox de
cada elemento incrementando em 1 o valor
da posição do elemento “visitado”.
45
Pesquisa
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
4 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Pesquisar por todos os
elementos na lista
46
Pesquisa
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
4 2
3 -1
9 4
7
5
Legenda:
Chave Prox
“visitado” posição
3 0
4 1
7 2
9 3
47
Pesquisa
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
4 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Pesquisa pela chave 4.
Aux: 3
48
Pesquisa
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
4 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Pesquisa pela chave 4.
Aux: 2
49
Pesquisa
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
4 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Pesquisa pela chave 4.
Deve retornar a posição.
Qual é a complexidade
dessa operação?
Aux: 2
50
Pesquisa
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
4 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Pesquisa pela chave 4.
Qual é a complexidade
dessa operação? O(n).
Aux: 2
51
Pesquisar elemento (por posição)
/* Pré-condição: a lista já está iniciada;
Pós-condição: retorna a posição do
elemento na lista, ou um valor especial
caso não exista. */
int PesquisaLista(TipoLista L, TipoChave
chave) {
................
}
52
Pesquisar elemento (por posição)
/* Pré-condição: a lista já está iniciada;
Pós-condição: retorna a posição do elemento na
lista, ou um valor especial caso não exista. */
int PesquisaLista(TipoLista L, TipoChave chave) {
int i = L->primeiro;
int achou = 0;
int posAtual = 0;
while((!achou) && (i != -1)) {
if(L->no[i].item.chave == chave) {
achou = 1;
} else {
i = L->no[i].prox;
posAtual++;
}
} /* segue... */
53
Pesquisar elemento (por posição)
if(achou) {
return posAtual;
} else {
return NAO_ENCONTRADO;
}
}
54
Remoção (por posição)
A remoção pode ser realizada por posição,
ou seja, um cursor para uma posição do
vetor deve ser informado.
Entretanto, é necessário que se conheça o
elemento anterior.
Dessa forma, a remoção é bastante similar
a realizada em listas ligadas.
É importante colocar o elemento liberado
na lista Dispo.
55
Remoção (por posição)
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
14 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Lista (3, 14, 7, 9)
Remoção do elemento na
posição 2 (i.e. o 3ro
elemento da lista que é o
elemento 7)
56
Remoção (por posição)
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
14 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Lista (3, 14, 7, 9)
Remoção do elemento na
posição 2 (elemento 7)
Aux: 3
57
Remoção (por posição)
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
14 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Lista (3, 14, 7, 9)
Remoção do elemento na
posição 2 (elemento 7)
Aux: 2
58
Remoção (por posição)
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
5
14 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Lista (3, 14, 7, 9)
Remoção do elemento na
posição 2 (elemento 7)
Aux: 2
59
Remoção (por posição)
-1
?
1 2 3 4
Primeiro: 3 Dispo: 1
4
14 2
3 -1
9 4
7
5
Legenda:
Chave Prox
Lista (3, 14, 7, 9)
Remoção do elemento na
posição 2 (elemento 7)
Atualização da lista
encadeada e...
Aux: 2
60
Remoção (por posição)
-1
?
1 2 3 4
Primeiro: 3 Dispo: 5
4
14 2
3 -1
9 1
?
5
Legenda:
Chave Prox
Remoção do elemento na
posição 2
Atualização da lista
encadeada e...
Atualização da lista Dispo
Aux: 2
61
Remoção (por posição)
-1
?
1 2 3 4
Primeiro: 3 Dispo: 5
4
14 2
3 -1
9 1
?
5
Legenda:
Chave Prox
Lista retornada (3, 14, 9)
Qual é a complexidade
essa operação? O(n)
62
Remover elemento (por posição)
/* Pré-condição: a lista já está
iniciada e uma posição válida da lista é
informada;
Pós-condição: o elemento na posição
fornecida é removido da lista. */
void RemoveDeLista(TipoLista L, int pos) {
..............
}
63
Remover elemento (por posição)
/* Pré-condição: a lista já está iniciada e
uma posição válida da lista é informada;
Pós-condição: o elemento na posição fornecida é
removido da lista. */
void RemoveDeLista(TipoLista L, int pos) {
int i;
int anterior;
int posAtual;
if(pos == 0) {/* remover 1ro elemento da lista*/
i = L->primeiro;
L->primeiro = L->no[L->primeiro].prox;
L->no[i].prox = L->dispo;
L->dispo = i;
} /* Segue...*/
64
Remover elemento (por posição)
} else {
i = L->no[L->primeiro].prox;
anterior = L->primeiro;
posAtual = 1;
while(posAtual != pos) {
anterior = i;
i = L->no[i].prox;
posAtual++;
}
L->no[anterior].prox = L->no[i].prox;
L->no[i].prox = L->dispo;
L->dispo = i;
}
}
65
TAD Lista
A seguir veremos a implementação do
TAD lista mas usando agora uma
estrutura estática na qual os
elementos da lista encontram-se
duplamente encadeados
66
Listas Duplamente Encadeadas
Os cursores na estrutura estática podem
ser utilizados para implementar listas
duplamente encadeadas.
Para isso basta manter um ponteiro ant
para um elemento anterior.
Variáveis auxiliares como nr_elementos e
ultimo ajudam nas operações de contar e
inserir na última posição, respectivamente,
e serão usadas nesta implementação.
67
Listas Duplamente Encadeadas
2
?
? 3
?
? 4
?
? -1
?
?
1 2 3 4
Primeiro: -1 NrElementos: 0 Ultimo: -1 Dispo: 1
Ant Chave Prox
Legenda: Lista vazia
68
Definição de Tipos
#define MAX_TAM 3
#define NAO_ENCONTRADO -1
typedef int TipoChave;
typedef struct {
TipoChave chave;
/* Outros Campos */
} TipoItem;
typedef struct {
TipoItem item;
int ant;
int prox;
} TipoNo;
69
Definição de Tipos
typedef struct TipoLista {
TipoNo no[MAX_TAM];
int primeiro;
int dispo;
int nrElementos;
int ultimo;
} *TipoLista;
70
Listas Duplamente Encadeadas
2
?
? 3
?
? 4
?
? -1
?
?
1 2 3 4
Primeiro: -1 NrElementos: 0 Ultimo: -1 Dispo: 1
Ant Chave Prox
Legenda: Inserir o valor 2 no início da lista.
O que deve ser feito?
71
Listas Duplamente Encadeadas
-1
2
-1 3
?
? 4
?
? -1
?
?
1 2 3 4
Primeiro: 1 NrElementos: 1 Ultimo: 1 Dispo: 2
Ant Chave Prox
Legenda:
Após a inserção do valor 2
no início da lista
72
Listas Duplamente Encadeadas
-1
2
-1 3
?
? 4
?
? -1
?
?
1 2 3 4
Primeiro: 1 NrElementos: 1 Ultimo: 1 Dispo: 2
Ant Chave Prox
Legenda:
Inserir o valor 4 no fim da lista.
O que deve ser feito?
73
Listas Duplamente Encadeadas
2
2
-1 -1
4
1 4
?
? -1
?
?
1 2 3 4
Primeiro: 1 NrElementos: 2 Ultimo: 2 Dispo: 3
Ant Chave Prox
Legenda:
Após a inserção do valor 4
no final da lista
74
Análise
A implementação estática encadeada compartilha
características comuns com as implementações
de listas com vetores e com ponteiros:
◼ Vetores:
 O número máximo de elementos deve ser
estipulado a priori.
◼ Ponteiros:
 As operações de inserção no início e em qualquer
posição e remoção em qualquer posição não
requerem o deslocamento de elementos.
75
Exercício (usando as
declarações de tipo definidas)
1. Implemente as operações do TAD lista
utilizando uma lista estática encadeada
simples.
2. Implemente as operações do TAD lista
utilizando uma lista estática encadeada
dupla.
3. Qual a complexidade dessas operações
utilizando lista estática encadeada
simples e dupla?

Mais conteúdo relacionado

Semelhante a Listas Estáticas Encadeadas usando linguagem C

Aula_02_-_Listas_com_Vetores-OOP_2011_2.ppt
Aula_02_-_Listas_com_Vetores-OOP_2011_2.pptAula_02_-_Listas_com_Vetores-OOP_2011_2.ppt
Aula_02_-_Listas_com_Vetores-OOP_2011_2.pptssuserd654cb1
 
Aula_02_-_Listas_com_Vetores-OOP.ppt
Aula_02_-_Listas_com_Vetores-OOP.pptAula_02_-_Listas_com_Vetores-OOP.ppt
Aula_02_-_Listas_com_Vetores-OOP.pptssuserd654cb1
 
Listas em Prolog
Listas em PrologListas em Prolog
Listas em PrologNatã Melo
 
15 algoritmos de busca em tabelas - sequencial e binaria
15   algoritmos de busca em tabelas - sequencial e binaria15   algoritmos de busca em tabelas - sequencial e binaria
15 algoritmos de busca em tabelas - sequencial e binariaRicardo Bolanho
 
Técnicas de Programação Funcional
Técnicas de Programação FuncionalTécnicas de Programação Funcional
Técnicas de Programação FuncionalLambda 3
 
Programando em python listas
Programando em python   listasProgramando em python   listas
Programando em python listassamuelthiago
 
Programando em python recursao
Programando em python   recursaoProgramando em python   recursao
Programando em python recursaosamuelthiago
 
Listas duplamente encadeadas
Listas duplamente encadeadasListas duplamente encadeadas
Listas duplamente encadeadasJailson Torquato
 
10 alocacao dinamica - listas ligadas
10   alocacao dinamica - listas ligadas10   alocacao dinamica - listas ligadas
10 alocacao dinamica - listas ligadasRicardo Bolanho
 

Semelhante a Listas Estáticas Encadeadas usando linguagem C (20)

Aula_02_-_Listas_com_Vetores-OOP_2011_2.ppt
Aula_02_-_Listas_com_Vetores-OOP_2011_2.pptAula_02_-_Listas_com_Vetores-OOP_2011_2.ppt
Aula_02_-_Listas_com_Vetores-OOP_2011_2.ppt
 
Aula_02_-_Listas_com_Vetores-OOP.ppt
Aula_02_-_Listas_com_Vetores-OOP.pptAula_02_-_Listas_com_Vetores-OOP.ppt
Aula_02_-_Listas_com_Vetores-OOP.ppt
 
Aula 07 - lista linear
Aula 07 - lista linearAula 07 - lista linear
Aula 07 - lista linear
 
Usar explicação 01
Usar explicação 01Usar explicação 01
Usar explicação 01
 
Usar explicação 01
Usar explicação 01Usar explicação 01
Usar explicação 01
 
Listas Encadeadas
Listas EncadeadasListas Encadeadas
Listas Encadeadas
 
Listas em C
Listas em CListas em C
Listas em C
 
Listas em Prolog
Listas em PrologListas em Prolog
Listas em Prolog
 
Aula 11
Aula 11Aula 11
Aula 11
 
Estrutura de Dados - Listas Encadeadas
Estrutura de Dados - Listas EncadeadasEstrutura de Dados - Listas Encadeadas
Estrutura de Dados - Listas Encadeadas
 
15 algoritmos de busca em tabelas - sequencial e binaria
15   algoritmos de busca em tabelas - sequencial e binaria15   algoritmos de busca em tabelas - sequencial e binaria
15 algoritmos de busca em tabelas - sequencial e binaria
 
Técnicas de Programação Funcional
Técnicas de Programação FuncionalTécnicas de Programação Funcional
Técnicas de Programação Funcional
 
Programando em python listas
Programando em python   listasProgramando em python   listas
Programando em python listas
 
Programando em python recursao
Programando em python   recursaoProgramando em python   recursao
Programando em python recursao
 
Listas duplamente encadeadas
Listas duplamente encadeadasListas duplamente encadeadas
Listas duplamente encadeadas
 
Lista duplamente encadeada
Lista duplamente encadeadaLista duplamente encadeada
Lista duplamente encadeada
 
Python 02
Python 02Python 02
Python 02
 
Programacao logica
Programacao logicaProgramacao logica
Programacao logica
 
10 alocacao dinamica - listas ligadas
10   alocacao dinamica - listas ligadas10   alocacao dinamica - listas ligadas
10 alocacao dinamica - listas ligadas
 
Aula 12
Aula 12Aula 12
Aula 12
 

Listas Estáticas Encadeadas usando linguagem C

  • 1. TAD Listas Estáticas Encadeadas Profa. Maria Carolina Monard Implementações C de Ígor Assis Braga Material Parcial do Prof. Gustavo Batista
  • 2. 2 Listas Estáticas Encadeadas Vamos apresentar uma outra possibilidade de implementação do TAD Listas. Essa implementação é chamada de estática encadeada ◼ Estática por utilizar vetores; ◼ Encadeada por manter uma estrutura de encadeamento que difere da estrutura seqüencial. Essa implementação é menos comum do que as demais, mas bastante interessante por motivos didáticos.
  • 3. 3 Listas Estáticas Encadeadas Listas Estáticas Encadeadas simulam o conceito de ponteiros: ◼ Esses “ponteiros” armazenam posições do vetor ao invés de endereços de memória; ◼ Chamamos esses “ponteiros” de cursores. A princípio, todas as posições do vetor estão disponíveis, isso é representado da seguinte maneira usando o cursor dispo em listas estáticas simplesmente encadeadas...
  • 4. 4 Lista Dispo 2 ? 1 2 3 4 Primeiro: -1 Dispo: 1 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox A operação de criar a lista é responsável por realizar essa inicialização. Qual é a complexidade dessa operação?
  • 5. 5 Lista Dispo 2 ? 1 2 3 4 Primeiro: -1 Dispo: 1 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox A operação de criar a lista é responsável por realizar essa inicialização. Qual é a complexidade dessa operação?
  • 6. 6 Lista Dispo 2 ? 1 2 3 4 Primeiro: -1 Dispo: 1 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox A operação de criar a lista é responsável por realizar essa inicialização. Qual é a complexidade dessa operação? O(n).
  • 7. 7 Definição de Tipos #define MAX_TAM 300 #define NAO_ENCONTRADO -1 typedef int TipoChave; typedef struct { TipoChave chave; /* Outros Campos */ } TipoItem; typedef struct { TipoItem item; int prox; } TipoNo;
  • 8. 8 Definição de Tipos typedef struct TipoLista { TipoNo no[MAX_TAM]; int primeiro; int dispo; } *TipoLista;
  • 9. 9 Observar... Lembrar que na estrutura de dados o primeiro elemento da lista encontra-se inicialmente na posião 0 (zero)
  • 10. 10 Cria lista /* Pré-condição: nenhuma; Pós-condição: retorna uma lista vazia. */ TipoLista IniciaLista() { ....... }
  • 11. 11 Cria lista /* Pré-condição: nenhuma; Pós-condição: retorna uma lista vazia. */ TipoLista IniciaLista() { int i; TipoLista L = malloc(sizeof(struct TipoLista)); if(L != NULL) { L->primeiro = -1; L->dispo = 0; /* segue... */
  • 12. 12 Cria lista for(i = 0; i < MAX_TAM - 1; i++) { L->no[i].prox = i + 1; } assert(i == MAX_TAM - 1); /* não é realmente necessária. Útil para debug */ L->no[i].prox = -1; } return L; }
  • 13. 13 assert(<exp> ) assert(), definida em assert.h, aborta a execução do programa se a expressão <exp> vale 0 (zero). Caso contrário, assert() não faz nada Caso <exp> valer 0 (zero), escreve informação do erro -- o formato dessa informação depende do compilador
  • 14. 14 assert(<exp> ) assert() geralmente é usada para ajudar a verificar se um programa está operando corretamente. A expressão <exp> deve ser planejada de forma a que ela seja verdadeira (diferente de 0) somente quando não ocorre nenhum erro Não é necessário remover assert() do código fonte após o programa ter sido depurado
  • 15. 15 Destroi lista /* Pré-condição: a lista já está iniciada; Pós-condição: libera memória ocupada pela lista. */ void DestroiLista(TipoLista L) { free(L); }
  • 16. 16 Inserção na primeira posição A operação de inserção deve ser realizada em dois passos: ◼ Recuperar a posição disponível; ◼ Inserir o elemento, atualizando os cursores primeiro e prox. Vamos simular a inserção do valor 7...
  • 17. 17 Inserção na primeira posição 2 ? 1 2 3 4 Primeiro: -1 Dispo: 1 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção do valor 7 no início da lista (vazia). Qual é a complexidade da operação de inserção no início da lista?
  • 18. 18 Inserção na primeira posição 2 ? 1 2 3 4 Primeiro: 1 Dispo: 1 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção do valor 7 no início da lista (vazia).. Qual é a complexidade da operação de inserção no início da lista?
  • 19. 19 Inserção na primeira posição 2 ? 1 2 3 4 Primeiro: 1 Dispo: 2 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção do valor 7 no início da lista (vazia). Qual é a complexidade da operação de inserção no início da lista?
  • 20. 20 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 1 Dispo: 2 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção do valor 7 no início da lista (vazia). Qual é a complexidade da operação de inserção no início da lista?
  • 21. 21 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 1 Dispo: 2 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção do valor 7 no início da lista (vazia). Qual é a complexidade da operação de inserção no início da lista? O(1)
  • 22. 22 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 1 Dispo: 2 3 ? 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção de um segundo valor, 4, no início da lista (não vazia).
  • 23. 23 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 2 Dispo: 3 1 4 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção de um segundo valor, 4, no início da lista (não vazia).
  • 24. 24 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 2 Dispo: 3 1 4 4 ? 5 ? -1 ? 5 Legenda: Chave Prox Inserção de um segundo valor, 4, no início da lista (não vazia). Qual é a complexidade da operação de inserção no início da lista com n elementos? O(1)
  • 25. 25 Inserção na primeira posição Uma situação especial é a inserção de um elemento quando a lista somente possui uma posição livre. Vamos ver um exemplo disso...
  • 26. 26 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 4 Dispo: 5 1 4 2 3 3 9 -1 ? 5 Legenda: Chave Prox Inserção do valor 3 quando somente existe uma posição livre.
  • 27. 27 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 5 Dispo: -1 1 4 2 3 3 9 4 3 5 Legenda: Chave Prox Inserção do valor 3 quando somente existe uma posição livre.
  • 28. 28 Inserção na primeira posição -1 7 1 2 3 4 Primeiro: 5 Dispo: -1 1 4 2 3 3 9 4 3 5 Legenda: Chave Prox Inserção do valor 3 quando somente existe uma posição livre.
  • 29. 29 Lista Cheia e Vazia Dessa forma, podemos estipular regras para verificar se uma lista está cheia ou vazia: ◼ Lista Vazia: Primeiro = -1; ◼ Lista Cheia: Dispo = -1.
  • 30. 30 Lista cheia /* Pré-condição: a lista já está iniciada; Pós-condição: retorna 1 se a lista estiver cheia e 0 caso- contrário. */ int ListaCheia(TipoLista L) { ............. }
  • 31. 31 Lista cheia /* Pré-condição: a lista já está iniciada; Pós-condição: retorna 1 se a lista estiver cheia e 0 caso- contrário. */ int ListaCheia(TipoLista L) { if(L->dispo == -1) { return 1; } else { return 0; } }
  • 32. 32 Lista vazia /* Pré-condição: a lista já está iniciada; Pós-condição: retorna 1 se a lista estiver vazia e 0 caso- contrário. */ int ListaVazia(TipoLista L) { ............. }
  • 33. 33 Lista vazia /* Pré-condição: a lista já está iniciada; Pós-condição: retorna 1 se a lista estiver vazia e 0 caso- contrário. */ int ListaVazia(TipoLista L) { if(L->primeiro == -1) { return 1; } else { return 0; } }
  • 34. 34 Inserir elemento (primeira posição) /* Pré-condição: a lista já está iniciada e não está cheia; Pós-condição: insere um elemento na primeira posição. */ void InserePrimeiroLista(TipoLista L, TipoItem elem) { ................. }
  • 35. 35 Inserir elemento (primeira posição) /* Pré-condição: a lista já está iniciada e não está cheia; Pós-condição: insere um elemento na primeira posição. */ void InserePrimeiroLista(TipoLista L, TipoItem elem) { int dispo = L->dispo; L->no[dispo].item = elem; L->dispo = L->no[dispo].prox; L->no[dispo].prox = L->primeiro; L->primeiro = dispo; }
  • 36. 36 Inserção na última posição 3 7 1 2 3 4 Primeiro: 2 Dispo: 4 1 4 -1 10 5 ? -1 ? 5 Legenda: Chave Prox Deve percorrer a lista para achar o último elemento, inserir após ele o novo elemento (seja 12) e atualizar a estrutura
  • 37. 37 Inserção na última posição 3 7 1 2 3 4 Primeiro: 2 Dispo: 5 1 4 4 10 -1 12 -1 ? 5 Legenda: Chave Prox Após inserir o novo elemento 12
  • 38. 38 Inserir elemento (última posição) /* Pré-condição: a lista já está iniciada e não está cheia; Pós-condição: insere um elemento na última posição. */ void InsereUltimoLista(TipoLista L, TipoItem elem) { ................. }
  • 39. 39 Inserir elemento (última posição) /* Pré-condição: a lista já está iniciada e não está cheia; Pós-condição: insere um elemento na última posição. */ void InsereUltimoLista(TipoLista L, TipoItem elem) { int dispo = L->dispo; int i = L->primeiro; L->no[dispo].item = elem; L->dispo = L->no[dispo].prox; L->no[dispo].prox = -1; /* Segue... */
  • 40. 40 Inserir elemento (última posição) if(i == -1) {/* lista de entrada vazia*/ L->primeiro = dispo; } else { do { if(L->no[i].prox == -1) {/* ultimo elemento da lista de entrada */ L->no[i].prox = dispo; i = -1; /* para fim do loop*/ } else { i = L->no[i].prox; } } while(i != -1); } }
  • 41. 41 Observação -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 4 2 3 -1 9 4 7 5 Legenda: Chave Prox Esta instância da estrutura representa a lista (3, 4, 7, 9)
  • 42. 42 Observação 5 3 1 2 3 4 Primeiro: 1 Dispo: 4 3 7 -1 9 -1 ? 2 4 5 Legenda: Chave Prox Essa lista (3, 4, 7, 9) também é representada por esta outra instância da estrutura...
  • 43. 43 Observação Nessa lista (3, 4, 7, 9) convencionamos que o elemento 3 está na posição 0, 4 na posição 1, 7 na posição 2 e assim por diante
  • 44. 44 Observação Após diversas inserções e remoções a lista não estará com os elementos na seqüência das posições do vetor. Dessa forma, a pesquisa deve seguir a partir do cursor Primeiro (elemento na posição 0) e seguir os cursores Prox de cada elemento incrementando em 1 o valor da posição do elemento “visitado”.
  • 45. 45 Pesquisa -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 4 2 3 -1 9 4 7 5 Legenda: Chave Prox Pesquisar por todos os elementos na lista
  • 46. 46 Pesquisa -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 4 2 3 -1 9 4 7 5 Legenda: Chave Prox “visitado” posição 3 0 4 1 7 2 9 3
  • 47. 47 Pesquisa -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 4 2 3 -1 9 4 7 5 Legenda: Chave Prox Pesquisa pela chave 4. Aux: 3
  • 48. 48 Pesquisa -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 4 2 3 -1 9 4 7 5 Legenda: Chave Prox Pesquisa pela chave 4. Aux: 2
  • 49. 49 Pesquisa -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 4 2 3 -1 9 4 7 5 Legenda: Chave Prox Pesquisa pela chave 4. Deve retornar a posição. Qual é a complexidade dessa operação? Aux: 2
  • 50. 50 Pesquisa -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 4 2 3 -1 9 4 7 5 Legenda: Chave Prox Pesquisa pela chave 4. Qual é a complexidade dessa operação? O(n). Aux: 2
  • 51. 51 Pesquisar elemento (por posição) /* Pré-condição: a lista já está iniciada; Pós-condição: retorna a posição do elemento na lista, ou um valor especial caso não exista. */ int PesquisaLista(TipoLista L, TipoChave chave) { ................ }
  • 52. 52 Pesquisar elemento (por posição) /* Pré-condição: a lista já está iniciada; Pós-condição: retorna a posição do elemento na lista, ou um valor especial caso não exista. */ int PesquisaLista(TipoLista L, TipoChave chave) { int i = L->primeiro; int achou = 0; int posAtual = 0; while((!achou) && (i != -1)) { if(L->no[i].item.chave == chave) { achou = 1; } else { i = L->no[i].prox; posAtual++; } } /* segue... */
  • 53. 53 Pesquisar elemento (por posição) if(achou) { return posAtual; } else { return NAO_ENCONTRADO; } }
  • 54. 54 Remoção (por posição) A remoção pode ser realizada por posição, ou seja, um cursor para uma posição do vetor deve ser informado. Entretanto, é necessário que se conheça o elemento anterior. Dessa forma, a remoção é bastante similar a realizada em listas ligadas. É importante colocar o elemento liberado na lista Dispo.
  • 55. 55 Remoção (por posição) -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 14 2 3 -1 9 4 7 5 Legenda: Chave Prox Lista (3, 14, 7, 9) Remoção do elemento na posição 2 (i.e. o 3ro elemento da lista que é o elemento 7)
  • 56. 56 Remoção (por posição) -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 14 2 3 -1 9 4 7 5 Legenda: Chave Prox Lista (3, 14, 7, 9) Remoção do elemento na posição 2 (elemento 7) Aux: 3
  • 57. 57 Remoção (por posição) -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 14 2 3 -1 9 4 7 5 Legenda: Chave Prox Lista (3, 14, 7, 9) Remoção do elemento na posição 2 (elemento 7) Aux: 2
  • 58. 58 Remoção (por posição) -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 5 14 2 3 -1 9 4 7 5 Legenda: Chave Prox Lista (3, 14, 7, 9) Remoção do elemento na posição 2 (elemento 7) Aux: 2
  • 59. 59 Remoção (por posição) -1 ? 1 2 3 4 Primeiro: 3 Dispo: 1 4 14 2 3 -1 9 4 7 5 Legenda: Chave Prox Lista (3, 14, 7, 9) Remoção do elemento na posição 2 (elemento 7) Atualização da lista encadeada e... Aux: 2
  • 60. 60 Remoção (por posição) -1 ? 1 2 3 4 Primeiro: 3 Dispo: 5 4 14 2 3 -1 9 1 ? 5 Legenda: Chave Prox Remoção do elemento na posição 2 Atualização da lista encadeada e... Atualização da lista Dispo Aux: 2
  • 61. 61 Remoção (por posição) -1 ? 1 2 3 4 Primeiro: 3 Dispo: 5 4 14 2 3 -1 9 1 ? 5 Legenda: Chave Prox Lista retornada (3, 14, 9) Qual é a complexidade essa operação? O(n)
  • 62. 62 Remover elemento (por posição) /* Pré-condição: a lista já está iniciada e uma posição válida da lista é informada; Pós-condição: o elemento na posição fornecida é removido da lista. */ void RemoveDeLista(TipoLista L, int pos) { .............. }
  • 63. 63 Remover elemento (por posição) /* Pré-condição: a lista já está iniciada e uma posição válida da lista é informada; Pós-condição: o elemento na posição fornecida é removido da lista. */ void RemoveDeLista(TipoLista L, int pos) { int i; int anterior; int posAtual; if(pos == 0) {/* remover 1ro elemento da lista*/ i = L->primeiro; L->primeiro = L->no[L->primeiro].prox; L->no[i].prox = L->dispo; L->dispo = i; } /* Segue...*/
  • 64. 64 Remover elemento (por posição) } else { i = L->no[L->primeiro].prox; anterior = L->primeiro; posAtual = 1; while(posAtual != pos) { anterior = i; i = L->no[i].prox; posAtual++; } L->no[anterior].prox = L->no[i].prox; L->no[i].prox = L->dispo; L->dispo = i; } }
  • 65. 65 TAD Lista A seguir veremos a implementação do TAD lista mas usando agora uma estrutura estática na qual os elementos da lista encontram-se duplamente encadeados
  • 66. 66 Listas Duplamente Encadeadas Os cursores na estrutura estática podem ser utilizados para implementar listas duplamente encadeadas. Para isso basta manter um ponteiro ant para um elemento anterior. Variáveis auxiliares como nr_elementos e ultimo ajudam nas operações de contar e inserir na última posição, respectivamente, e serão usadas nesta implementação.
  • 67. 67 Listas Duplamente Encadeadas 2 ? ? 3 ? ? 4 ? ? -1 ? ? 1 2 3 4 Primeiro: -1 NrElementos: 0 Ultimo: -1 Dispo: 1 Ant Chave Prox Legenda: Lista vazia
  • 68. 68 Definição de Tipos #define MAX_TAM 3 #define NAO_ENCONTRADO -1 typedef int TipoChave; typedef struct { TipoChave chave; /* Outros Campos */ } TipoItem; typedef struct { TipoItem item; int ant; int prox; } TipoNo;
  • 69. 69 Definição de Tipos typedef struct TipoLista { TipoNo no[MAX_TAM]; int primeiro; int dispo; int nrElementos; int ultimo; } *TipoLista;
  • 70. 70 Listas Duplamente Encadeadas 2 ? ? 3 ? ? 4 ? ? -1 ? ? 1 2 3 4 Primeiro: -1 NrElementos: 0 Ultimo: -1 Dispo: 1 Ant Chave Prox Legenda: Inserir o valor 2 no início da lista. O que deve ser feito?
  • 71. 71 Listas Duplamente Encadeadas -1 2 -1 3 ? ? 4 ? ? -1 ? ? 1 2 3 4 Primeiro: 1 NrElementos: 1 Ultimo: 1 Dispo: 2 Ant Chave Prox Legenda: Após a inserção do valor 2 no início da lista
  • 72. 72 Listas Duplamente Encadeadas -1 2 -1 3 ? ? 4 ? ? -1 ? ? 1 2 3 4 Primeiro: 1 NrElementos: 1 Ultimo: 1 Dispo: 2 Ant Chave Prox Legenda: Inserir o valor 4 no fim da lista. O que deve ser feito?
  • 73. 73 Listas Duplamente Encadeadas 2 2 -1 -1 4 1 4 ? ? -1 ? ? 1 2 3 4 Primeiro: 1 NrElementos: 2 Ultimo: 2 Dispo: 3 Ant Chave Prox Legenda: Após a inserção do valor 4 no final da lista
  • 74. 74 Análise A implementação estática encadeada compartilha características comuns com as implementações de listas com vetores e com ponteiros: ◼ Vetores:  O número máximo de elementos deve ser estipulado a priori. ◼ Ponteiros:  As operações de inserção no início e em qualquer posição e remoção em qualquer posição não requerem o deslocamento de elementos.
  • 75. 75 Exercício (usando as declarações de tipo definidas) 1. Implemente as operações do TAD lista utilizando uma lista estática encadeada simples. 2. Implemente as operações do TAD lista utilizando uma lista estática encadeada dupla. 3. Qual a complexidade dessas operações utilizando lista estática encadeada simples e dupla?