Busca Linear em Zig — Implementação e Explicação
A Busca Linear (ou busca sequencial) é o algoritmo de busca mais simples. Ela percorre cada elemento da coleção sequencialmente até encontrar o elemento desejado ou chegar ao final sem encontrá-lo.
Como Funciona
- Comece pelo primeiro elemento
- Compare o elemento atual com o valor procurado
- Se for igual, retorne a posição
- Se não for, avance para o próximo elemento
- Se chegar ao final sem encontrar, retorne “não encontrado”
Visualização do Processo
Array: [14, 33, 27, 10, 35, 19, 42, 44]
Procurando: 35
Passo 1: [14] 33 27 10 35 19 42 44 → 14 ≠ 35
Passo 2: 14 [33] 27 10 35 19 42 44 → 33 ≠ 35
Passo 3: 14 33 [27] 10 35 19 42 44 → 27 ≠ 35
Passo 4: 14 33 27 [10] 35 19 42 44 → 10 ≠ 35
Passo 5: 14 33 27 10 [35] 19 42 44 → 35 = 35 ✓
Encontrado na posição 4!
Implementação em Zig
const std = @import("std");
/// Busca linear genérica — retorna o índice do elemento ou null.
pub fn buscaLinear(comptime T: type, items: []const T, alvo: T) ?usize {
for (items, 0..) |item, i| {
if (item == alvo) return i;
}
return null;
}
/// Busca linear com comparador personalizado.
pub fn buscaLinearBy(
comptime T: type,
items: []const T,
comptime iguais: fn (T, T) bool,
alvo: T,
) ?usize {
for (items, 0..) |item, i| {
if (iguais(item, alvo)) return i;
}
return null;
}
/// Busca linear com sentinela — evita verificação de limite a cada iteração.
/// Requer que o slice seja mutável para colocar o sentinela no final.
pub fn buscaLinearSentinela(comptime T: type, items: []T, alvo: T) ?usize {
if (items.len == 0) return null;
const ultimo_idx = items.len - 1;
const ultimo_valor = items[ultimo_idx];
// Verifica se o último já é o alvo
if (ultimo_valor == alvo) return ultimo_idx;
// Coloca o sentinela no final
items[ultimo_idx] = alvo;
// Busca sem verificar limite (sentinela garante parada)
var i: usize = 0;
while (items[i] != alvo) : (i += 1) {}
// Restaura o valor original
items[ultimo_idx] = ultimo_valor;
// Se encontrou antes do sentinela, é válido
if (i < ultimo_idx) return i;
return null;
}
/// Busca linear que retorna todas as ocorrências.
pub fn buscaLinearTodas(
comptime T: type,
allocator: std.mem.Allocator,
items: []const T,
alvo: T,
) ![]usize {
var resultados = std.ArrayList(usize).init(allocator);
for (items, 0..) |item, i| {
if (item == alvo) try resultados.append(i);
}
return resultados.toOwnedSlice();
}
/// Busca linear em structs por campo específico.
const Pessoa = struct {
nome: []const u8,
idade: u32,
};
pub fn buscaPorIdade(pessoas: []const Pessoa, idade: u32) ?usize {
for (pessoas, 0..) |p, i| {
if (p.idade == idade) return i;
}
return null;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const numeros = [_]i32{ 14, 33, 27, 10, 35, 19, 42, 44 };
// Busca simples
if (buscaLinear(i32, &numeros, 35)) |idx| {
try stdout.print("35 encontrado na posição {d}\n", .{idx});
}
if (buscaLinear(i32, &numeros, 99)) |_| {
try stdout.print("99 encontrado\n", .{});
} else {
try stdout.print("99 não encontrado\n", .{});
}
// Busca em structs
const pessoas = [_]Pessoa{
.{ .nome = "Ana", .idade = 25 },
.{ .nome = "Bruno", .idade = 30 },
.{ .nome = "Clara", .idade = 28 },
};
if (buscaPorIdade(&pessoas, 30)) |idx| {
try stdout.print("Pessoa com 30 anos: {s}\n", .{pessoas[idx].nome});
}
}
Análise de Complexidade
| Caso | Tempo | Espaço |
|---|---|---|
| Melhor caso | O(1) — elemento no início | O(1) |
| Caso médio | O(n/2) = O(n) | O(1) |
| Pior caso | O(n) — elemento no final ou ausente | O(1) |
Características
- Simplicidade: o algoritmo mais fácil de implementar
- Sem pré-requisitos: funciona em qualquer coleção, ordenada ou não
- Espaço constante: O(1) de memória adicional
- Versátil: funciona com qualquer tipo de dados
Quando Usar
- Listas pequenas (n < 20): overhead de algoritmos complexos não compensa
- Dados não ordenados: quando não é possível ordenar primeiro
- Busca única: quando a busca é feita raramente
- Listas encadeadas: acesso sequencial é a única opção
Para coleções ordenadas e buscas frequentes, use Busca Binária com O(log n).
Otimizações
- Sentinela: elimina a verificação de limite, melhorando constante
- Move-to-front: move o elemento encontrado para o início (melhora buscas repetidas)
- Transposição: troca o encontrado com o anterior (melhoria gradual)
Recursos Relacionados
- Busca Binária em Zig — Busca O(log n) para dados ordenados
- Busca por Interpolação — Busca adaptativa
- Hash Table — Busca O(1) amortizado com tabela hash
- Array Estático — Estrutura base para busca linear
- Lista Encadeada — Busca linear é o padrão aqui