Prof. Rafael Mesquita rgm@cin.ufpe.br Listas Encadeadas Prof. Rafael Mesquita rgm@cin.ufpe.br.

Slides:



Advertisements
Apresentações semelhantes
Recursividade Prof. Rosana Palazon.
Advertisements

Listas encadeadas Prof. Rosana Palazon.
Listas duplamente encadeadas
Lista Encadeada Circular Lista Duplamente Encadeada
ALGORITMOS E ESTRUTURAS DE DADOS
exercícios listas encadeadas
Lista Encadeada Circular Lista Duplamente Encadeada
Listas lineares Denise Guliato Faculdade de Computação – UFU
UNIVERSIDADE FEDERAL DE MINAS GERAIS Pilhas e Filas Cristiano Arbex Valle Vinicius Fernandes dos Santos
UNIVERSIDADE FEDERAL DE MINAS GERAIS Listas Lineares Cristiano Arbex Valle Vinicius Fernandes dos Santos
Métodos de Pesquisa e Ordenação Estruturas de Dados Melissa Marchiani Palone Zanatta.
Estrutura de Dados (DPADF 0056) Aula 7 – Encadeamento de Memória Universidade Federal de Santa Maria Colégio Agrícola de Frederico Westphalen Curso Superior.
Linguagem de Programação – Aula 03 Prof. Me. Ronnison Reges Vidal.
1 Aula 11 Matrizes Prof. Filipe Mutz. Matrizes São estruturas de dados usadas para armazenar informações multidimensionais (que possuem mais de uma dimensão).
Linguagens de Programação Conceitos e Técnicas Definições e declarações Prof. Isabel Cafezeiro
Diagrama de Use Cases. Objetivo  O Diagrama de Use Cases tem o objetivo de auxiliar a comunicação entre os analistas e o cliente.
Algoritmos e Estruturas de Dados I
Introdução à Computação para Engenharia MAC2166
Introdução e Conceitos.
INF1007: Programação 2 8 – Listas Encadeadas
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2016
Algoritmos e Estruturas de Dados I
Ordenação dos Elementos de um Vetor - Bubble Sort e Quick Sort .
Programação em C Aula 8.
Capítulo II – Listas Lineares Gerais
Orientação a Objetos - Programação em C++
Diagrama de Use Cases.
Fundamentos de Programação 1
Estruturas de Repetição
Linguagem C Para programadores Python
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas
INF1007 – Programação 2 9 – Pilhas
Capítulo VIII – Técnicas de Ordenação
Algoritmos e Estruturas de Dados I
Prof. Wellington Franco
Estrutura de dados Pilhas e filas
Prof. Wellington Franco Manipulação de Arquivos em C
Árvores.
Algoritmos e Estruturas de Dados I
Análise de Algoritmo Profº Me. Jeferson Bussula Pinheiro
FUNDAMENTO DE PROGRAMAÇÃO
IP – Repetições Prof. Eduardo Falcão.
UNIDADE 7 Tipos estruturados
INE 5201 – INTRODUÇÃO À CIÊNCIA DA COMPUTAÇÃO
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS
Algoritmos e Programação MC102
Listas Encadeadas.
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2017
Organização básica de arquivos
Ementário Noções de hardware e software. Conceitos Fundamentais.
Estruturas de Dados Dinâmicas
Estruturas de Dados aula 4
Relembrando... Variáveis : endereçam uma posição de memória que contem um determinado valor dependendo do seu tipo (char, int, float, double, ...) void.
Complexidade de Algoritmos
Função de buscar elemento na lista simplesmente encadeada
Linguagem de Programação II
Árvores Binárias de Pesquisa e Balanceamento usando Árvores AVL
Estruturas de Dados aula 3
Prof. Rafael Mesquita Pilha Prof. Rafael Mesquita
Filas Prof. Kariston Pereira
Continuação.
Prof. Rafael Mesquita Fila Prof. Rafael Mesquita
Filas.
Arrays de caracteres: strings
Algoritmos de ordenação
Ementário Noções de hardware e software. Conceitos Fundamentais.
Ponteiros.
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2019
Aula 7 Professores: Conteúdo: Dante Corbucci Filho
Aula 8 Professores: Conteúdo: Dante Corbucci Filho
Transcrição da apresentação:

Prof. Rafael Mesquita rgm@cin.ufpe.br Listas Encadeadas Prof. Rafael Mesquita rgm@cin.ufpe.br

O que veremos nesta aula? Motivação Estruturas de dados estáticas vs. dinâmicas Limitações no uso de vetores Listas encadeadas simples Características Definição da Estrutura Operações básicas Vantagens e desvantagens Exercícios

Motivação Vetores int meuVetor[10]; Limitações? Tamanho fixo: quantidade de elementos não pode ser maior que a quantidade declarada Disperdício de memória Caso todas as posições não sejam utilizadas

Motivação Vetores Alocação dinâmica resolve o problema? int* meuVetor = (int*) malloc(n*sizeof(int)); Não completamente!! Uma vez que a memória é alocada, os mesmos problemas de limitação de espaço e disperdício de memória existirão!

Motivação Considere o seguinte vetor de float como você faria para inserir ou remover um elemento em uma posição específica, mantendo a ordem crescente? Por exemplo, inserir 2.5... Ou remover o elemento 3... Problema: elementos posteriores precisam ser reorganizados 1 2 3 4.5 7.6

Lista encadeada Resolve os problemas mencionados nos slides anteriores Maior flexibilidade que vetores Conjunto de dados pode crescer ou diminuir Evita o disperdício de memória Elementos podem ser inseridos ou removidos em posições específicas Sem necessidade de reordenação do restante dos elementos

Lista encadeada Características principais ref info 1 info 2 info 3 Estrutura sequencial Cada elemento (ou nó) da lista possui Um campo ‘informação’ Um campo ponteiro para o próximo elemento ref info 1 prox info 2 prox info 3

Lista encadeada Características principais ref info 1 info 2 info 3 Caso não exista um próximo elemento, ponteiro ‘prox’ deve ser NULL Indica o fim da lista Existe, ainda, um ponteiro externo (‘ref’) que aponta para o primeiro nó da lista ‘ref’ é do tipo ponteiro para lista (ou para um nó da lista) ref info 1 prox info 2 prox info 3

Lista encadeada Implementação: novo tipo de dado struct lista{ int info; struct lista* prox; }; typedef struct lista Lista; info prox

Lista encadeada Implementação: criação de uma nova lista Lista* criaLista() { return NULL; } Quando a lista é criada, temos uma lista vazia: Não existe nenhum elemento A referência para a lista aponta para NULL Garante que o último elemento da lista aponta para NULL int main() { Lista* ref = criaLista(); ... }

Lista encadeada Implementação: Inserção Função deve receber a lista onde o novo elemento será inserido E o valor da informação do novo elemento Um inteiro no nosso exemplo Abordagem utilizada nesta aula: Inserir sempre no início da lista Mais eficiente do que inserir no meio ou no final da lista

Lista encadeada Implementação: inserção no início da lista Lista* ref info 1 prox info 2 prox info 3

Lista encadeada Implementação: inserção no início da lista Lista* ref info 1 prox info 2 prox info 3 Lista* insere(Lista* ref, int valor) { Lista* novoNo = (Lista*)malloc(sizeof(Lista)); novoNo->info = valor; novoNo->prox = ref; ref = novoNo; return ref; } info 0 prox Novo elemento inserido!

Lista encadeada Detalhe: cópia de ‘ref’ é modificada em insere() Lista* ref NULL 1 ref é uma cópia de ref int main() { Lista* ref = NULL; ref = insere(ref, 1); ... Lista* insere(Lista* ref, int valor) { Lista* novoNo = (Lista*)malloc(sizeof(Lista)); novoNo->info = valor; novoNo->prox = ref; ref = novoNo; return ref; }

Lista encadeada Implementação: Impressão Após inserção de elementos, é importante imprimir a lista para testar se o funcionamento está correto Mesmo vale após remoção de elementos Cada nó da lista deve ser acessado, e sua informação impressa

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox p

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 p void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 p void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 p void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 p void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox p = NULL

Lista encadeada Implementação: impressão da lista Lista* ref info 1 prox info 2 prox info 3 void imprimir(Lista* ref) { Lista* p; printf("\nImprimindo a lista:\n"); if (ref == NULL){ printf("Lista vazia!"); return; } for (p = ref; p != NULL; p = p->prox) printf("%d ", p->info); info 0 prox p = NULL

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Função deve buscar um determinado elemento para ser removido Ponteiro ‘p’ percorre a lista até que o elemento a ser removido seja encontrado Suponha a seguinte tentativa de remoção do nó ‘p’ Como acessar o nó 3 se a sua referência foi perdida? Lista* ref p 1 prox 2 prox 3 prox 4

Lista encadeada Remoção de elementos Função deve buscar um determinado elemento para ser removido Ponteiro ‘p’ percorre a lista até que o elemento a ser removido seja encontrado Solução para problema da referência: Uso de ponteiro auxiliar ‘ant’, que também percorre a lista ‘ant’ deve estar sempre em uma posição anterior a ‘p’

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Ex: Remover elemento com valor 3 Lista* ref ant = NULL p 1 prox 2 prox 3 prox 4 Lista* remove(Lista* ref, int valor) { Lista* ant=NULL; Lista* p = ref;

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Ex: Remover elemento com valor 3 Lista* ref ant = NULL p ant 1 prox 2 prox 3 prox 4 while (p != NULL && p->info != elemBuscado) { ant = p; p = p->prox; }

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Ex: Remover elemento com valor 3 Lista* ref p ant p 1 prox 2 prox 3 prox 4 while (p != NULL && p->info != elemBuscado) { ant = p; p = p->prox; }

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Ex: Remover elemento com valor 3 Lista* ref ant p ant 1 prox 2 prox 3 prox 4 while (p != NULL && p->info != elemBuscado) { ant = p; p = p->prox; }

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Ex: Remover elemento com valor 3 Lista* ref p ant p 1 prox 2 prox 3 prox 4 while (p != NULL && p->info != elemBuscado) { ant = p; p = p->prox; }

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Ex: Remover elemento com valor 3 Lista* ref ant p 1 prox 2 prox 3 prox 4 if (p == NULL) //elemento não encontrado return ref; //remove primeiro elemento if (p == ref) ref = p->prox; else //remove do meio ou fim da lista ant->prox = p->prox;

Lista encadeada Remoção de elementos Lista* ref 1 2 3 4 Ex: Remover elemento com valor 3 Lista* ref ant p 1 prox 2 prox 3 prox 4 free(p); return ref; }

Lista encadeada Remoção de elementos Lista* ref info 1 info 2 info 3 Caso específico: remoção do primeiro elemento da lista Lista* ref p info 1 prox info 2 prox info 3 if (p == ref) ref = p->prox;

Lista encadeada Remoção de elementos Lista* ref info 1 info 2 info 3 Caso específico: remoção do primeiro elemento da lista Lista* ref p info 1 prox info 2 prox info 3 if (p == ref) ref = p->prox;

Lista encadeada Remoção de elementos Lista* ref info 1 info 2 info 3 Caso específico: remoção do primeiro elemento da lista Lista* ref p info 1 prox info 2 prox info 3 free(p); return ref;

Lista encadeada Liberando a memória da Lista Caso específico: remoção do primeiro elemento da lista Passagem de ponteiro para ponteiro Alternativa para modificar ref sem ter que retornar nada void libera(Lista** lista) { Lista* l = *lista; while (l != NULL) Lista* aux = l->prox; free(l); l = aux; } *lista = NULL;

Lista encadeada int main() { Lista* ref = criaLista(); ref = insere(ref, 1); ref = insere(ref, 2); ref = insere(ref, 3); ref = insere(ref, 4); imprimir(ref); ref = remove(ref, 2); ref = remove(ref, 4); 4 3 2 1 4 3 1 3 1 3 1

Lista encadeada 3 Lista vazia! 6 5 Lista vazia! 8 7 ref = remove(ref, 1); imprimir(ref); ref = remove(ref, 3); ref = insere(ref, 5); ref = insere(ref, 6); libera(&ref); ref = insere(ref, 7); ref = insere(ref, 8); printf("\n\nFim!"); getchar(); return 0; } 3 Lista vazia! 6 5 Lista vazia! 8 7

Lista encadeada circular Considere uma lista simples, e um ponteiro ‘p’ que aponta para algum dos elementos da lista Problema: a partir de ‘p’, não podemos acessar os elementos anteriores a ‘p’ Solução: Último nó aponta para o primeiro Definição de lista circular! info 1 prox info 2 prox info 3 prox

Lista encadeada circular Não existe uma definição exata do primeiro e último elementos da lista No entanto, pode ser adotada uma convenção Referência para lista aponta para o último elemento Assim, pode-se facilmente realizar inserções no início ou no fim da lista Lista* ref primeiro nó último nó info 1 prox info 2 prox info 3 prox

Lista encadeada circular Para percorrer uma lista não-circular, testamos se o elemento acessado é NULL for (aux = ref; aux != NULL; aux = aux->prox) … Em uma lista circular, deve ser mantida a referência para o último nó da lista A cada elemento acessado, deve ser verificado se o fim da lista foi alcançado Válido para busca, impressão de elementos, etc... for (aux = ref->prox; aux != ref; aux = aux->prox) Após o laço, último nó deve ser processado!

Lista encadeada circular Inserção em uma lista vazia Ponteiro ‘próximo’ deve apontar para o próprio elemento if (ref == NULL) { } Lista* ref novoNo->prox = novoNo; novoNo ref = novoNo; info prox

Lista encadeada circular Inserção em uma lista contendo pelo menos um elemento Insere no início Lista* ref novoNo if (ref == NULL) { novoNo->prox = novoNo; ref = novoNo; } info prox info prox else { } novoNo->prox = ref->prox;

Lista encadeada circular Inserção em uma lista contendo pelo menos um elemento Insere no início Lista* ref novoNo if (ref == NULL) { novoNo->prox = novoNo; ref = novoNo; } info prox info prox else { } novoNo->prox = ref->prox; ref->prox = novoNo;

Lista encadeada circular Inserção em uma lista circular Lista* insereCircular(Lista* ref, int info) { Lista* novoNo = (Lista*)malloc(sizeof(Lista)); novoNo->info = info; if (ref == NULL) novoNo->prox = novoNo; ref = novoNo; } else novoNo->prox = ref->prox; ref->prox = novoNo; return ref;

Lista encadeada circular Remoção de elementos Ponteiro ‘p’ percorre a lista até que o elemento a ser removido seja encontrado Ponteiro auxiliar ‘ant’ também percorre a lista, estando sempre em uma posição anterior a ‘p’ Uma vez que o elemento é encontrado, o ponteiro de ‘ant’ aponta para o elemento apontado pelo ponteiro de ‘p’ ...e ‘p’ é removido e sua memória liberada

Lista encadeada circular Remoção de elementos Ocorre de modo similar à remoção em uma lista simples Porém, para encerrar busca elemento de referência é utilizado No caso de listas simples, sabemos que o elemento que aponta para NULL é o último da lista

Lista encadeada circular Remoção de elementos Alguns tratamentos específicos Remoção do único elemento de uma lista deve retornar NULL Referencia externa para a lista recebe valor NULL, indicando que a lista se encontra vazia Lista* ref if (p->prox == p) { free(p); return NULL; } info prox

Lista encadeada circular Remoção de elementos Alguns tratamentos específicos Caso o elemento a ser removido seja a referencia da lista Referência deve ser atualizada Nova referência deve ser o elemento anterior if (p == ref) ref = ant;

Lista encadeada circular Remoção de elementos Lista* removeCircular(Lista* ref, int elemBuscado) { Lista* p; Lista* ant; if (ref == NULL) return ref; p = ref->prox; ant = ref; while (p->info != elemBuscado && p != ref) ant = p; p = p->prox; }

Lista encadeada circular Remoção de elementos if (p->info == elemBuscado) { if (p->prox == p) free(p); return NULL; } if (p == ref) ref = ant; ant->prox = p->prox; p = NULL; return ref;

Lista encadeada circular Impressão de elementos void imprimeListaCircular(Lista* ref) { Lista* aux; printf("\nimprimindo lista:\n"); if (ref == NULL) printf("\nLista vazia!\n"); return; } for (aux = ref->prox; aux != ref; aux = aux->prox) printf("%d ", aux->info);

Mais Variações Lista duplamente encadeada Lista circular duplamente encadeada left info right left info right left info right left info right left info right left info right

Vantagens em relação ao uso de vetores Maior flexibilidade Conjunto de dados pode crescer ou diminuir Evita o disperdício de memória Elementos podem ser removidos em posições específicas E também inseridos em posições específicas Mostre nos exercícios!

Desvantagens em relação ao uso de vetores Acesso sequencial Para alcançar o n-ésimo elemento, os ‘n-1’ elementos anteriores a ‘n’ devem ser acessados Com vetores Acesso constante meuVetor[n] Acesso mais rápido

Exercícios Crie sua própria implementação de Lista Encadeada, com as funcionalidades apresentadas nesta aula Modifique a lista da questão 1 para armazenar inteiros na ordem crescente Elementos podem ser inseridos no meio ou no final da lista! Modifique a operação ‘remover’ para que seja mais eficiente do que na lista da questão 1 (somente a parte necessária da lista deve ser processada)