Sacos Ordenados
Igor Machado Coelho
02/11/2026
Esta parte é curta e serve como motivação para as próximas aulas.
No Saco, a busca custa
O(n):
sem ordem, é preciso olhar tudo (desafio do Percorrível!).
E se mantivermos os elementos sempre ordenados, como no Conjunto Ordenado?
x?”, “quais entre a e
b?”Um Saco Ordenado é um Saco cujo vetor satisfaz a invariante:
v[0]≤v[1]≤⋯≤v[N−1](≤, pois haˊ repetic¸o˜es!)
Consequência: seu iterador visita os elementos em ordem crescente.
Lembrete: no Saco, removíamos trazendo o último para o buraco. Por que isso agora é proibido?
| Operação | Saco (vetor) | Saco Ordenado (vetor) |
|---|---|---|
adiciona |
O(1) | O(n): abre espaço |
remove |
O(1): traz o último | O(n): fecha o buraco |
busca |
O(n) | O(logn) |
| percorrer | O(n), ordem qualquer | O(n), ordem crescente |
contar cópias de x |
O(n) | O(logn) |
| menor / maior | O(n) | O(1): nas pontas |
| intervalo [a,b] (k elementos) | O(n) | O(logn+k) |
Vale a pena quando há muitas consultas e poucas atualizações.
Motivação: pense em uma estante. Para guardar mais um d
em uma estante ordenada, há um primeiro e um
último lugar possível:
a | d d d | f
^ ^
0 1 2 3 4
buscaMaiorIgual('d') = 1 buscaMaior('d') = 4
(1o elemento >= d) (1o elemento > d)
dd não está no
sacoNa STL existem lower_bound (buscaMaiorIgual) e
upper_bound (buscaMaior), e no Java ceiling e
higher.
O Saco Ordenado usa o mesmo iterador do Saco em vetor (veja mais detalhes nos slides de Sacos):
le(): lê o elemento atual (é uma
Vista)proximo(): avança uma posiçãoterminou(): chegou em fim?Um par (atual, fim) delimita uma
faixa do vetor: as buscas deste tópico só escolhem onde
ela começa e termina!
Um Saco Ordenado é um Saco com elementos comparáveis e com as duas buscas por ordem:
Atenção: o conceito verifica que as buscas existem, mas não que o vetor está ordenado: essa invariante o compilador não consegue verificar!
Consideraremos um vetor de caracteres pré-alocado com capacidade
MAX_N, sempre ordenado.
struct SacoOrdenado1 {
char elementos[MAX_N]; // sempre ordenado
int N; // num. de elementos
void cria(); // vazio
void cria(IteradorTAD<char> auto it); // cópia
void libera();
void adiciona(char x);
IteradorVetor1 iterador();
IteradorVetor1 busca(char x);
IteradorVetor1 remove(IteradorVetor1 it);
int tamanho();
IteradorVetor1 buscaMaiorIgual(char x);
IteradorVetor1 buscaMaior(char x);
};
static_assert(SacoOrdenadoTAD<SacoOrdenado1, char>);// primeira posição com elemento > x
IteradorVetor1 buscaMaior(char x) {
// idêntica, trocando a comparação:
// if (elementos[meio] <= x)
...
}
IteradorVetor1 busca(char x) {
auto it = buscaMaiorIgual(x);
if (!it.terminou() && it.le() == x)
return it;
return {.atual = elementos + N,
.fim = elementos + N};
}Ambas
O(n):
achar o lugar é rápido, deslocar é que custa. O
contrato de remove é o mesmo do Saco!
O intervalo é apenas um iterador com outro fim: uma vista de uma faixa do saco!
Como criar um Saco Ordenado com os n elementos de outro saco?
| Estratégia | Custo |
|---|---|
n
chamadas de adiciona |
O(n2): cada uma desloca |
| copiar + Insertion Sort | O(n2) no pior caso, O(n) se já ordenado |
| copiar + Merge Sort | O(nlogn) sempre |
void cria(IteradorTAD<char> auto it) { // iterador de QUALQUER saco
N = 0;
while (!it.terminou()) { // O(n): copia
elementos[N] = it.le();
N++; it.proximo();
}
ordena(); // O(n log n) com Merge Sort (aula de Conjuntos Simples)
}Desafio: faça o ordena()! Se a origem
for outro Saco Ordenado, qual ordenação você
escolheria?
std::multiset (árvore) e
std::flat_multiset (C++23, vetor ordenado: é o nosso!)buscaMaiorIgual,
buscaMaior e intervalo serão as mesmas!Pergunta final: no Saco Ordenado, achamos o lugar em O(logn), mas deslocamos em O(n). Que estrutura evitaria o deslocamento?
Além da bibliografia do curso, recomendamos para esse tópico:
Em especial, agradeço aos colegas que elaboraram bons materiais, como o prof. Fabiano Oliveira (IME-UERJ), e o prof. Jayme Szwarcfiter cujos conceitos formam o cerne desses slides.
Estendo os agradecimentos aos demais colegas que colaboraram com a elaboração do material do curso de Pesquisa Operacional, que abriu caminho para verificação prática dessa tecnologia de slides.
Esse material de curso só é possível graças aos inúmeros projetos de código-aberto que são necessários a ele, incluindo:
Agradecimento especial a empresas que suportam projetos livres envolvidos nesse curso:
Esses slides foram escritos utilizando pandoc, segundo o tutorial ilectures:
Exceto expressamente mencionado (com as devidas ressalvas ao material cedido por colegas), a licença será Creative Commons.
Licença: CC-BY 4.0 2020
Igor Machado Coelho