Caixa de Ferramentas II: Vetores, Matrizes, Vistas e Algoritmos
por Frank de Alcantara em 30/09/2026
- 1. Contar Antes de Programar: Complexidade, Restrições e Medição
- 2. A Máquina por Baixo do Algoritmo: Tipos, Cache e Desvios
- 3. Treino T01: Contando Antes de Codificar
- 4. Caixa de Ferramentas I: Tipos, Números e Trabalho em Tempo de Compilação
- 5. Caixa de Ferramentas II: Vetores, Matrizes, Vistas e Algoritmos
- 6. Treino T02: Pagar Uma Vez, Perguntar Sempre
- 7. Entrada e Saída de Alto Desempenho
- 8. Treino T03: Alimentando a Máquina
- 9. Busca Binária: Comprar Informação pela Metade
- 10. Ordenar por Comparação: o Limite, a Biblioteca e a Seleção
- 11. Ordenar sem Comparar: Contagem, Radix e a Escolha da Ferramenta
- 12. Treino T04: Comprar Informação
- 13. Somas de Prefixo e Arrays de Diferenças: Integrar e Derivar em Tempo Constante
- 14. Janelas que Deslizam: Deque Monotônico, Dois Ponteiros, Kadane e Sparse Table
- 15. Bits como Conjuntos: Máscaras, popcount e Bitsets de Muitas Palavras
- 16. Hash de Prefixo, Seleção em Três Partes e o Algoritmo de Mo
- 17. Treino T05: Intervalos com Orçamento
- 18. Pilhas, Filas, Heaps e Contêineres Associativos: o Estado que Sobrevive à Pergunta Seguinte
O Artigo 4 cuidou dos valores: o tipo de um literal, as constantes calculadas pelo compilador, as funções genéricas e as lambdas. Este artigo cuida de onde os valores moram e de como são percorridos. A pergunta que atravessa todas as seções é a mesma que o Artigo 2 fez sobre a memória: quem é dono destes bytes, onde eles estão e em que ordem o programa vai visitá-los? Um vetor é dono. Uma vista não é. Uma matriz pode ser um bloco contíguo ou uma coleção de blocos espalhados. Um algoritmo da biblioteca padrão consome uma sequência sem se importar com quem a guarda.
A maior parte das soluções de competição usa três ou quatro contêineres e uma dúzia de algoritmos. Conhecer o custo exato desses poucos instrumentos rende mais do que conhecer superficialmente todos os outros. Por isso, cada ferramenta deste artigo vem acompanhada de uma conta e de uma medição. A conta diz o que deveria acontecer. A medição diz o que aconteceu no MSVC do Visual Studio 18.10.3, compilado com /std:c++latest /O2 /W4 /permissive-, em um Intel Core i7-10750H. Quando as duas discordam, é a conta que precisa ser revista.
1. Vetores: posse, tamanho e capacidade
std::vector<T> é um arranjo contíguo de tamanho variável. A palavra que define o vetor é posse: ele aloca a memória, constrói os elementos nela, destrói os elementos e libera a memória quando deixa de existir. Uma função que recebe std::vector<T> por valor recebe um vetor seu, copiado. Uma função que recebe std::vector<T>& recebe acesso ao vetor de quem chamou. Uma função que recebe std::span<T>, assunto da Seção 3, recebe apenas uma vista sobre memória contígua que pertence a outro objeto.
Um vetor guarda três informações: onde começa o bloco alocado, quantos elementos estão vivos e quantos elementos o bloco comporta. As duas últimas têm nomes. size() é o tamanho, o número de elementos vivos. capacity() é a capacidade, o número de elementos que o bloco atual comporta sem uma nova alocação. A diferença entre as duas é uma reserva de memória que o vetor mantém para que o próximo push_back seja barato.
1.1 Crescimento geométrico e custo amortizado
Quando o tamanho alcança a capacidade, o próximo push_back não cabe. O vetor então aloca um bloco maior, move os elementos antigos para ele, libera o bloco anterior e só então insere o novo elemento. Essa operação custa
A resposta depende da regra de crescimento, que a norma não fixa. A norma exige apenas que push_back tenha custo amortizado constante, isto é, que o custo total de
Este artigo completo contém estratégias práticas e dados exclusivos reservados para nossos membros cadastrados.
Continuar com Google Acesso gratuito e instantâneo com sua conta Google(Updated: )