Listas encadeadas ou listas ligadas
representam uma seqüência de objetos na
memória do computador.
Exemplo: Lista de afazeres
1. Comprar uma lâmpada
2. Trocar uma lâmpada queimada
3. Procurar uma conta no quarto
4. Pagar uma conta na internet
5. Desligar o computador
6. Dormir
Na lista de afazeres anterior, uma tarefa
dependia da execução da tarefa anterior
Próxima
Ação atual ação
1. Comprar 2
lâmpada
2. Trocar 3
lâmpada
3. Procurar 4
conta
4. Pagar 5
conta
5. Desligar 6
micro
6. Dormir fim
Como representar a lista anterior em um
programa escrito na Linguagem C?
◦ Primeira opção: vetores ou matrizes
Tarefa: Comprar Trocar Procurar Pagar Desligar
Dormir
lâmpada lâmpada conta conta micro
Índice: 1 2 3 4 5 6
Primeira opção: vetores ou matrizes
◦ Como acrescentar “Ligar micro”?
Tarefa: Comprar Trocar Procurar Pagar
Ligar Desligar
Dormir
lâmpada lâmpada conta conta
micro micro
Índice: 1 2 3 4 5 6 7
Primeira opção: vetores ou matrizes
◦ Os itens da lista são armazenados em posições
contíguas de memória.
◦ A lista pode ser percorrida em qualquer direção.
◦ A inserção de um novo item pode ser realizada
após o último item com custo constante.
◦ A inserção de um novo item no meio da lista requer
um deslocamento de todos os itens localizados
após o ponto de inserção.
◦ Retirar um item do início da lista requer um
deslocamento de itens para preencher o espaço
deixado vazio.
Segunda opção: ponteiros
◦ Estruturas de dados dinâmicas: estruturas de dados
que contém ponteiros para si próprias.
class Lista {
String nomeTarefa;
float duracao;
String responsavel;
...
Referência para a
Lista prox;
própria classe Lista
};
Representação gráfica de um elemento da lista:
campos de informação
próximo nó
◦ Cada item é encadeado com o seguinte, mediante uma
variável do tipo ponteiro.
◦ Permite utilizar posições não contíguas de memória.
◦ É possível inserir e retirar elementos sem necessidade de
deslocar os itens seguintes da lista.
Cada item em particular de uma lista pode ser
chamado de elemento, nó, célula, ou item.
O apontador para o início da lista também é
tratado como se fosse uma célula (cabeça), para
simplificar as operações sobre a lista.
O símbolo / representa o ponteiro nulo (null),
indicando o fim da lista.
p
3
5
2
4 /
Podemos realizar algumas operações sobre
uma lista encadeadas, tais como:
◦ Inserir itens;
◦ Retirar itens;
◦ Buscar itens.
Para manter a lista ordenada, após realizar
alguma dessas operações, será necessário
apenas movimentar alguns ponteiros (de um
a três elementos).
Outras operações possíveis:
◦ Criar uma lista
◦ Destruir uma lista
◦ Ordenar uma lista
◦ Intercalar duas listas
◦ Concatenar duas listas
◦ Dividir uma lista em duas
◦ Copiar uma lista em outra
class NoLista {
float info;
NoLista proximo;
public NoLista(float valor)
{
this.info = valor;
this.proximo = null;
}
}
Prof. Adriano Teixeira de Souza
Para criar a lista propriamente dita, criaremos
a classe Lista, que manipula objetos do tipo
NoLista
class Lista {
NoLista inicio;
public Lista() {
this.inicio = null;
}
// insere valor no começo da lista
public void inserir(int valor) {...}
// insere valor no fim da lista
public void inserirNoFim(int valor) {...}
}
Podemos inserir itens:
◦ No início de uma lista
◦ No final de uma lista
◦ No meio de uma lista
O endereço armazenado no ponteiro p deve
ser alterado para o endereço do item a ser
acrescido à lista.
p 5 2 4 /
3
public void inserir(float valor) {
if (this.inicio == null) {
// lista vazia, então só é preciso criar o nó
this.inicio = new NoLista(valor);
} else {
// cria-se novo no e atualiza o NoLista inicio
NoLista novoNo = new NoLista(valor);
novoNo.proximo = this.inicio;
this.inicio = novoNo;
}
}
Prof. Adriano Teixeira de Souza
O endereço armazenado em p será alterado caso
a lista esteja vazia ou
O campo proximo do último item será alterado.
/
p 3 /
p 3 5 /
public void inserirNoFim(int valor) {
if (this.inicio == null) {
// lista vazia
this.inicio = new NoLista(valor);
} else {
// procura pelo fim da lista
NoLista atual = this.inicio;
while (atual.proximo != null)
atual = atual.proximo;
// insere o nó no fim da lista
atual.proximo = new NoLista(valor);
}
}
Prof. Adriano Teixeira de Souza
Campo proximo do item a ser inserido recebe
o campo proximo do item posterior
Campo proximo do item antecessor recebe o
endereço do item a ser inserido
p 3 2 4 /
5
lista[5].proximo ← lista[2]
lista[3].proximo ← 5
O endereço armazenado no ponteiro p deve
ser alterado para o endereço do item que
segue o primeiro item da lista.
p 5 2 4 /
O campo proximo do último item será alterado
caso a lista contenha mais de um item ou
O endereço armazenado em p será alterado para
null caso tenha somente um elemento.
p 3 5 /
p 3 /
/
Item antecessor recebe o campo proximo do
item a ser removido
lista[3].proximo ← lista[5].proximo
p 3 5 2 4 /
void retira (float v) {//Em qualquer posicao
NoLista ant = null;
NoLista p = this.inicio;
while (p != null && p.info != v) {
ant = p;
p = p.proximo;
}
if (p != null){
if (ant == null) {
this.inicio = p.proximo;
}else {
ant.proximo = p.proximo;
}
};
}
NoLista busca (float v){
int i=0;
for (NoLista p = this.inicio; p!=null; p=p.proximo){
if(p.info == v){
System.out.println("nnachou “+i+”nn");
return p;
}
i++;
}
return null;
}
Prof. Adriano Teixeira de Souza
void imprime (){
for(NoLista q=this.inicio;q!=null; q=q.proximo)
System.out.println(q.info);
}
Prof. Adriano Teixeira de Souza
public static void main(String[] args){
Lista l = new Lista();
l.inserir(20.0f);
l.inserir(44.5f);
l.inserir(33.3f);
l.inserir(20.9f);
l.imprime();
NoLista n = l.busca(20.9f);//Busca
if (n != null){
System.out.println("Encontrado:"+n.info);
l.retira(n.info);
}
System.out.println("Configuracao da lista:");
l.imprime();
//Libera memoria
l = null;
}
Prof. Adriano Teixeira de Souza
void insereOrdenado ( float valor)
{
NoLista novoNo = new NoLista(valor );
NoLista ant = null;
NoLista p = this.inicio;
while (p != null && p.info < valor) {
ant = p;
p = p.proximo;
}
if (ant == null) {
novoNo.proximo = this.inicio;
this.inicio = novoNo;
} else {
novoNo.proximo = ant.proximo;
ant.proximo = novoNo;
}
}
Prof. Adriano Teixeira de Souza
Adicionado a C# 2.0 e posteriormente a Java 5
Classes Genéricas, que utilizam o conceito de “parâmetros tipo”<..>
Lista com Genéricos: cada lista armazena um tipo específico, sem
precisar criar código novo para cada tipo
Sem Genéricos:
Com Genéricos:
class NoListaI{
int valor;
NoLista next; class NoLista<E> {
} E elemento;
NoLista<E> next;
class NoListaS{ }
String nome;
NoLista next;
}
class Lista<E> {
NoLista<E> inicio;
public Lista() {
this.inicio = null;
}
public void inserir(E elemento) {
if (this.inicio == null) {
this.inicio = new NoLista<E>(elemento);
} else {
NoLista<E> novoNo = new NoLista<E>(elemento);
novoNo.next = this.inicio;
this.inicio = novoNo;
}
}
}