std::unordered_map::reserve în C++

reserve() pregătește tabela hash pentru n elemente; bucket_count() și load_factor() arată cât de încărcată este.

Sintaxă
void reserve(size_type n);
size_type bucket_count() const noexcept;
float load_factor() const noexcept;
float max_load_factor() const noexcept;

Ce face std::unordered_map::reserve

O tabelă hash are un număr de găleți (bucket_count()). load_factor() este media de elemente pe găleată: size() / bucket_count(). Când aceasta ar depăși max_load_factor() (implicit 1.0), tabela face un rehash: alocă mai multe găleți și redistribuie toate elementele. Rehash-ul costă și invalidează toți iteratorii.

reserve(n) alege dinainte destule găleți pentru n elemente fără să depășească max_load_factor(), deci nu vor mai fi rehash-uri până la n elemente. Numărul exact de găleți ales depinde de bibliotecă (libc++ preferă numere prime); valorile de mai jos sunt cele de pe libc++.

Parametri

Parametru Descriere
n Numărul de elemente pentru care se pregătește tabela.

Ce returnează

reserve: nimic. bucket_count: numărul de găleți. load_factor: elemente pe găleată, ca float.

Exemple

Exemplul 1: Găleți și grad de încărcare

#include <print>
#include <unordered_map>

int main() {
    std::unordered_map<int, int> m;
    std::println("gol:           buckets={} load={}", m.bucket_count(), m.load_factor());
    m.reserve(100);
    std::println("după reserve:  buckets={} load={}", m.bucket_count(), m.load_factor());
    for (int i = 0; i < 50; ++i) {
        m[i] = i * i;
    }
    std::println("50 elemente:   buckets={} load={:.3f} max={}", m.bucket_count(), m.load_factor(), m.max_load_factor());
}

Rezultat

gol:           buckets=0 load=0
după reserve:  buckets=101 load=0
50 elemente:   buckets=101 load=0.495 max=1

Exemplul 2: Câte rehash-uri evită reserve

#include <print>
#include <unordered_map>

int rehashuri(bool cu_reserve) {
    std::unordered_map<int, int> m;
    if (cu_reserve) {
        m.reserve(10000);
    }
    int numar = 0;
    auto galeti = m.bucket_count();
    for (int i = 0; i < 10000; ++i) {
        m[i] = i;
        if (m.bucket_count() != galeti) {
            ++numar;
            galeti = m.bucket_count();
        }
    }
    return numar;
}

int main() {
    std::println("Fără reserve: {} rehash-uri", rehashuri(false));
    std::println("Cu reserve:   {} rehash-uri", rehashuri(true));
}

Rezultat

Fără reserve: 13 rehash-uri
Cu reserve:   0 rehash-uri

Greșeli frecvente

  • Confunzi reserve(n) al tabelei hash cu cel al vectorului: aici n înseamnă elemente, nu găleți. Pentru un număr de găleți, există rehash(numar_galeti).
  • Te bazezi pe valori exacte ale lui bucket_count(). Ele diferă între biblioteci (libc++, libstdc++, MSVC).

Comenzi înrudite

  • std::unordered_map: Dicționar bazat pe tabelă hash: căutare în timp mediu constant, dar fără o ordine anume a elementelor.
  • std::vector::reserve: reserve() rezervă memorie pentru n elemente, capacity() spune cât loc este rezervat, iar shrink_to_fit() cere eliberarea locului nefolosit.
  • std::unordered_set: Mulțime de valori unice bazată pe hash: verificare „există?” în timp mediu constant, fără ordine.