dispostos linearmente, seguindo ou não determinada organização, como [E1, E2, E3, E4, E5, ..., En], onde n deve ser maior ou igual a zero. • São estruturas de dados mais flexíveis do que as pilhas e as filas, pois permitem a manipulação de elementos em qualquer posição; como exemplo, podemos citar listas de alunos, de compras, de telefone, de convidados, entre outras. Listas
• Quando criamos uma estrutura de dados do tipo lista,
podemos utilizar como contêiner, para armazenamento dos dados, um vetor ou uma matriz. Dizemos, então, que se trata de uma lista implementada por meio de arranjo. • Porém, em vez de utilizarmos um contêiner, podemos empregar a alocação dinâmica, na qual dados são armazenados em posições de memória referenciadas, sendo possível, a partir de um elemento, encontrar os próximos — o que chamamos de lista encadeada. Listas encadeadas
• Uma lista encadeada é um conjunto de elementos
dispostos em uma dada organização não linear. Em outras palavras, os elementos estão espalhados pela memória. • Na figura a seguir, temos a representação de uma lista encadeada, com quatro elementos; cada um deles é simbolizado por um nó que possui um compartimento para o valor e outro para referenciar o próximo elemento da lista, se houver. • De acordo com esta implementação, temos, ainda, um nó identificado como primeiro e outro, como último. Listas encadeadas
• Na alocação dinâmica, utilizamos posições
descontinuadas da memória para armazenar cada elemento da lista (nó), o que é possível em função da referência que cada um deles guarda em relação ao outro. • Esta referência pode ser imaginada como o “endereço” da posição de memória em que se localiza o outro elemento, como se fosse um ponteiro ou apontador. Listas encadeadas
• A tabela a seguir mostra uma lista de pagamentos que
devem ser efetuados no mês, dispostos em uma ordem linear. Tipos de listas encadeadas • Existem quatro tipos de listas encadeadas: encadeamento simples, duplamente encadeada, ordenada e circular. • Na lista de encadeamento simples, cada elemento (nó) possui apenas um ponteiro indicando o elemento sucessor ou próximo, como apresentado na figura a seguir. Tipos de listas encadeadas • A lista duplamente encadeada é constituída por elementos que possuem dois ponteiros: o um que aponta para o seu antecessor (chamado anterior) e outro para o seu sucessor (chamado próximo), conforme ilustra a figura a seguir. Tipos de listas encadeadas • Uma lista ordenada é aquela em que a ordem linear de seus elementos corresponde a ordem dos dados armazenados; e, quando um novo elemento é inserido, deve ser colocado na posição que garanta a manutenção desta ordem. • Ela pode ser de encadeamento simples ou duplamente encadeada, desde que mantido o princípio da ordenação, como ocorre na lista de números inteiros representada na figura a seguir. Tipos de listas encadeadas • Na lista circular, o ponteiro próximo (do último elemento) aponta para o primeiro da lista; e o ponteiro anterior (do primeiro elemento) aponta para o último. Operações em listas de encadeamento simples • Nesta seção, apresentaremos os algoritmos que implementam a criação e a manipulação de uma lista de encadeamento simples, ou lista simples. • Para facilitar a compreensão das estruturas, o algoritmo foi dividido em partes, cada uma delas relativa a um tipo de operação, seguida dos comentários. Criação de uma lista simples
• Para o algoritmo em pseudocódigo, utilizamos um
apontador, indicado pelo símbolo “^”, que precede o nome da variável, e estruturas do tipo registro para os dados. • Para a implementação em Java, empregamos uma classe para o nó, e outra para a lista, pois cada objeto do tipo lista é constituído de um ou vários objetos do tipo nó. Criação de uma lista simples Criação de uma lista simples Criação de uma lista simples • Os elementos da lista (NoSimples) possuem os atributos valor, do tipo Object, permitindo maior flexibilidade em relação aos tipos de dados que podem ser armazenados, e prox, do tipo NoSimples, cuja função é referenciar o próximo elemento da lista, fazendo o papel de um apontador. • Esta classe possui um método construtor (linhas 4 a 7) que recebe um objeto como parâmetro e faz a atribuição inicial de nulo a prox, uma vez que o valor deste atributo será tratado em tempo de execução. Criação de uma lista simples Criação de uma lista simples • A classe ListaSimples possui dois atributos do tipo NoSimples, primeiro e ultimo, com a finalidade de fazer referência aos elementos do início e final da lista, respectivamente, e declara um construtor, que inicializa os atributos como nulo, já que a lista, inicialmente, está vazia. • A esta implementação, devem ser acrescidos os métodos das operações descritas nos próximos exemplos, de forma que possa funcionar adequadamente. Operação para inserir um elemento no final da lista simples • Dando prosseguimento à criação da estrutura da lista encadeada, implementamos o procedimento para inserir um elemento (nó) no final da lista, lembrando que, por sua característica, uma lista permite a realização de operações de inserção em qualquer posição. Operação para inserir um elemento no final da lista simples • O código em Java fica bastante semelhante ao pseudocódigo, exceto pelo fato de que os objetos primeiro e ultimo são do tipo NoSimples (não são ponteiros), que guardam a referência para os respectivos elementos. Operação para inserir um elemento no início da lista simples De forma semelhante à inclusão de um elemento no final da lista, é possível inserir um elemento no início, com pequenas alterações no algoritmo. Operação para inserir um elemento no início da lista simples Operação para contar a quantidade de nós da lista simples • Contar a quantidade de elementos de uma lista é uma operação útil, que pode servir simplesmente para averiguar tal informação; para verificar se a lista está vazia; ou, ainda, para verificar o número de nós válidos, auxiliando na execução de outras operações, como a inclusão de um elemento em determinada posição (conforme veremos na próxima seção). Operação para contar a quantidade de nós da lista simples • A função ContarNos() utiliza um elemento temporário, denominado noTemp, que, por meio de uma estrutura de laço, recebe o ponteiro de cada um dos elementos da lista, desde o primeiro até o último, realizando, a cada iteração, o incremento da variável quantidade, que faz o papel de contador e serve como valor de retorno. Operação para inserir um elemento em determinada posição da lista simples • O procedimento para inserir um elemento em determinada posição da lista simples é em especial interessante, pois explora o recurso da estrutura dinâmica que as listas encadeadas possuem. É uma operação bastante eficiente, uma vez que não necessitamos realocar os demais elementos, a exemplo do que ocorre com a implementação, por meio de arranjos. • Na figura a seguir, exibimos a operação de inserção do elemento 2 na lista, na posição 1, considerando que os nós são numerados a partir de 0 (zero). Operação para excluir um elemento da lista simples • A função para excluir um elemento da lista, apresentada no exemplo a seguir, possibilita a exclusão de um nó, a partir de uma posição fornecida por meio de um valor inteiro, recebido como parâmetro, retornando um texto (literal) que informa o resultado da execução. • Estamos considerando que os elementos de uma lista são numerados a partir de zero, por meio de números inteiros, a fim de manter a similaridade com os vetores. Operação para excluir um elemento da lista simples Operações em listas de encadeamento duplo • Quando percorremos uma lista de encadeamento simples, é bastante difícil fazer o caminho inverso, isto é, acessar elementos anteriores, pois a estrutura não considera a referência ao nó anterior. • Nas listas de encadeamento duplo, este problema não existe, uma vez que cada nó possui uma referência para o próximo elemento da lista e outra referência para o anterior. • A construção de uma lista de encadeamento duplo é similar à construção de listas de encadeamento simples, bastando acrescentar a cada elemento (nó) uma variável para fazer a referência ao nó anterior, como é feito com o próximo. Criação de uma lista de encadeamento duplo • A implementação da lista de encadeamento duplo será feita, em pseudocódigo, por meio de um registro, e, em Java, com uma classe para representar o nó e outra para lista, conforme mostra o exemplo. Criação de uma lista de encadeamento duplo Operação para inserir um elemento no final da lista dupla
• Criamos o procedimento para inserir um elemento (nó) no final
da lista, lembrando que, por sua característica, uma lista permite a realização de operações de inserção em qualquer posição. Operação para inserir um elemento no início da lista dupla • De forma similar à inclusão de um elemento no final da lista, é possível, com pequenas alterações no algoritmo, inserir um elemento no início, alocando adequadamente os ponteiros da lista e dos nós, conforme o exemplo a seguir. Operação para recuperar um elemento de uma lista dupla • Esta operação tem uma função bastante específica: a de recuperar um elemento da lista, possibilitando sua utilização para a inclusão ou exclusão de um elemento de uma posição da lista dupla, além de servir para outras operações que necessitem obter elementos da lista para as suas ações. Operação para recuperar um elemento de uma lista dupla
• O valor retornado por este método precisa ser tratado
pelo chamador, em função da possibilidade de um valor nulo como resultado; e, por ser um método cujo acesso e exclusivo na classe, foi declarado como privado. Operação para inserir um elemento em determinada posição da lista dupla • Esta operação pode ser interessante para manter uma lista em que se deseja organizar seus elementos em uma certa ordem, aproveitando o principal recurso das listas encadeadas — a inclusão de elementos de uma maneira eficiente, sem que seja necessário alterar a posição dos demais. Operação para inserir um elemento em determinada posição da lista dupla Operação para excluir um elemento em determinada posição da lista dupla • Esta operação pode ser utilizada para manter uma lista organizada, em uma determinada ordem, removendo os elementos de qualquer uma das posições existentes, funcionando de forma complementar ao algoritmo exposto no exemplo a seguir. Operação para excluir um elemento em determinada posição da lista dupla Operação para excluir um elemento em determinada posição da lista dupla • A função que exclui uma posição da lista dupla baseia-se na ordem dos elementos inseridos, cuja numeração é considerada a partir de zero, a qual não faz parte da estrutura de dados. • Assim, em uma lista com 5 elementos, consideramos que estes são numerados de 0 a 4 e, se qualquer um deles for removido, teríamos uma lista com elementos numerados de 0 a 3.