Neste artigo, você aprenderá a implementar uma lista encadeada explorando os conceitos básicos e as operações mais comuns. Vamos explorar as vantagens, desvantagens e como aplicá-las de forma prática no código.
O que são Listas Encadeadas?
Imagine uma sequência de elementos, onde cada um aponta para o próximo, como uma corrente. Esses elementos, chamados de nós, podem estar em qualquer lugar da memória, mas são conectados por referências. Cada nó contém dois campos:
- O valor do nó.
- Um ponteiro que aponta para o próximo nó na sequência.
O último nó da lista sempre terá o valor null
em seu ponteiro, indicando o fim da estrutura.
Exemplo em JavaScript:
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
}
}
Principais Operações em Listas Encadeadas
Aqui, vamos explorar a implementação de dois métodos fundamentais: append
, para adicionar novos elementos, e delete
, para removê-los. No entanto, vale destacar que existem diferentes abordagens e métodos.
Adicionando elementos (append
)
Cenário 1: Lista vazia
Adicionando o primeiro elemento:
class LinkedList {
// ...
append(value) {
const node = new Node(value);
if (!this.head) {
this.head = node;
return;
}
}
}
Teste automatizado:
test('should append a node to the empty list', () => {
const list = new LinkedList();
list.append(10);
expect(list.head.next).toBeNull();
});
Cenário 2: Lista com elementos
Ao adicionar em uma lista já preenchida, é necessário percorrê-la até encontrar o último elemento:
class LinkedList {
// ...
append(value) {
// ...
let current;
while (current.next) {
current = current.next;
}
current.next = node;
}
}
Teste correspondente:
test('should append a node to the list', () => {
const list = new LinkedList();
list.append(10);
list.append(15);
expect(list.head.next.value).toBe(15);
});
Removendo elementos (delete
)
Cenário 1: Lista vazia
Antes de qualquer ação, verifique se a lista tem elementos:
class LinkedList {
// ...
delete(value) {
if (!this.head) return;
}
}
Cenário 2: Removendo o primeiro elemento
Para isso, basta ajustar o head para apontar para o próximo elemento:
class LinkedList {
// ...
delete(value) {
// ...
if (this.head.value === value) {
this.head = this.head.next;
return;
}
}
}
Teste para validar:
test('should delete the first node by value', () => {
const list = new LinkedList();
list.append(10);
list.append(15);
list.delete(10);
expect(list.head.value).toBe(15);
});
Cenário 3: Removendo elementos do meio ou final
Aqui, precisamos iterar pela lista até encontrar o nó desejado:
class LinkedList {
// ...
delete(value) {
// ...
let current = this.head;
while (current.next && current.next.value !== value) {
current = current.next;
}
if (current.next) {
current.next = current.next.next;
}
}
}
Teste correspondente:
test('should delete any nodes by value', () => {
const list = new LinkedList();
list.append(10);
list.append(20);
list.append(30);
list.delete(20);
expect(list.head.next.value).toBe(30);
});
Prós e Contras das Listas Encadeadas
Vantagens
- Inserções e remoções eficientes: Não é necessário deslocar elementos na memória.
- Leitura sequencial: Ideal para percorrer itens de forma linear.
Desvantagens
- Acesso lento a elementos específicos: É necessário iterar a lista para encontrar o nó desejado.
Conclusão
Listas encadeadas são poderosas quando bem aplicadas, especialmente em cenários onde inserções e remoções frequentes são necessárias. Embora tenham suas limitações, seu uso eficiente pode fazer toda a diferença no desempenho de aplicações que lidam com grandes volumes de dados.
Gostou desse conteúdo? Deixe um comentário e compartilhe!