Aula 18 - Estruturas de Dados Dinâmicas em C 🧱
Objetivo Pedagógico
Objetivo: Construção bare-metal de estruturas de dados dinâmicas em C: Listas Duplamente Encadeadas, Pilhas e Filas com alocação na Heap e liberação segura sem memory leaks.
📑 1. Fundamentos Teóricos & Análise Técnica
Diferente de linguagens de alto nível com coleções nativas redimensionáveis (como ArrayList em Java ou listas em Python), em linguagem C a construção de estruturas com dimensionamento dinâmico exige a criação manual de nós alocados na Heap interconectados através de ponteiros.
- Lista Duplamente Encadeada (Doubly Linked List): Cada nó armazena seu dado e dois ponteiros:
next(para o próximo elemento) eprev(para o elemento anterior). Permite travessia bidirecional e inserção/remoção em tempo constante \(O(1)\) quando o ponteiro para o nó já é conhecido. - Pilhas (LIFO - Last-In, First-Out): Operações estritas de
push(empilhar) epop(desempilhar) realizadas exclusivamente no topo. - Filas (FIFO - First-In, First-Out): Operações de
enqueue(enfileirar no fim) edequeue(desenfileirar no início).
A disciplina de memória é crítica: a destruição de uma lista exige percorrer nó por nó, preservando o ponteiro para o próximo elemento antes de liberar o nó atual com free().
📐 Arquitetura Conceitual & Diagrama de Fluxo
graph LR
Head["Head (Início)"] --> N1["Nó 1 [prev: NULL | data: 10 | next]"]
N1 <--> N2["Nó 2 [prev | data: 20 | next]"]
N2 <--> N3["Nó 3 [prev | data: 30 | next: NULL]"]
Tail["Tail (Fim)"] --> N3
style Head fill:#e1f5fe,stroke:#01579b
style N1 fill:#fff3e0,stroke:#e65100
style N2 fill:#fff3e0,stroke:#e65100
style N3 fill:#fff3e0,stroke:#e65100
style Tail fill:#e8f5e9,stroke:#2e7d32 🔍 Pilares e Diretrizes Técnicas
Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Nós com Alocação Dinâmica: Uso de malloc(sizeof(Node)) para cada elemento inserido na coleção. - Manutenção de Invariantes de Ponteiros: Atualização atômica de next e prev para evitar nós órfãos. - Prevenção de Falhas de Segmentação (Segmentation Fault): Checagem mandatória de if (ptr == NULL) antes de desreferenciar ponteiros. - Varredura de Liberação Segura: Armazenamento temporário de temp = current->next antes de executar free(current).
🛠️ 2. Implementação Prática em C ANSI e Algoritmos de Estruturas de Dados
Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:
// doubly_linked_list.c (Lista Duplamente Encadeada em C)
#include <stdio.h>
#include <stdlib.h>
typedef struct DNode {
int data;
struct DNode* prev;
struct DNode* next;
} DNode;
typedef struct {
DNode* head;
DNode* tail;
} DList;
void dlist_push_back(DList* list, int val) {
DNode* newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = val;
newNode->next = NULL;
newNode->prev = list->tail;
if (list->tail) {
list->tail->next = newNode;
} else {
list->head = newNode;
}
list->tail = newNode;
}
void dlist_free(DList* list) {
DNode* curr = list->head;
while (curr) {
DNode* next = curr->next;
free(curr);
curr = next;
}
list->head = NULL;
list->tail = NULL;
}
💡 Análise Passo a Passo do Código
- Inserção em O(1): O ponteiro
tailpermite anexar elementos no fim da lista instantaneamente sem percorrer todos os nós. - Encadeamento Duplo: O nó anterior e o próximo conhecem-se mutuamente através de
prevenext. - Liberação Completa:
dlist_freeevita vazamento de memória percorrendo e destruindo cada nó sequencialmente.
🎯 3. Próximos Passos & Sequência Didática
-
Slides da Aula
-
Quiz de Fixação
-
Exercícios Práticos
-
Desafio de Projeto