Carregar apresentação
A apresentação está carregando. Por favor, espere
PublicouBaltazar da Silva das Neves Alterado mais de 8 anos atrás
1
Capítulo II Listas Lineares Gerais CES-11 ALGORITMOS E ESTRUTURAS DE DADOS
2
Capítulo II – Listas Lineares Gerais 2.1 – Introdução 2.2 – Estruturas contíguas 2.3 – Estruturas encadeadas 2.4 – Aprimoramento das estruturas encadeadas 2.5 – Listas ortogonais 2.6 – Exercícios resolvidos
3
2.1 – Introdução 2.1.1 – Definições Lista linear geral ou simplesmente lista linear é um modelo bem simples de armazenamento de informações Lista linear geral ou simplesmente lista linear é um modelo bem simples de armazenamento de informações Consiste de uma sequência linear de zero ou mais elementos de um dado tipo (genericamente, tipelemento) Consiste de uma sequência linear de zero ou mais elementos de um dado tipo (genericamente, tipelemento) Simbolicamente, L = a 1, a 2,..., a n ( n 0 ) Simbolicamente, L = a 1, a 2,..., a n ( n 0 ) L
4
Cada a i é do tipo tipelemento Cada a i é do tipo tipelemento a 1 : primeiro elemento; a n : último elemento a 1 : primeiro elemento; a n : último elemento n: comprimento da lista linear; se n = 0, L é vazia n: comprimento da lista linear; se n = 0, L é vazia L
5
Posição de um elemento numa lista é o local ocupado por ele na lista Posição de um elemento numa lista é o local ocupado por ele na lista Às vezes posição é expressa por um índice num vetor, às vezes por um ponteiro para uma estrutura num encadeamento Os elementos numa lista linear são ordenados linearmente: Os elementos numa lista linear são ordenados linearmente: a i precede a i+1 ; a i segue a i-1 ; i é a posição de a i na lista L
6
Propriedades: Propriedades: Listas crescem e diminuem conforme a demanda Seus elementos podem ser acessados, deletados ou inseridos em qualquer posição Listas podem ser concatenadas ou repartidas Lista Linear é um tipo abstrato de dados (TAD): Lista Linear é um tipo abstrato de dados (TAD): Deve ser definida uma lista de operadores aplicáveis Deve ser estabelecida sua estrutura de dados
7
2.1.2 – Operadores para o TAD lista linear O conjunto de operadores apresentado a seguir é apenas um exemplo; outros operadores podem ser acrescentados O conjunto de operadores apresentado a seguir é apenas um exemplo; outros operadores podem ser acrescentados Estruturas de dados, bem como implementações da maioria desses operadores, serão vistas mais adiante Estruturas de dados, bem como implementações da maioria desses operadores, serão vistas mais adiante posicao Fim (lista L): retorna a posição na lista após aquela de seu último elemento a n posicao Fim (lista L): retorna a posição na lista após aquela de seu último elemento a n LFim (L)
8
void Inserir (tipelemento x, posicao p, lista *L): insere o elemento x na posição p da lista L. void Inserir (tipelemento x, posicao p, lista *L): insere o elemento x na posição p da lista L. Antes: L = a 1, a 2,..., a p-1, a p,..., a n Depois:L = a 1, a 2,..., a p-1, x, a p,..., a n Passa-se endereço de lista para L, pois a lista será alterada Se (p == Fim(L)), depois: L = a 1, a 2,..., a n, x Se L não tiver posição p, nada será inserido
9
posicao Local (tipelemento x, lista L): posição de x em L posicao Local (tipelemento x, lista L): posição de x em L Se x aparecer duas vezes: posição da 1ª ocorrência Se x não aparecer: Local = Fim (L) tipelemento Elemento (posicao p, lista L): elemento da posição p em L tipelemento Elemento (posicao p, lista L): elemento da posição p em L Se (p == Fim (L)) ou (L não tiver p), o resultado será indefinido
10
tipelemento Deletando (posicao p, lista *L): deleta o elemento da posição p em L e retorna o elemento deletado tipelemento Deletando (posicao p, lista *L): deleta o elemento da posição p em L e retorna o elemento deletado Antes: L = a 1, a 2,..., a p-1, a p, a p+1,..., a n Depois: L = a 1, a 2,..., a p-1, a p+1,..., a n O elemento seguinte passa para a posição p Passa-se endereço de lista para L, pois a lista será alterada Se (p == Fim (L)) ou (L não tiver p), nada será deletado e o valor retornado será indefinido
11
posicao Primeira (lista L) : retorna a posição do 1 o elemento da lista L posicao Primeira (lista L) : retorna a posição do 1 o elemento da lista L Se (L estiver vazia), o resultado será Fim (L) posicao Próxima (posicao p, lista L) e posicao Próxima (posicao p, lista L) e posicao Prévia (posicao p, lista L): retornam respectivamente a posição seguinte e a anterior a p em L Se p for a última posição: Próxima (p, L) = Fim (L) Se (p == Fim (L)): Próxima (p, L) será indefinido Se (p == Primeira(L)): Prévia (p, L) será indefinido Ambas as funções serão indefinidas se (L não tiver p)
12
lista NovaLista (): retorna uma nova lista com um novo lote de elementos lista NovaLista (): retorna uma nova lista com um novo lote de elementos Os elementos serão digitados pelo operador void Escrever (lista L): escreve os elementos de L em ordem de ocorrência void Escrever (lista L): escreve os elementos de L em ordem de ocorrência void Ordenar (lista *L): ordena os elementos de L void Ordenar (lista *L): ordena os elementos de L Passa-se endereço de lista para L, pois a lista será alterada void Esvaziar (lista *L): esvazia a lista L void Esvaziar (lista *L): esvazia a lista L Passa-se endereço de lista para L, pois a lista será alterada
13
logic Vazia (lista L): retorna True se L estiver vazia logic Vazia (lista L): retorna True se L estiver vazia void Concatenar (lista *L1, lista *L2): as listas L1 e L2 serão concatenadas e L1 passará a conter a lista resultante; L2 será esvaziada void Concatenar (lista *L1, lista *L2): as listas L1 e L2 serão concatenadas e L1 passará a conter a lista resultante; L2 será esvaziada void Repartir (lista *L, lista *L1, lista *L2, posicao p): reparte L em L1 e L2; p é a posição em L do primeiro elemento de L2; L será esvaziada void Repartir (lista *L, lista *L1, lista *L2, posicao p): reparte L em L1 e L2; p é a posição em L do primeiro elemento de L2; L será esvaziada void Copiar (lista *L1, lista L2): copia L2 em L1 void Copiar (lista *L1, lista L2): copia L2 em L1 int Cardinalidade (lista L): retorna o número de elementos de L int Cardinalidade (lista L): retorna o número de elementos de L
14
Exemplo: subprograma para eliminar elementos duplicados numa lista: void Unifica (lista *L) { posicao p, q; p = primeira(*L); enquanto (p != Fim(*L)) { q = Proxima (p, *L); enquanto (q != Fim(*L)) { se (Iguais(Elemento(p, *L), Elemento(q, *L ))) Deletando(q, L); senão q = Proxima(q, *L); } p = Proxima(p, *L); }} O argumento passado é um endereço: Unifica deve alterar o conteúdo da lista envolvida Não há referência à estrutura interna de *L É uma função independente da estrutura de dados
15
Exemplo: subprograma para fundir duas listas ordenadas: void Intercalar (lista *L1, lista *L2, lista *L3) As listas L1 e L2 serão fundidas em L3 As listas L1 e L2 serão fundidas em L3 L1 e L2 serão esvaziadas L1 e L2 serão esvaziadas Devem ser passados como argumentos os endereços das 3 listas envolvidas, pois todas serão alteradas pelo subprograma Devem ser passados como argumentos os endereços das 3 listas envolvidas, pois todas serão alteradas pelo subprograma O subprograma Intercalar pressupõe que a terceira lista esteja inicialmente vazia O subprograma Intercalar pressupõe que a terceira lista esteja inicialmente vazia Os elementos das listas são inteiros Os elementos das listas são inteiros
16
O processo de intercalação: 2456 L1 *L1 Fim(*L1) 14678 L2 *L2 Fim(*L2) L3 *L3 Fim(*L3) p q r p = Primeira(*L1); q = Primeira(*L2); r = Primeira(*L3); Primeira(*L3) Fim(*L3)
17
O processo de intercalação: 2456 L1 *L1 Fim(*L1) 14678 L2 *L2 Fim(*L2) L3 *L3 Fim(*L3) p q r Elemento(q, *L2) < Elemento(p, *L1)Deletá-lo e inseri-lo na posição r de L3
18
O processo de intercalação: 2456 L1 *L1 Fim(*L1) 4678 L2 *L2 Fim(*L2) L3 *L3 Fim(*L3) p q r Deletá-lo e inseri-lo na posição r de L3 1 Avançar r em L3 r Elemento(p, *L1) < Elemento(q, *L2)Deletá-lo e inseri-lo na posição r de L3
19
O processo de intercalação: 456 L1 *L1 Fim(*L1) 4678 L2 *L2 Fim(*L2) L3 *L3 Fim(*L3) p q 1 r Deletá-lo e inseri-lo na posição r de L3 2 E assim por diante até...Avançar r em L3 r
20
O processo de intercalação: L1 *L1 Fim(*L1) L2 *L2 Fim(*L2) L3 *L3 Fim(*L3) 124456678 p q r A seguir o algoritmo da função Intercalar
21
void IntercalarListas (lista *L1, lista *L2, lista *L3) { posicao p, q, r; p = Primeira(*L1); q = Primeira(*L2); r = Primeira (*L3); while (p != Fim(*L1) && q != Fim(*L2)) { if (Elemento(p, *L1) < Elemento(q, *L2)) Inserir (Deletando(p, L1), r, L3); else Inserir (Deletando(q, L2), r, L3); r = Proxima(r, *L3); } while (p != Fim(*L1)) { Inserir (Deletando(p, L1), r, L3); r = Proxima(r, *L3); } while (q != Fim(*L2)) { Inserir (Deletando(q, L2), r, L3); r = Proxima(r, *L3); }}
22
Observações: Em muitos dos subprogramas-operadores relacionados anteriormente, listas lineares são passadas como argumentos por valor Em muitos dos subprogramas-operadores relacionados anteriormente, listas lineares são passadas como argumentos por valor Exemplos: Fim, Escrever, Local, Elemento, Primeira, Proxima, Previa, Vazia, Copiar, Cardinalidade Se isso provocar movimentação de grande massa de dados, deve-se estudar a possibilidade de fazer a passagem por endereço Muitos detalhes de programação envolvendo TAD’s são justificados por proporcionarem facilidade de troca de estruturas de dados desses TAD’s Muitos detalhes de programação envolvendo TAD’s são justificados por proporcionarem facilidade de troca de estruturas de dados desses TAD’s
23
2.1.3 – Estruturas de dados para o TAD lista linear As estruturas de dados para as listas lineares se dividem em dois grandes grupos As estruturas de dados para as listas lineares se dividem em dois grandes grupos Estruturas contíguas: seus elementos são armazenados num vetor Estruturas contíguas: seus elementos são armazenados num vetor Estruturas encadeadas: seus elementos são guardados em encadeamentos de estruturas Estruturas encadeadas: seus elementos são guardados em encadeamentos de estruturas
24
Capítulo II – Listas Lineares Gerais 2.1 – Introdução 2.2 – Estruturas contíguas 2.3 – Estruturas encadeadas 2.4 – Aprimoramento das estruturas encadeadas 2.5 – Listas ortogonais 2.6 – Exercícios resolvidos
25
2.2 – Estruturas Contíguas 2.2.1 – Aspectos gerais e declarações Os elementos são armazenados em células contíguas num vetor Dificuldades de inserir e deletar elementos no início e no meio da lista: Em listas muito grandes, movimentação de grande massa de dados
26
Declarações: Sejam listas cujos elementos são inteiros Sejam listas cujos elementos são inteiros const int MAX = 50; typedef int vetor[51]; typedef struct lista lista; struct lista { vetor Elementos; int ultimo; }; typedef int posicao; lista L, L1, L2, L3; Posição de um elemento é seu índice no vetor
27
Declarações: Sejam listas cujos elementos são inteiros Sejam listas cujos elementos são inteiros Por convenção, o 1º elemento fica guardado na posição 1 do vetor Elementos Se o valor do campo ultimo for zero, a lista estará vazia Se for 1, a lista terá apenas um elemento
28
2.2.2 – Operadores básicos a) Posição de fim de lista: posicao Fim (lista L) { return L.Ultimo + 1; } A operação é O(1)
29
b) Formar uma nova lista: lista NovaLista () { lista L; int i, n; write ("Digite o numero de elementos:"); read (n); L.Ultimo = n; if (n > MAX || n MAX || n < 0) { Erro ("Numero de elementos improprio"); L.Ultimo = 0; } else if (n > 0) { write ("Digite ", n, " elemento(s): "); for (i = 1; i <= n; i++) read (L.Elementos[i]); } return L; } L void main () { lista L1; L1 = NovaLista(); }
30
c) Escrever os elementos de uma lista: void Escrever (lista L) { int i; if (L.Ultimo < 1) write ("Lista vazia"); else for (i = 1; i <= L.Ultimo; i++) write (L.Elementos[i]); } void main () { lista L1; - - - - - Escrever (L1); }
31
d) Inserir o elemento x na posição p da lista L: void Inserir (int x, posicao p, lista *L) L x (main) 342 L1 1 2 3 i i+1 n n+1 elemento Elementos Ultimo n void main () { lista L1; int x; posicao p; - - - - - Inserir (x, p, &L1); } *L p (main) i x (Inserir) 342 p (Inserir) i
32
d) Inserir o elemento x na posição p da lista L: void Inserir (int x, posicao p, lista *L) L x (main) 342 L1 1 2 3 i i+1 n n+1 elemento Elementos Ultimo n void main () { lista L1; int x; posicao p; - - - - - Inserir (x, p, &L1); } *L p (main) i x (Inserir) 342 p (Inserir) i
33
d) Inserir o elemento x na posição p da lista L: void Inserir (int x, posicao p, lista *L) L x (main) 342 L1 1 2 3 i i+1 n n+1 elemento Elementos Ultimo void main () { lista L1; int x; posicao p; - - - - - Inserir (x, p, &L1); } *L p (main) i x (Inserir) 342 p (Inserir) i elemento n+1
34
d) Inserir o elemento x na posição p da lista L: void Inserir (int x, posicao p, lista *L) L x (main) 342 L1 1 2 3 i i+1 n n+1 elemento Elementos Ultimo void main () { lista L1; int x; posicao p; - - - - - Inserir (x, p, &L1); } *L p (main) i x (Inserir) 342 p (Inserir) i elemento n+1 342
35
Algoritmo de inserção: void Inserir (int x, posicao p, lista *L) { posicao q; if (L->Ultimo >= MAX) Erro ("Lista cheia: inserção impossivel"); else if (p L->Ultimo + 1) Erro ("A posicao de insercao nao existe"); else { L->Ultimo++; for (q = L->Ultimo - 1; q >= p; q--) L->Elementos[q+1] = L->Elementos[q]; L->Elementos[p] = x; }} No pior caso, T(n) é O(n), onde n é o número de elementos da lista
36
d) Deletar e retornar o elemento da posição p da lista L: int Deletando (posicao p, lista *L) L x (main) L1 1 2 3 i i+1 n-1 n elemento 837 elemento Elementos Ultimo n void main () { lista L1; int x; posicao p; - - - - - x = Deletando (p, &L1); } *L p (main) i p (Deletando) i x (Deletando)
37
d) Deletar e retornar o elemento da posição p da lista L: int Deletando (posicao p, lista *L) L x (main) L1 1 2 3 i i+1 n-1 n elemento 837 elemento Elementos Ultimo n void main () { lista L1; int x; posicao p; - - - - - x = Deletando (p, &L1); } *L p (main) i p (Deletando) i x (Deletando) 837
38
d) Deletar e retornar o elemento da posição p da lista L: int Deletando (posicao p, lista *L) L x (main) L1 1 2 3 i i+1 n-1 n elemento 837 elemento Elementos Ultimo n void main () { lista L1; int x; posicao p; - - - - - x = Deletando (p, &L1); } *L p (main) i p (Deletando) i x (Deletando) 837
39
d) Deletar e retornar o elemento da posição p da lista L: int Deletando (posicao p, lista *L) L x (main) L1 1 2 3 i i+1 n-1 n elemento Elementos Ultimo void main () { lista L1; int x; posicao p; - - - - - x = Deletando (p, &L1); } *L p (main) i p (Deletando) i x (Deletando) 837 n-1 elemento
40
d) Deletar e retornar o elemento da posição p da lista L: int Deletando (posicao p, lista *L) L x (main) L1 1 2 3 i i+1 n-1 n elemento Elementos Ultimo void main () { lista L1; int x; posicao p; - - - - - x = Deletando (p, &L1); } *L p (main) i p (Deletando) i x (Deletando) 837 n-1 elemento 837
41
Algoritmo de deleção e retorno do valor deletado: int Deletando (posicao p, lista *L) { posicao q; int x; if (p L->Ultimo) Erro ("A posicao de delecao nao existe"); else { x = L->Elementos[p]; L->Ultimo--; for (q = p; q Ultimo; q++) L->Elementos[q] = L->Elementos[q+1]; return x; }} No pior caso, T(n) é O(n), onde n é o número de elementos da lista
42
f) Posição do elemento x na lista L: posicao Local (int x, lista L) { posicao q; q = 1; while (q <= L.Ultimo && L.Elementos[q] != x) q++; return q; } x 984 Se x não estiver em L, o valor de p será L.Ultimo + 1, ou seja, Fim(L) No pior caso, T(n) é O(n), quando x não estiver em L
43
g) Outros operadores: Elemento (p, L) é L. Elementos [p] Elemento (p, L) é L. Elementos [p] Próxima (p, L) é p+1 Próxima (p, L) é p+1 Prévia (p, L) é p-1 Prévia (p, L) é p-1 Esvaziar (L) faz L. Último = 0 Esvaziar (L) faz L. Último = 0 Primeira (L) é 1 Primeira (L) é 1 L Elementos Ultimo n elemento 1 2 3 p p+1 n-1 n elemento Para essas operações, T(n) é O(1)
44
Comentários: Comentários: Para listas com muitos elementos, inserir e deletar das posições iniciais envolvem grande movimentação de elementos A ineficiência será grande O tamanho das listas fica limitado à dimensão declarada do vetor Para aplicações com muitas inserções e deleções, a estrutura contígua se mostra inadequada
45
2.2.3 – Alternativa de implementação O início da lista pode variar O início da lista pode variar Declarações: Declarações: struct lista { struct lista { vetor Elementos; vetor Elementos; int Primeiro, Ultimo; int Primeiro, Ultimo;}; Elementos Ultimo n elemento m m+1 m+2 p p+1 n-1 n elemento Primeiro m L Os comentários anteriores também se aplicam a esta alternativa
46
Capítulo II – Listas Lineares Gerais 2.1 – Introdução 2.2 – Estruturas contíguas 2.3 – Estruturas encadeadas 2.4 – Aprimoramento das estruturas encadeadas 2.5 – Listas ortogonais 2.6 – Exercícios resolvidos
47
2.3 – Estruturas Encadeadas 2.3.1 – Aspectos gerais e declarações Na estrutura contígua, inserção e deleção exigem movimentação de grande massa de dados Na estrutura contígua, inserção e deleção exigem movimentação de grande massa de dados É necessário estimar o comprimento máximo das listas É necessário estimar o comprimento máximo das listas
48
Estruturas encadeadas: Os elementos são guardados em encadeamentos de estruturas: Os elementos são guardados em encadeamentos de estruturas: Cada estrutura costuma receber o nome de nó Cada estrutura costuma receber o nome de nó Cada nó guarda um elemento da lista e um ponteiro apontando para o nó que contém o sucessor desse elemento Cada nó guarda um elemento da lista e um ponteiro apontando para o nó que contém o sucessor desse elemento
49
Por convenção, o 1º nó do encadeamento não guarda nenhum elemento, para facilitar a programação de diversas operações com listas Por convenção, o 1º nó do encadeamento não guarda nenhum elemento, para facilitar a programação de diversas operações com listas Nessas operações, o 1º elemento pode ser tratado da mesma forma que os demais Nessas operações, o 1º elemento pode ser tratado da mesma forma que os demais Esse nó especial costuma receber a designação de nó-líder Esse nó especial costuma receber a designação de nó-líder
50
Declarações: Declarações: typedef struct noh noh; typedef noh *lista; struct noh { int elem; noh *prox; }; lista L; Um ponteiro para o nó-líder identifica perfeitamente a lista O tipo do campo elem poderia ser uma estrutura complexa
51
Variáveis do tipo posição na estrutura encadeada: Adota-se uma convenção não muito natural, mas útil para facilitar a programação das operações de inserir e deletar elementos da lista Adota-se uma convenção não muito natural, mas útil para facilitar a programação das operações de inserir e deletar elementos da lista Posição de um elemento é um ponteiro para o nó que contém o antecessor desse elemento Posição de um elemento é um ponteiro para o nó que contém o antecessor desse elemento typedef noh *posicao; posicao p;
52
Exemplos: Posição do 2º elemento: ponteiro para o nó do 1º elemento Posição do 2º elemento: ponteiro para o nó do 1º elemento Posição do 1º elemento: ponteiro para o nó-líder Posição do 1º elemento: ponteiro para o nó-líder Posição do último elemento: ponteiro para o penúltimo nó Posição do último elemento: ponteiro para o penúltimo nó typedef noh *posicao; posicao p; pp p
53
Fim de lista na estrutura encadeada: Ponteiro para o último nó Ponteiro para o último nó Fim (L)
54
2.3.2 – Operadores básicos a) A função Fim (L): posicao Fim (lista L) { posicao p; for (p = L; p->prox != NULL; p = p->prox); return p; return p;} Fim (L)
55
posicao Fim (lista L) { posicao p; for (p = L; p->prox != NULL; p = p->prox); return p; return p;} É uma implementação ineficiente; por exemplo: É uma implementação ineficiente; por exemplo: p = L; while (p != Fim (L)) p = p->prox; Fim (L) Corresponde a dois laços (O(n 2 )) n é o n o de elementos Percorre toda a lista em todo teste da condição do while Não usar Fim (L)
56
posicao Fim (lista L) { posicao p; for (p = L; p->prox != NULL; p = p->prox); return p; return p;} Trocar por: Trocar por: p = L; while (p->prox != NULL) p = p->prox; Fim (L)
57
Ou melhorar a estrutura mantendo para listas um ponteiro para o último elemento: Ou melhorar a estrutura mantendo para listas um ponteiro para o último elemento: typedef struct lista lista; struct lista {noh *inic, *fim;}; posicao Fim (lista L) { return L.fim; } Listas não seriam apenas ponteiros, mas sim estruturas com 2 ponteiros O uso de Fim (L) é importante na necessidade de mudança da estrutura de dados para listas
58
b) Formar uma nova lista: void main () { lista L; write ("Leitura de uma lista"); L = NovaLista (); write ("Confirmacao:"); EscreverLista (L); } L main
59
lista NovaLista () { lista L; posicao p; int i, n; L = (noh *) malloc (sizeof (noh)); L = (noh *) malloc (sizeof (noh)); write ("Digite o numero de elementos:"); read (n); if (n > 0) { write ("Digite ", n, "Elementos:"); for (p = L, i = 1; i <= n; i++) { p->prox = (noh *) malloc (sizeof (noh)); p = p->prox; read (p->elem); }} p->prox = NULL; return L; return L;} L main main: L = NovaLista (); NovaLista L n i p ## 257 Retorno 3 p 1 p 2 p 3 p 4 NovaLista sai do ar !!!Aqui, no pior caso, T(n) é O(n)
60
c) Escrita dos elementos de uma lista: void Escrever (lista L) { posicao p; if (L->prox == NULL) write ("Lista vazia"); else for (p = L->prox; p != NULL; p = p->prox) write (p->elem); } void main () { lista L1; - - - - - Escrever (L1); } L1 ## 2 5 7 L Aqui, no pior caso, T(n) é O(n)
61
d) Inserir um elemento numa posição de uma lista: void Inserir (int x, posicao p, lista *L) { posicao q; q = p->prox; p->prox = (noh *) malloc (sizeof (noh)); p->prox->elem = x; p->prox->prox = q; } void main () { lista L1; int x; posicao p; - - - - - Inserir (x, p, &L1); } ##33584 x p L1 p 4 x q L *L 4 Aqui, no pior caso, T(n) é O(1)
62
d) Inserir um elemento numa posição de uma lista: void Inserir (int x, posicao p, lista *L) { posicao q; q = p->prox; p->prox = (noh *) malloc (sizeof (noh)); p->prox->elem = x; p->prox->prox = q; } void main () { lista L1; int x; posicao p; - - - - - Inserir (x, p, &L1); } ##33584 x p L1 4 A rigor, na função Inserir, seria necessário verificar se p é uma posição em *L Em muitos contextos, isso é garantido
63
d) Inserir um elemento numa posição de uma lista: void Inserir (int x, posicao p, lista *L) { posicao q; q = p->prox; p->prox = (noh *) malloc (sizeof (noh)); p->prox->elem = x; p->prox->prox = q; } void main () { lista L1; int x; posicao p; - - - - - Inserir (x, p, &L1); } ##33584 x p L1 4 O parâmetro *L é portanto dispensável Só seria necessário para prever a troca da estrutura para listas
64
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } ##234587120132 void main () { lista L1; int x; - - - - - InserirOrdenado (x, &L1); } 102 x L1 L *L 102 x
65
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } 102 x p ##234587120132 L1*L L
66
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } 102 x p ##234587120132 L1*L L
67
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } 102 x p ##234587120132 L1*L L
68
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } 102 x p ##234587120132 L1*L L
69
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } Encontrada a posição de inserção 102 x p ##234587120132 L1*L L
70
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } Encontrada a posição de inserção 102 x p ##234587120132 L1*L L
71
e) Inserir um elemento numa lista ordenada: void InserirOrdenado (tipelemento x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); Inserir (x, p, L); } 102 x p Como o ponteiro *L não é alterado, a passagem poderia ser por valor No entanto, afim de prever mudança de estrutura ela fica por referência ##234587120132 L1*L L Aqui, no pior caso, T(n) é O(n)
72
f) Deletar e retornar o elemento da posição p da lista L: int Deletando (posicao p, lista *L) { posicao q; int x; if (p == NULL || p->prox == NULL) Erro ("Posicao nao existe"); else { q = p->prox; x = q->elem; p->prox = q->prox; free (q); return x; }} void main () { lista L1; posicao p; int x; - - - - - x = Deletando (p, &L1); } ##3358 p (main) 4 L1 retorno x L *L 4 4 x (main) p q 4 As variáveis da função Deletando são desalocadas
73
f) Deletar e retornar o elemento da posição p da lista L: int Deletando (posicao p, lista *L) { posicao q; int x; if (p == NULL || p->prox == NULL) Erro ("Posicao nao existe"); else { q = p->prox; x = q->elem; p->prox = q->prox; free (q); return x; }} ##3358 L1 A rigor, na função Deletando, seria necessário verificar se p é uma posição em *L Em muitos contextos, isso é garantido O parâmetro *L é portanto dispensável Só seria necessário para prever a troca da estrutura para listas Aqui, no pior caso, T(n) é O(1)
74
g) Deletar um elemento de uma lista ordenada: void DeletarOrdenado (int x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); if (p->prox != NULL && p->prox->elem == x) Deletar (p); } ##234587120132 void main () { lista L1; int x; - - - - - DeletarOrdenado (x, &L1); } L1 L *L 120 x (main) 120 x
75
g) Deletar um elemento de uma lista ordenada: void DeletarOrdenado (int x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); if (p->prox != NULL && p->prox->elem == x) Deletar (p); } p 120 x L ##234587120132 L1*L
76
g) Deletar um elemento de uma lista ordenada: void DeletarOrdenado (int x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); if (p->prox != NULL && p->prox->elem == x) Deletar (p); } ##234587120132 Encontrada a posição de deleção 120 x L L1*L p
77
g) Deletar um elemento de uma lista ordenada: void DeletarOrdenado (int x, lista *L) { posicao p; for (p = *L; p->prox != NULL && p->prox->elem prox); if (p->prox != NULL && p->prox->elem == x) Deletando (p, L); } Como o ponteiro *L não é alterado a passagem poderia ser por valor 120 x L ##234587120132 L1*L p Aqui, no pior caso, T(n) é O(n)
78
h) Posição de um elemento numa lista: posicao Local (int x, lista L) { posicao p; p = L; while (p->prox != NULL && p->prox->elem != x) p = p->prox; return p; } L1 ##217451321204932 void main () { lista L1; int x; - - - - - p = Local (x, L1); } p L 120 x x Ponteiro retornado Aqui, no pior caso, T(n) é O(n)
79
i) Esvaziar uma lista: void Esvaziar (lista *L) { posicao p; if (*L == NULL) Erro ("A lista nao foi inicializada"); else { while ((*L)->prox != NULL) { p = (*L)->prox; (*L)->prox = p->prox; free (p); free (p);}}} ##217451321204932 void main () { lista L1; - - - - - Esvaziar (&L1); } E assim por diante, permanecendo apenas o nó-líder L1*L L ppp
80
i) Esvaziar uma lista: void Esvaziar (lista *L) { posicao p; if (*L == NULL) Erro ("A lista nao foi inicializada"); else { while ((*L)->prox != NULL) { p = (*L)->prox; (*L)->prox = p->prox; free (p); free (p);}}} ## void main () { lista L1; - - - - - Esvaziar (&L1); } Como o ponteiro *L não é alterado a passagem poderia ser por valor L1*L L Aqui, no pior caso, T(n) é O(n)
81
j) Outros operadores: Elemento (p, L): p->prox->elemento Elemento (p, L): p->prox->elemento Primeira (L): L Primeira (L): L Próxima (p, L): p->prox Próxima (p, L): p->prox Prévia (p, L): ponteiro para o nó anterior àquele apontado por p; exige percurso sobre boa parte da lista; é ineficiente Prévia (p, L): ponteiro para o nó anterior àquele apontado por p; exige percurso sobre boa parte da lista; é ineficiente L ##217451321204932 p Para os 3 primeiros operadores, T(n) é O(1) Para o quarto, é O(n) no pior caso
82
2.3.3 – Comparação entre as estruturas contígua e encadeada Qual a melhor? - depende de quais operações serão mais frequentes e do tamanho que essas listas podem vir a ter Qual a melhor? - depende de quais operações serão mais frequentes e do tamanho que essas listas podem vir a ter Não sendo possível estabelecer limites para o tamanho da lista: melhor e estrutura encadeada Não sendo possível estabelecer limites para o tamanho da lista: melhor e estrutura encadeada A seguir, uma tabela comparativa de tempo de execução para os operadores básicos A seguir, uma tabela comparativa de tempo de execução para os operadores básicos
83
Tabela de tempo de execução, no pior caso, para as 2 estruturas: Tabela de tempo de execução, no pior caso, para as 2 estruturas: OperaçõesEstr. ContíguaEstr. Encadeada FimO(1)O(n) NovaListaO(n) EscreverO(n) InserirO(n)O(1) DeletandoO(n)O(1) LocalO(n) ElementoO(1) PrimeiraO(1) ProximaO(1) PreviaO(1)O(n) EsvaziarO(1)O(n)
84
Na utilização de memória: Na utilização de memória: Estrutura contígua gasta memória mesmo com listas pequenas Estrutura encadeada gasta memória com ponteiros
Apresentações semelhantes
© 2025 SlidePlayer.com.br Inc.
All rights reserved.