Operações em Vetores: Busca, Filtragem e Iteração
Armazenar coleções de dados é apenas o ponto de partida. O verdadeiro poder da computação reside em saber consultar, filtrar, sintetizar e transformar esses dados. Aprenda os algoritmos fundamentais de busca linear, localização de extremos (máximo e mínimo) e compactação de vetores em Portugol, JavaScript e Python.
1. Coleções com Propósito: Além do Simples Armazenamento
Na Aula 21, descobrimos como os vetores organizam múltiplos valores em um único bloco contíguo de memória RAM acessível por índices numéricos inteiros. Contudo, na engenharia de software do mundo real, guardar dados sem ser capaz de extrair respostas é inútil.
Imagine um banco de dados de clientes, o inventário de um e-commerce com milhares de mercadorias ou o sistema de telemetria de uma usina hidrelétrica:
- "O produto com código de barras 789100 existe no estoque?" Operação de Busca.
- "Qual foi a temperatura mais extrema registrada pelos sensores durante a madrugada?" Operação de Extremos (Máximo e Mínimo).
- "Quais foram as vendas cujo valor superou R$ 5.000,00 para gerar o relatório fiscal?" Operação de Filtragem.
- "Qual foi o faturamento total acumulado no mês?" Operação de Acumulação.
Essas quatro operações compõem a espinha dorsal de qualquer sistema de informação que lida com coleções. Nesta aula, dissecaremos a lógica algorítmica de cada uma delas, analisando suas complexidades, armadilhas clássicas e melhores práticas de escrita.
2. A Busca Linear (Sequencial): Encontrando Agulhas no Palheiro
A Busca Linear (também chamada de Busca Sequencial) é o algoritmo mais intuitivo e universal para descobrir se um determinado valor — chamado de Chave de Busca (Target) — reside dentro de um vetor não ordenado.
O princípio é elementar: colocamos uma chave de busca na mão e começamos a caminhar da posição 0 em direção à posição N-1. A cada passo, comparamos o elemento atual com a chave:
- Se o elemento for igual à chave: encontramos o alvo! Registramos o índice onde ele estava e podemos cessar a busca.
- Se o elemento for diferente: avançamos para a próxima célula.
- Se o laço terminar e chegarmos ao fim do vetor sem nenhum match: concluímos com certeza que o valor não existe na amostra.
Figura 1: A busca linear passo a passo. Ao encontrar a chave 42 no índice [2], a flag é acionada e o loop é interrompido imediatamente.
A Tríade da Busca Linear Perfeita: Chave, Flag e Parada
Um erro muito comum entre iniciantes é tentar imprimir a mensagem "Elemento não encontrado!" dentro do laço para no bloco senao. Isso faz a tela imprimir "Não encontrado" repetidamente para cada índice que não for o procurado!
A solução profissional envolve 3 elementos:
- Uma variável booleana de controle chamada Flag (ex:
achou: logico), que nasce valendofalso. - Uma variável para reter a posição onde o item foi localizado (ex:
numero posicaoEncontrada), inicializada com-1(um índice impossível que denota ausência). - O comando de desvio
pare(estudado na Aula 15) para abortar o laço assim que o item for achado, evitando gastar CPU à toa com o restante do vetor.
// Preenchendo a amostra de dados
vetor numeros = [15, 88, 42, 27, 91];
numero chaveProcurada = entrada("Informe o número que deseja localizar: ");
logico encontrou = falso;
numero posicaoEncontrada = -1;
// ALGORITMO DE BUSCA LINEAR COM EARLY BREAK
para (numero i = 0; i < tamanho(numeros); i++) {
se (numeros[i] == chaveProcurada) {
encontrou = verdadeiro;
posicaoEncontrada = i;
pare; // OTIMIZAÇÃO: Para a busca no primeiro match!
}
}
// AVALIAÇÃO DA FLAG FORA DO LAÇO
se (encontrou) {
saida("Sucesso! O valor " + chaveProcurada + " foi localizado no índice [" + posicaoEncontrada + "].");
} senao {
saida("O valor " + chaveProcurada + " não existe neste vetor.");
}
- Melhor Caso: $O(1)$ — O elemento procurado está logo no índice
0. O laço executa apenas uma única verificação. - Pior Caso: $O(n)$ — O elemento procurado está na última posição ou simplesmente não existe no vetor. O algoritmo é obrigado a inspecionar todos os $n$ elementos da lista.
3. Localização de Extremos: O Algoritmo de Maior e Menor Elemento
Determinar o valor máximo (ou mínimo) dentro de um grupo numérico é uma das rotinas mais requisitadas em relatórios gerenciais, dashboards e processamento de sinais analógicos.
Figura 2: A comparação entre a armadilha de inicializar extremos com zero versus a regra de ouro de adotar vetor[0].
A Regra de Ouro Inviolável: Inicialize Sempre com vetor[0]!
Esta é uma das maiores fontes de bugs em testes técnicos de empresas de tecnologia. Muitos candidatos escrevem:
maior = 0 // [ERRO] ERRO CRÍTICO DE CONCEITO!
Por que isso é um erro grave? Pense em um sensor de temperatura monitorando uma base científica na Antártida, cujas leituras foram: [-25, -18, -32, -12, -40].
Se você inicializar maior = 0, o computador comparará -25 > 0 (falso), -18 > 0 (falso)... Ao término do programa, o algoritmo anunciará com orgulho: "A maior temperatura registrada foi 0°C!". Isso é uma mentira: zero sequer existe nas medições!
O mesmo desastre acontece ao buscar o menor valor inicializando menor = 0 em uma lista de notas de alunos que tiraram entre 3 e 10: o algoritmo dirá que a menor nota foi zero, distorcendo o relatório acadêmico.
Defina o campeão provisório como o primeiro elemento real da própria coleção:
maior = vetor[0]
menor = vetor[0]
Dessa forma, seu ponto de partida é um dado autêntico da amostra. Em seguida, você inicia a varredura a partir do índice 1 (poupando a primeira comparação desnecessária!).
// Amostra de temperaturas com números negativos
vetor temps = [-25, -18, -32, -12, -40];
// REGRA DE OURO: Inicialize sempre com o primeiro elemento real!
numero maior = temps[0];
numero menor = temps[0];
// Começa do índice 1 poupando a comparação consigo mesmo
para (numero i = 1; i < tamanho(temps); i++) {
se (temps[i] > maior) {
maior = temps[i];
}
se (temps[i] < menor) {
menor = temps[i];
}
}
saida("Maior temperatura registrada: " + maior + "°C");
saida("Menor temperatura registrada: " + menor + "°C");
4. Filtragem e Projeção: Construindo Subconjuntos sem Lacunas
Filtrar um vetor significa inspecionar todos os seus itens e copiar para um novo vetor de destino apenas aqueles que satisfazem uma determinada condição booleana (como números pares, clientes maiores de idade ou produtos esgotados).
Figura 3: O papel indispensável do contador auxiliar de inserção para garantir que o vetor destino seja contíguo, sem posições vazias.
A Armadilha do Índice Duplo: Por Que Não Usar o Mesmo i?
Se o vetor de origem possui valores nos índices 0, 1, 2, 3, 4, 5 e apenas os índices 1, 3 e 4 satisfazem o filtro, você não pode fazer pares[i] = numeros[i]!
Se você fizer isso, o vetor de destino terá dados gravados nos índices 1, 3 e 4, deixando os índices 0 e 2 com valores vazios ou lixo de memória! Isso quebra a regra de ouro de que os vetores devem ser contíguos.
Para resolver isso, criamos um Ponteiro Auxiliar de Inserção (comumente batizado de k ou qtdFiltrados), que inicia em 0 e só é incrementado quando uma gravação efetiva acontecer:
vetor dados = [12, 7, 19, 24, 30, 15, 8];
vetor pares = [];
para (numero i = 0; i < tamanho(dados); i++) {
se (resto(dados[i], 2) == 0) {
pares[tamanho(pares)] = dados[i];
}
}
saida("Total de valores pares filtrados: " + tamanho(pares));
5. Inversão de Vetores in-place (Two Pointers)
Como inverter a ordem de um vetor (o primeiro vira último, o segundo vira penúltimo) sem gastar memória alocando um segundo vetor auxiliar?
Utiliza-se a técnica dos Dois Ponteiros (Two Pointers):
- Um ponteiro
iniciocomeça no índice0. - Um ponteiro
fimcomeça no último índice (tamanho - 1). - Enquanto
inicio < fim, trocamos os valores das duas pontas utilizando uma variável temporária de apoio (a manobra clássica do Swap). - Avançamos
inicio = inicio + 1e recuamosfim = fim - 1.
Esse algoritmo realiza a inversão perfeita em exatamente $\lfloor n / 2 \rfloor$ voltas com zero memória extra!
6. Laboratório Multi-Linguagem: Métodos Funcionais e Idiomáticos
No desenvolvimento profissional contemporâneo, as operações manuais que acabamos de estudar serviram de alicerce para os métodos de ordem superior (High-Order Functions) nativos das linguagens modernas:
// ==============================================
// JAVASCRIPT (ES6+ Functional Array Methods)
// ==============================================
const lista = [15, 88, 42, 27, 91, 14];
// 1. Busca Linear nativa (find / indexOf)
const achou42 = lista.includes(42); // true
const pos42 = lista.indexOf(42); // 2
// 2. Máximo e Mínimo (com Math)
const maiorJS = Math.max(...lista); // 91
const menorJS = Math.min(...lista); // 14
// 3. Filtragem declarativa (filter)
const paresJS = lista.filter(n => n % 2 === 0); // [88, 42, 14]
// 4. Acumulação e Média (reduce)
const somaJS = lista.reduce((acum, n) => acum + n, 0); // 277
// ==============================================
// PYTHON 3 (Idiomatic & Comprehensions)
// ==============================================
amostra = [15, 88, 42, 27, 91, 14]
# 1. Busca Linear (in / index)
possui_42 = 42 in amostra # True
indice_42 = amostra.index(42) # 2
# 2. Extremos
maior_py = max(amostra) # 91
menor_py = min(amostra) # 14
# 3. Filtragem com List Comprehension
pares_py = [n for n in amostra if n % 2 == 0] # [88, 42, 14]
7. As 5 Armadilhas Comuns nas Operações em Vetores
-
Não Parar a Busca Após Encontrar o Elemento: Se você está buscando um CPF único em uma base de 500.000 clientes e acha o registro na posição 10, esquecer o comando
parefará o programa rodar mais 499.990 voltas à toa na CPU. - Inicializar Extremos com Zero: Destrói a lógica quando todos os números da base são negativos ou quando zero é um dado fora de escala.
-
Divisão Inteira ao Calcular Médias: Em linguagens fortemente tipadas, somar inteiros e dividir pelo tamanho inteiro trunca as casas decimais (ex:
15 / 2 = 7em vez de7.5). Converta o divisor para número real (soma / 5.0). -
Usar o Índice do Vetor de Origem no Vetor Filtrado: Deixa buracos com valores indefinidos no vetor de destino. Use sempre um contador auxiliar independente
k. - Extrapolar o Tamanho Máximo do Vetor de Destino: Se o vetor original possui 100 itens e todos forem pares, o vetor de pares precisa ter sido alocado com capacidade de no mínimo 100 posições, caso contrário ocorrerá Index Out of Bounds.
8. Projeto Prático Resolvido: Sistema de Telemetria de Caldeiras Industriais
Para integrar todos os conceitos desta aula em uma aplicação robusta, vamos desenvolver um sistema que recebe leituras de temperatura de 6 sensores industriais distribuídos em uma caldeira de alta pressão, calcula a média térmica, identifica o sensor mais aquecido, verifica a presença de alerta crítico e gera um vetor isolado contendo apenas as temperaturas que excederam o limite de segurança operacional (80°C).
// =========================================================================
// MONITORAMENTO DE CALDEIRAS EM LOGICABR.DEV (100% FUNCIONAL)
// =========================================================================
vetor leituras = [72.5, 84.0, 68.2, 91.5, 79.0, 81.2];
numero totalSensores = tamanho(leituras);
numero somaTemp = 0.0;
saida("=== TELEMETRIA DE TEMPERATURA DA CALDEIRA ===");
// 1. Processamento e Acúmulo Térmico
para (numero i = 0; i < totalSensores; i++) {
saida("Sensor #" + (i + 1) + ": " + leituras[i] + "°C");
somaTemp = somaTemp + leituras[i];
}
numero mediaOperacional = somaTemp / totalSensores;
// 2. Localização do Pico de Calor (Maior Elemento)
numero picoCalor = leituras[0];
numero sensorPico = 1;
para (numero i = 1; i < totalSensores; i++) {
se (leituras[i] > picoCalor) {
picoCalor = leituras[i];
sensorPico = i + 1;
}
}
// 3. Filtragem: Isolando Leituras Acima de 80.0°C
vetor criticos = [];
para (numero i = 0; i < totalSensores; i++) {
se (leituras[i] > 80.0) {
criticos[tamanho(criticos)] = leituras[i];
}
}
// 4. Relatório Técnico Gerencial
saida("");
saida("---------------- RELATÓRIO OPERACIONAL ----------------");
saida("Média Térmica da Caldeira: " + mediaOperacional + "°C");
saida("Pico Máximo de Calor: " + picoCalor + "°C (Registrado no Sensor #" + sensorPico + ")");
se (tamanho(criticos) > 0) {
saida("[ALERTA] CRÍTICO: " + tamanho(criticos) + " sensor(es) operando acima de 80.0°C!");
para (numero i = 0; i < tamanho(criticos); i++) {
saida(" >> Temperatura perigosa #" + (i + 1) + ": " + criticos[i] + "°C");
}
} senao {
saida("[SUCESSO] OPERAÇÃO ESTÁVEL: Nenhum sensor atingiu o limite de alarme.");
}
9. Perguntas Frequentes sobre Operações em Vetores (FAQ)
A busca linear funciona se o vetor não estiver ordenado?
Sim! Essa é a principal virtude da busca linear: ela não impõe nenhum pré-requisito de ordenação aos dados. Quer os valores estejam em ordem crescente, decrescente ou completamente embaralhados, a busca sequencial sempre encontrará o item se ele existir, pois inspeciona cada índice um a um.
Existe alguma forma mais rápida de buscar em um vetor do que a busca linear?
Sim. Se o vetor estiver previamente ordenado em ordem crescente, podemos utilizar o algoritmo de Busca Binária (Binary Search), que divide o espaço de busca pela metade a cada comparação, operando em tempo logarítmico extraordinário de $O(\log n)$. Em um vetor de 1.000.000 de itens ordenados, a busca linear faz até 1 milhão de testes, enquanto a busca binária encontra qualquer item em no máximo 20 testes!
O que acontece se houver mais de uma ocorrência da chave procurada no vetor?
Se você utilizar o comando pare na primeira igualdade, o algoritmo retornará apenas o primeiro índice encontrado (primeira ocorrência). Se você desejar encontrar todas as ocorrências, basta remover o comando pare, manter um contador de ocorrências ou salvar os índices encontrados em um vetor auxiliar de posições.
O que aprenderemos na próxima aula (Aula 23)?
Na Aula 23, avançaremos para o universo fascinante dos Algoritmos de Ordenação! Estudaremos em detalhes o famoso Bubble Sort (Método da Bolha): entenderemos a mecânica da flutuação de elementos maiores para o final da lista, laços aninhados, a manobra fundamental da troca de posições (Swap) e otimizações com flags de parada prematura.
Pratique Algoritmos de Vetores na IDE Online!
Escreva o sistema de telemetria industrial no editor do logicabr.dev, execute com dados reais e acompanhe os cálculos diretamente no console.
Abrir IDE Online e Experimentar →