Mapas e Dicionários

Os dicionários e mapas do MicroPython usam técnicas chamadas endereçamento aberto e sondagem linear. Este capítulo detalha ambos os métodos.

Endereçamento aberto

O endereçamento aberto é usado para resolver colisões. As colisões são ocorrências muito comuns e acontecem quando dois itens acabam tendo o mesmo hash para o mesmo slot ou local. Por exemplo, dada uma configuração de hash como esta:

../_images/collision.png

Se houver uma requisição para preencher o slot 0 com 70, como o slot 0 não está vazio, o endereçamento aberto encontra o próximo slot disponível no dicionário para atender a essa requisição. Essa busca sequencial por um local alternativo é chamada de sondagem (probing). Existem vários algoritmos de sondagem por sequência, mas o MicroPython usa a sondagem linear, descrita na próxima seção.

Sondagem linear

A sondagem linear é um dos métodos para encontrar um endereço ou slot disponível em um dicionário. No MicroPython, ela é usada com o endereçamento aberto. Para atender à requisição descrita acima, diferentemente de outros algoritmos de sondagem, a sondagem linear assume um intervalo fixo de 1 entre as sondagens. A requisição será, portanto, atendida colocando o item no próximo slot livre, que é o slot 4 em nosso exemplo:

../_images/linprob.png

Os mesmos métodos, ou seja, endereçamento aberto e sondagem linear, são usados para buscar um item em um dicionário. Suponha que queremos buscar o item de dados 33. O valor de hash calculado será 2. Olhando para o slot 2, encontramos 33. Nesse ponto, retornamos True. Buscar 70 é bem diferente, pois houve uma colisão no momento da inserção. Portanto, o valor de hash calculado é 0, que atualmente contém 44. Em vez de simplesmente retornar False, realizamos uma busca sequencial começando no ponto 1 até que o item 70 seja encontrado ou encontremos um slot livre. Esta é a maneira geral de realizar consultas em hashes:

// not yet found, keep searching in this table
pos = (pos + 1) % set->alloc;

if (pos == start_pos) {
    // search got back to starting position, so index is not in table
    if (lookup_kind & MP_MAP_LOOKUP_ADD_IF_NOT_FOUND) {
        if (avail_slot != NULL) {
            // there was an available slot, so use that
            set->used++;
            *avail_slot = index;
            return index;
        } else {
            // not enough room in table, rehash it
            mp_set_rehash(set);
            // restart the search for the new element
            start_pos = pos = hash % set->alloc;
        }
    }
} else {
     return MP_OBJ_NULL;
}