View
234
Download
0
Category
Preview:
Citation preview
INE5408Estruturas de Dados
Listas EncadeadasSimples
Listas com Vetores: Desvantagens
4
554128924 5
55412892420
• Tamanho máximo fixo;• mesmo vazias ocupam um grande
espaço de memória:– mesmo que utilizemos um vetor de
ponteiros, se quisermos prever uma lista de 10.000 elementos, teremos 40.000 bytes desperdiçados;
• operações podem envolver muitos deslocamentos de dados:– inclusão em uma posição ou no
início;– exclusão em uma posição ou no
início.
Listas Encadeadas• São listas onde cada elemento
está armazenado em uma Classe chamada elemento de lista;
• cada elemento de lista referencia o próximo e só é alocado dinamicamente quando necessário;
• para referenciar o primeiro elemento utilizamos uma Classe cabeça de lista.
Listas Encadeadas
5
melãoinfo próximo
maçãinfo próximo
uvainfo próximo
nro dados Cabeçade Lista
Elemento de Lista
Modelagem: Cabeça de Lista• Necessitamos:
– um ponteiro para o primeiro elemento da lista;– um inteiro para indicar quantos elementos a lista
possui.
• Pseudo-código:classe tLista {
tElemento *dados;inteiro tamanho;
};
Modelagem: Elemento de Lista• Necessitamos:
– um ponteiro para o próximo elemento da lista;– um campo do tipo da informação que vamos
armazenar.
• Pseudo-código:class tElemento {
tElemento *próximo;tipo-que-eu-vou-usar-nesta-aplicação info;
};
Listas Encadeadas: Modelagem• Para tornar todos os algoritmos da lista mais genéricos, fazemos
o campo info ser um ponteiro para um elemento de informação.
3
info próximo info próximo info próximo
nro dados
Elemento de Informação(tipoInfo)
melãodocecaro
maçãazedacara
uvairkh
barata
Modelagem: Elemento de Lista• Pseudo-código da Classe elemento de
lista:
class tElemento {tElemento *próximo;TipoInfo *info;
};
• Local: lista.h
Ao invés de colocar a Informação no elemento de lista, usamos um ponteiro para ela.
Modelagem: Elemento de Dados• Pseudo-código da Classe TipoInfo:
class TipoInfo {tipo-do-campo1 campo1;tipo-do-campo2 campo2;…tipo-do-campoN campoN;
}
• Local: info.h
Modelagem: Elemento de Dados• Razões para a modelagem do TipoInfo:
– vamos na maioria dos algoritmos trabalhar com algum elemento de informação;
– se este elemento é somente um ponteiro para um TipoInfo, não importando o que este seja, teremos algoritmos totalmente genéricos:
• posso usar o mesmo código de lista para muitas aplicações diferentes simplesmente recompilando.
• somente modifico um único headerfile: info.h
• Desvantagens:– o algoritmo de destruição da lista
torna-se mais complexo.– TipoInfo necessita de um destrutor próprio
Modelagem: Aspecto Funcional3 Categorias de Operações:• colocar e retirar dados da lista;• testar se a lista está vazia e outros testes;• inicializá-la e garantir a ordem dos elementos.
5
melãodocecaro
maçãazedacara
uvairkh
barata
Modelagem: Operações da Lista• Operações - colocar e retirar dados da lista:
– Adiciona(dado)– AdicionaNoInício(dado)– AdicionaNaPosição(dado, posição)– AdicionaEmOrdem(dado)
– Retira()– RetiraDoInício()– RetiraDaPosição(posição)– RetiraEspecífico(dado)
Modelagem: Operações da Lista• Operações - testar a lista e outros testes:
– ListaVazia()– Posição(dado)– Contém(dado)
• Operações - inicializar ou limpar:– CriaLista()– DestróiLista()
Algoritmo CriaListaLista* MÉTODO criaLista()
//Retorna ponteiro para uma nova cabeça de lista ou NULO.variáveis
Lista *aLista;início
aLista <- aloque(Lista);SE (aLista ~= NULO) ENTÃO
//Só posso inicializar se consegui alocar.aLista->tamanho <- 0;aLista->dados <- NULO;
FIM SERETORNE(aLista);
fim;
Algoritmo CriaListaLista* MÉTODO criaLista()
//Retorna ponteiro para uma nova cabeça de lista ou NULO.variáveis
Lista *aLista;início
aLista <- aloque(Lista);SE (aLista ~= NULO) ENTÃO
//Só posso inicializar se consegui alocar.aLista->tamanho <- 0;aLista->dados <- NULO;
FIM SERETORNE(aLista);
fim;
Algoritmo CriaListaLista* MÉTODO criaLista()
//Retorna ponteiro para uma nova cabeça de lista ou NULO.variáveis
Lista *aLista;início
aLista <- aloque(Lista);SE (aLista ~= NULO) ENTÃO
//Só posso inicializar se consegui alocar.aLista->tamanho <- 0;aLista->dados <- NULO;
FIM SERETORNE(aLista);
fim;
Algoritmo ListaVaziaBooleano MÉTODO listaVazia()início
SE (tamanho = 0) ENTÃORETORNE(Verdadeiro)
SENÃORETORNE(Falso);
fim;
• Um algoritmo ListaCheia não existe aqui;• verificar se houve espaço na memória para um novo
elemento será responsabilidade de cada operação de adição.
Algoritmo AdicionaNoInício• Procedimento:
– testamos se é possível alocar um elemento;
– fazemos o próximo deste novo elemento ser o primeiro da lista;
– fazemos a cabeça de lista apontar para o novo elemento.
• Parâmetros:– O tipo info (dado) a ser inserido;
Algoritmo AdicionaNoInício
2
maçãazedacara
uvairkh
barata
melãodocecaro
novo
Algoritmo AdicionaNoInício
2
maçãazedacara
uvairkh
barata
melãodocecaro
3
Algoritmo AdicionaNoInícioInteiro MÉTODO adicionaNoInício(TipoInfo *dado)
variáveis tElemento *novo; //Variável auxiliar.início
novo <- aloque(tElemento);SE (novo = NULO) ENTÃO RETORNE(ErroListaCheia);SENÃO novo->próximo <- dados; novo->info <- dado;
dados <- novo; tamanho <- tamanho + 1;
RETORNE(1); FIM SE
fim;
Algoritmo AdicionaNoInícioInteiro MÉTODO adicionaNoInício(TipoInfo *dado)
variáveis tElemento *novo; //Variável auxiliar.início
novo <- aloque(tElemento);SE (novo = NULO) ENTÃO RETORNE(ErroListaCheia);SENÃO novo->próximo <- dados; novo->info <- dado;
dados <- novo; tamanho <- tamanho + 1;
RETORNE(1); FIM SE
fim;
Algoritmo AdicionaNoInícioInteiro MÉTODO adicionaNoInício(TipoInfo *dado)
variáveis tElemento *novo; //Variável auxiliar.início
novo <- aloque(tElemento);SE (novo = NULO) ENTÃO RETORNE(ErroListaCheia);SENÃO novo->próximo <- dados; novo->info <- dado;
dados <- novo; tamanho <- tamanho + 1;
RETORNE(1); FIM SE
fim;
Algoritmo RetiraDoInício
• Procedimento:– testamos se há elementos;– decrementamos o tamanho;– liberamos a memória do elemento;– devolvemos a informação.
Algoritmo RetiraDoInício
3
maçãazedacara
uvairkh
barata
melãodocecaro
saiu
volta
Algoritmo RetiraDoInício
3
maçãazedacara
uvairkh
barata
melãodocecaro
saiu
volta
Algoritmo RetiraDoInício
2
maçãazedacara
uvairkh
barata
melãodocecaro
saiu
volta
Algoritmo RetiraDoInícioTipoInfo* MÉTODO retiraDoInício()
//Elimina o primeiro elemento de uma lista.//Retorna a informação do elemento eliminado ou NULO.variáveis tElemento *saiu; //Variável auxiliar para o primeiro elemento.
TipoInfo *volta; //Variável auxiliar para o dado retornado.início
SE (listaVazia()) ENTÃO RETORNE(NULO);SENÃO saiu <- dados; volta <- saiu->info; dados <- saiu->próximo; tamanho <- tamanho - 1; LIBERE(saiu); RETORNE(volta);FIM SE
fim;
Algoritmo EliminaDoInícioInteiro MÉTODO eliminaDoInício()
//Elimina o primeiro elemento de uma lista e sua respectiva informação.//Retorna a posição do elemento eliminado ou erro.variáveis tElemento *saiu; //Variável auxiliar para o primeiro elemento.início
SE (listaVazia()) ENTÃO RETORNE(ErroListaVazia);SENÃO saiu <- dados; dados <- saiu->próximo; tamanho <- tamanho - 1; LIBERE(saiu->info); LIBERE(saiu); RETORNE(tamanho + 1);FIM SE
fim;
Algoritmo EliminaDoInício• Observe que a linha LIBERE(saiu->info)
possui um perigo:– se o TipoInfo for por sua vez um conjunto estruturado
de dados com referências internas através de ponteiros (outra lista, por exemplo), a chamada à função LIBERE(saiu->info) só liberará o primeiro nível da estrutura (aquele apontado diretamente);
– tudo o que for referenciado através de ponteiros em info permanecerá em algum lugar da memória, provavelmente inatingível (garbage);
– para evitar isto pode-se criar uma função destrói(info) para o TipoInfo que será chamada no lugar de LIBERE.
Exemplo simplificado: Programa Principal#inclua listaEnc.hvariáveis
tLista *devedores, *credores, *listaEscolhida;TipoInfo *dado;caracter opção;
1 Programa Principal2 início3 devedores <- criaLista();4 credores <- criaLista();5 opção <- ´´;6 ENQUANTO (opção ~= ´f´) ENTÃO7 escreveMenu();8 leia(opção);9 CASO opção SEJA10 ´c´: listaEscolhida <- credores;11 ´d´: listaEscolhida <- devedores;12 ´i´: dado <- leiaInfo();13 listaEscolhida.adicionaNoInício(dado);-- - - - - -- - - - - -- FIM CASO-- FIM ENQUANTO -- fim;
• Memória logo após o início do programa, quando o fluxo de execução se encontra na linha #2.
Sist.OperacionalSist.Operacional
10010101...10010101...
devedores, credores,
listaEscolhida, dado, opção
HeapPointerTopo da ÁreaAlocável
StackPointerTopo da Pilha
Base da Memória
Variáveis estáticas(globais)
Código objetodo Programa
• Memória logo após as 2 chamadas à função criaLista(), quando o fluxo de execução do programa se encontra na linha #5.
Sist.OperacionalSist.Operacional
10010101...10010101...
devedores, credores,
listaEscolhida, dado, opção
HeapPointerTopo da ÁreaAlocável
StackPointerTopo da Pilha
Base da Memória
Variáveis estáticas(globais)
Código objetodo Programa
Lista
Lista
• Memória imediatamente antes de retornar de uma chamada à função adicionaNoInício(), quando a listaEscolhida é a dos credores e o fluxo de execução do programa se encontra na última linha da função adicionaNoInício() e retornará ao programa principal para a linha #13.
Sist.OperacionalSist.Operacional
10010101...10010101...
devedores, credores,
listaEscolhida, dado, opção
HeapPointerTopo da ÁreaAlocável
StackPointerTopo da Pilha
Base da Memória
Variáveis estáticas(globais)
Código objetodo Programa
Lista
Lista
&progr. #13 lista dado novo
TipoInfo
Elemento
Algoritmo AdicionaNaPosição• Procedimento:
– testamos se a posição existe e se é possível alocar elemento;
– caminhamos até a posição;– adicionamos o novo dado na posição;– incrementamos o tamanho.
• Parâmetros:– o dado a ser inserido;– a posição onde inserir;
Algoritmo AdicionaNaPosição
3
melãodocecaro
novo
maçãazedacara
uvairkh
barata
maçãazedacara
anterior
Algoritmo AdicionaNaPosição
4
melãodocecaro
novo
maçãazedacara
uvairkh
barata
maçãazedacara
anterior
Algoritmo AdicionaNaPosiçãoInteiro MÉTODO adicionaNaPosição(TipoInfo *info,
inteiro posição)//Adiciona novo elemento na posição informada.//Retorna o novo número de elementos da lista ou erro.variáveis tElemento *novo, *anterior; //Ponteiros auxiliares.início SE (posição > tamanho + 1) ENTÃORETORNE(ErroPosição) SENÃOSE (posição = 1) ENTÃO RETORNE(adicionaNoInício(info);SENÃO novo <- aloque(tElemento); SE (novo = NULO) ENTÃO RETORNE(ErroListaCheia); SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; novo->próximo <- anterior->próximo; novo->info <- info; anterior->próximo <- novo; tamanho <- tamanho + 1; RETORNE(aLista->tamanho); FIM SE FIM SE FIM SEfim;
Algoritmo AdicionaNaPosiçãoInteiro MÉTODO adicionaNaPosição(TipoInfo *info,
inteiro posição)//Adiciona novo elemento na posição informada.//Retorna o novo número de elementos da lista ou erro.variáveis tElemento *novo, *anterior; //Ponteiros auxiliares.início SE (posição > tamanho + 1) ENTÃORETORNE(ErroPosição) SENÃOSE (posição = 1) ENTÃO RETORNE(adicionaNoInício(aLista, info);SENÃO novo <- aloque(tElemento); SE (novo = NULO) ENTÃO RETORNE(ErroListaCheia); SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; novo->próximo <- anterior->próximo; novo->info <- info; anterior->próximo <- novo; tamanho <- tamanho + 1; RETORNE(tamanho); FIM SE FIM SE FIM SEfim;
Algoritmo AdicionaNaPosiçãoInteiro MÉTODO adicionaNaPosição(TipoInfo *info,
inteiro posição)//Adiciona novo elemento na posição informada.//Retorna o novo número de elementos da lista ou erro.variáveis tElemento *novo, *anterior; //Ponteiros auxiliares.início SE (posição > tamanho + 1) ENTÃORETORNE(ErroPosição) SENÃOSE (posição = 1) ENTÃO RETORNE(adicionaNoInício(info);SENÃO novo <- aloque(tElemento); SE (novo = NULO) ENTÃO RETORNE(ErroListaCheia); SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; novo->próximo <- anterior->próximo; novo->info <- info; anterior->próximo <- novo; tamanho <- tamanho + 1; RETORNE(tamanho); FIM SE FIM SE FIM SEfim;
Algoritmo AdicionaNaPosiçãoInteiro MÉTODO adicionaNaPosição(TipoInfo *info,
inteiro posição)//Adiciona novo elemento na posição informada.//Retorna o novo número de elementos da lista ou erro.variáveis tElemento *novo, *anterior; //Ponteiros auxiliares.início SE (posição > tamanho + 1) ENTÃORETORNE(ErroPosição) SENÃOSE (posição = 1) ENTÃO RETORNE(adicionaNoInício(info);SENÃO novo <- aloque(tElemento); SE (novo = NULO) ENTÃO RETORNE(ErroListaCheia); SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; novo->próximo <- anterior->próximo; novo->info <- info; anterior->próximo <- novo; tamanho <- tamanho + 1; RETORNE(tamanho); FIM SE FIM SE FIM SEfim;
Algoritmo RetiraDaPosição• Procedimento:
– testamos se a posição existe;– caminhamos até a posição;– retiramos o dado da posição;– decrementamos o tamanho.
• Parâmetros:– a posição de onde retirar;
Algoritmo RetiraDaPosição
4
maçãazedacara
uvairkh
barata
melãodocecaro
anterior
jacairkh
barata
eliminar
Posições > 1
Algoritmo RetiraDaPosição
4
maçãazedacara
uvairkh
barata
melãodocecaro
anterior
jacairkh
barata
eliminar
Posições > 1
Algoritmo RetiraDaPosição
4
maçãazedacara
melãodocecaro
anterior
jacairkh
barata
eliminar
Posições > 1
Algoritmo RetiraDaPosição
3
maçãazedacara
melãodocecaro
anterior
jacairkh
barata
eliminar
Posições > 1
Algoritmo RetiraDaPosição
3
maçãazedacara
melãodocecaro
jacairkh
barata
Posições > 1
Algoritmo RetiraDaPosiçãoTipoInfo* MÉTODO retiraDaPosição(inteiro posição)
//Elimina o elemento da posição de uma lista.//Retorna a informação do elemento eliminado ou NULO.variáveis tElemento *anterior, *eliminar; //Variável auxiliar para elemento.TipoInfo *volta; //Variável auxiliar para o dado retornado.início SE (posição > tamanho) ENTÃORETORNE(NULO); SENÃOSE (posição = 1) ENTÃO RETORNE(retiraDoInício(aLista));SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; eliminar <- anterior->próximo; volta <- eliminar->info; anterior->próximo <- eliminar->próximo; tamanho <- tamanho - 1; LIBERE(eliminar); RETORNE(volta);FIM SE FIM SEfim;
Algoritmo RetiraDaPosiçãoTipoInfo* MÉTODO retiraDaPosição(inteiro posição)
//Elimina o elemento da posição de uma lista.//Retorna a informação do elemento eliminado ou NULO.variáveis tElemento *anterior, *eliminar; //Variável auxiliar para elemento.TipoInfo *volta; //Variável auxiliar para o dado retornado.início SE (posição > tamanho) ENTÃORETORNE(NULO); SENÃOSE (posição = 1) ENTÃO RETORNE(retiraDoInício());SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; eliminar <- anterior->próximo; volta <- eliminar->info; anterior->próximo <- eliminar->próximo; tamanho <- tamanho - 1; LIBERE(eliminar); RETORNE(volta);FIM SE FIM SEfim;
Algoritmo RetiraDaPosiçãoTipoInfo* MÉTODO retiraDaPosição(inteiro posição)
//Elimina o elemento da posição de uma lista.//Retorna a informação do elemento eliminado ou NULO.variáveis tElemento *anterior, *eliminar; //Variável auxiliar para elemento.TipoInfo *volta; //Variável auxiliar para o dado retornado.início SE (posição > tamanho) ENTÃORETORNE(NULO); SENÃOSE (posição = 1) ENTÃO RETORNE(retiraDoInício());SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; eliminar <- anterior->próximo; volta <- eliminar->info; anterior->próximo <- eliminar->próximo; tamanho <- tamanho - 1; LIBERE(eliminar); RETORNE(volta);FIM SE FIM SEfim;
Algoritmo RetiraDaPosiçãoTipoInfo* MÉTODO retiraDaPosição(inteiro posição)
//Elimina o elemento da posição de uma lista.//Retorna a informação do elemento eliminado ou NULO.variáveis tElemento *anterior, *eliminar; //Variável auxiliar para elemento.TipoInfo *volta; //Variável auxiliar para o dado retornado.início SE (posição > tamanho) ENTÃORETORNE(NULO); SENÃOSE (posição = 1) ENTÃO RETORNE(retiraDoInício(aLista));SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; eliminar <- anterior->próximo; volta <- eliminar->info; anterior->próximo <- eliminar->próximo; tamanho <- tamanho - 1; LIBERE(eliminar); RETORNE(volta);FIM SE FIM SEfim;
Algoritmo RetiraDaPosiçãoTipoInfo* MÉTODO retiraDaPosição(inteiro posição)
//Elimina o elemento da posição de uma lista.//Retorna a informação do elemento eliminado ou NULO.variáveis tElemento *anterior, *eliminar; //Variável auxiliar para elemento.TipoInfo *volta; //Variável auxiliar para o dado retornado.início SE (posição > tamanho) ENTÃORETORNE(NULO); SENÃOSE (posição = 1) ENTÃO RETORNE(retiraDoInício(aLista));SENÃO anterior <- dados; REPITA (posição - 2) VEZESanterior <- anterior->próximo; eliminar <- anterior->próximo; volta <- eliminar->info; anterior->próximo <- eliminar->próximo; tamanho <- tamanho - 1; LIBERE(eliminar); RETORNE(volta);FIM SE FIM SEfim;
Modelagem do Tipo Info• Para inserção em ordem e para achar um
elemento determinado, necessitamos da capacidade de comparar informações associadas aos elementos;– estas operações de comparação fazem parte do
Classe TipoInfo e não da lista;– devem ser implementadas como tal.
• Operações: testar AS INFORMAÇÕES:– Igual(dado1, dado2)– Maior(dado1, dado2)– Menor(dado1, dado2)
Algoritmo AdicionaEmOrdem• Procedimento:
– necessitamos de um método para comparar os dados (maior);
– procuramos pela posição onde inserir comparando dados;
– chamamos adicionaNaPosição().• Parâmetros:
– o dado a ser inserido;
Algoritmo AdicionaEmOrdemInteiro MÉTODO adicionaEmOrdem(TipoInfo dado)
variáveis tElemento *atual; //Variável auxiliar para caminhar. inteiro posição;início SE (listaVazia(aLista)) ENTÃO RETORNE(adicionaNoInício(dado)); SENÃO atual <- dados; posição <- 1; ENQUANTO (atual->próximo ~= NULO E maior(dado, atual->info)) FAÇA //Encontrar posição para inserir. atual <- atual->próximo; posição <- posição + 1;FIM ENQUANTOSE maior(dado, atual->info) ENTÃO //Parou porque acabou a lista. RETORNE(adicionaNaPosição(dado, posição + 1));SENÃO RETORNE(adicionaNaPosição(dado, posição));FIM SE
FIM SEfim;
Algoritmos Restantes• Por conta do aluno:
– Adiciona(dado)– Retira()– RetiraEspecífico(dado)
• Operações - inicializar ou limpar:– DestróiLista()
Algoritmo DestróiListaFUNÇÃO destróiLista(tLista *aLista)
variáveis tElemento *atual, *anterior; //Variável auxiliar para caminhar.início SE (listaVazia(aLista)) ENTÃO
LIBERE(aLista); SENÃO atual <- aLista->dados; ENQUANTO (atual ~= NULO) FAÇA
//Eliminar até o fim. anterior <- atual; //Vou para o próximo mesmo que seja nulo. atual <- atual->próximo; //Liberar primeiro a Info. LIBERE(anterior->info); //Liberar o elemento que acabei de visitar. LIBERE(anterior);FIM ENQUANTOLIBERE(aLista);
FIM SEfim;
Recommended