Professor Muniz Educação & Programação

Trilha: Estrutura de Dados

Voltar aos conteúdos
Apostila de Apoio Didático

Estrutura de Dados: Listas Ligadas

Alocação Dinâmica, Padrão de Nó Sentinela, Inserção Ordenada e Remoção por Salto de Ponteiros em Java

MÓDULO 1

Fundamentos Conceituais e o Nó Sentinela

1.1 Vetores Estáticos vs. Listas Dinâmicas

Em estruturas baseadas em vetores estáticos, os elementos ocupam posições contíguas e exigem uma dimensão máxima pré-fixada. A Lista Ligada (ou simplesmente encadeada) adota um paradigma de alocação dinâmica:

Memória Dinâmica na Heap

Cada elemento (chamado de Nó) é instanciado independentemente na memória Heap. Não há necessidade de continuidade física na RAM, permitindo crescimento sem limites estáticos prévios.

O Padrão do Nó Sentinela

A lista utiliza um nó fictício inicial new No(0) como sentinela de controle. Esse nó garante que o ponteiro inicio nunca seja null, simplificando drasticamente as validações de borda de todos os métodos.

Esquema Gráfico: Nó Sentinela e Encadeamento Dinâmico
Nó Sentinela (inicio)
0 (ignorado)
prox
➜
10
prox ➜
➜
20
prox ➜
➜
50
null
Visualização do percurso impresso: 10 -> 20 -> 50 -> null
MÓDULO 2

A Estrutura do Nó (No.java)

A classe No modela a unidade atômica da estrutura. Ela possui duas propriedades com encapsulamento completo: o dado inteiro (numero) e o ponteiro para o próximo nó (prox).

public class No {
    private int numero;
    private No prox;

    No() {
    }

    No(int numero) {
        this.numero = numero;
    }

    public int getNumero() {
        return numero;
    }

    public void setNumero(int numero) {
        this.numero = numero;
    }

    public No getProx() {
        return prox;
    }

    public void setProx(No prox) {
        this.prox = prox;
    }
}
MÓDULO 3

A Classe de Gerenciamento (Lista.java)

A classe Lista isola o controle da estrutura. O construtor instancia o nó sentinela inicial, e o método inserirNoInicio realiza a inserção instantânea em tempo constante O(1):

Inicialização do Sentinela

No construtor, this.inicio = new No(0); cria o nó cabeça com valor ignorado. A lista vazia é representada por inicio.getProx() == null.

Inserção no Início em O(1)

Liga-se o novo nó diretamente ao sucessor do sentinela: novo.setProx(inicio.getProx()) e depois inicio.setProx(novo).

public class Lista {
    private No inicio; // Nó sentinela — não armazena dado real

    public Lista() {
        this.inicio = new No(0); // Sentinela: valor ignorado, só guia o prox
    }

    // Inserção no início da lista (O(1))
    public void inserirNoInicio(int valor) {
        No novo = new No(valor);
        novo.setProx(inicio.getProx());
        inicio.setProx(novo);
    }

    // Percurso e exibição dos elementos
    public void imprimir() {
        No atual = inicio.getProx(); // Pula o sentinela
        while (atual != null) {
            System.out.print(atual.getNumero() + " -> ");
            atual = atual.getProx();
        }
        System.out.println("null");
    }
}
MÓDULO 4

Inserção Ordenada & Remoção Eficiente

4.1 Inserção Ordenada (Crescente)

Para manter a lista ordenada sem precisar reordená-la posteriormente, o algoritmo inspeciona o valor do próximo elemento (atual.getProx().getNumero()). Ao encontrar um valor maior ou o final da lista, encaixa o novo nó na posição correta:

// Inserção mantendo a ordem crescente
public void inserirOrdenado(int valor) {
    No novo = new No(valor);
    No atual = inicio;

    // Avança enquanto o próximo nó existir e seu valor for menor que o novo
    while (atual.getProx() != null && atual.getProx().getNumero() < valor) {
        atual = atual.getProx();
    }

    // Encaixa o novo nó entre 'atual' e 'atual.getProx()'
    novo.setProx(atual.getProx());
    atual.setProx(novo);
}

4.2 Remoção por Salto de Ponteiros

A remoção busca o nó anterior ao elemento alvo. Ao localizá-lo, desconecta o elemento fazendo um salto direto para o sucessor através de atual.setProx(atual.getProx().getProx()):

// Remoção de nó por valor com salto de ponteiro
public boolean remover(int valor) {
    No atual = inicio;

    // Busca o nó anterior ao valor procurado
    while (atual.getProx() != null && atual.getProx().getNumero() != valor) {
        atual = atual.getProx();
    }

    // Se o elemento existe na lista, "pula" o nó removendo-o da cadeia
    if (atual.getProx() != null) {
        atual.setProx(atual.getProx().getProx());
        return true;
    }

    return false; // Valor não localizado
}

Por que o Nó Sentinela Simplifica a Remoção?

Graças ao nó sentinela inicio, mesmo quando o primeiro elemento útil da lista (ex: o 10) precisa ser removido, a variável atual aponta para o sentinela. Não é necessário nenhum bloco if (inicio == alvo) específico!
MÓDULO 5

Execução Completa: Classe de Teste (App.java)

A classe executável App.java valida na prática as inserções desordenadas que resultam em uma lista perfeitamente ordenada, seguida da remoção do elemento intermediário:

public class App {
    public static void main(String[] args) {
        Lista lista = new Lista();

        System.out.println("--- 1. Inserção Ordenada de Elementos ---");
        lista.inserirOrdenado(30);
        lista.inserirOrdenado(10);
        lista.inserirOrdenado(50);
        lista.inserirOrdenado(20);
        
        // Impressão esperada: 10 -> 20 -> 30 -> 50 -> null
        System.out.print("Lista após inserções: ");
        lista.imprimir();

        System.out.println("\n--- 2. Remoção do Elemento 30 ---");
        boolean removido = lista.remover(30);
        System.out.println("Elemento 30 removido com sucesso? " + removido);

        // Impressão esperada: 10 -> 20 -> 50 -> null
        System.out.print("Lista após remoção: ");
        lista.imprimir();
    }
}

Estudo de Caso Prático: Rastreio de Execução na Heap

Ação Instrução Chamada Mecanismo de Ponteiros Estado da Lista
1 inserirOrdenado(30) Lista vazia: sentinela aponta para 30 30 -> null
2 inserirOrdenado(10) 10 < 30: 10 aponta para 30 e sentinela aponta para 10 10 -> 30 -> null
3 inserirOrdenado(50) 50 > 30: caminha até o fim e anexa o 50 10 -> 30 -> 50 -> null
4 inserirOrdenado(20) Encaixa entre o 10 e o 30 10 -> 20 -> 30 -> 50 -> null
5 remover(30) Salto: nó 20 passa a apontar diretamente para 50 10 -> 20 -> 50 -> null
MÓDULO 6

Prática de Laboratório (Mãos à Obra!)

Desafio Prático: Métodos de Consulta na Classe Lista

Utilizando a estrutura com nó sentinela da classe Lista, implemente dois novos métodos de análise:

Especificações do Desafio:
  1. Método 1 (tamanho()): Percorre a lista e retorna o total de elementos armazenados (desconsiderando o sentinela).
  2. Método 2 (contem(int valor)): Realiza uma busca e retorna true se o elemento estiver presente, interrompendo antecipadamente caso encontre um número maior (aproveitando que a lista está ordenada).
Gabarito Recomendado de Resolução:
// Retorna a quantidade total de nós reais
public int tamanho() {
    int cont = 0;
    No atual = inicio.getProx();
    while (atual != null) {
        cont++;
        atual = atual.getProx();
    }
    return cont;
}

// Busca otimizada para lista ordenada
public boolean contem(int valor) {
    No atual = inicio.getProx();
    while (atual != null) {
        if (atual.getNumero() == valor) {
            return true; // Encontrado
        }
        if (atual.getNumero() > valor) {
            return false; // Parada antecipada: os próximos serão ainda maiores!
        }
        atual = atual.getProx();
    }
    return false;
}
COMPARATIVO

Comparativo Definitivo: Vetores vs. Listas Ligadas

Sintetize as características arquiteturais entre armazenamento sequencial por índice e encadeamento dinâmico:

Critério de Avaliação Vetor Estático (Array) Lista Ligada (Linked List)
Alocação de Memória Contígua, bloco rígido pré-alocado Dinâmica, sob demanda na Heap
Acesso Aleatório por Índice O(1) - Direto via endereço base O(N) - Sequencial de nó em nó
Inserção / Remoção no Início O(N) - Requer shift de todos os itens O(1) - Apenas ajuste de ponteiros
Inserção Ordenada O(N) busca + O(N) deslocamento O(N) busca + O(1) relinkagem
Risco de Overflow Físico Sim (quando atinge capacidade) Não (apenas o limite da RAM)
Overhead de Memória Zero ponteiros adicionais Consome espaço para o ponteiro prox

Fim deste Conteúdo

Parabéns por dominar a base de Listas Ligadas com Nó Sentinela, Inserção Ordenada e Remoção! Na próxima aula, avançaremos para o estudo de Listas Duplamente Encadeadas e Listas Circulares em Java.

Materiais Complementares de Apoio

Slides da Aula: Listas Ligadas & Nó Sentinela

Acesse o slide de apoio didático estruturado em PDF/PowerPoint, contendo diagramas conceituais, alocação na Heap e passos de manipulação de ponteiros.

Baixar Slides
Videoaula Relacionada: Listas Ligadas em Java

Assista à explicação detalhada com resoluções de problemas e exemplos práticos de implementação de listas encadeadas.

Assistir Vídeo
Repositório de Código Fonte

Explore, acesse e faça o download de todos os códigos-fonte de exemplo e exercícios estruturados nesta trilha.

Abrir Repositório
Voltar aos conteúdos