Mapas e Dicionários

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

Endereçamento aberto

O endereçamento aberto é utilizado para resolver colisões. As colisões são ocorrências muito comuns e acontecem quando dois elementos têm o mesmo valor de hash para a mesma posição ou localização. Por exemplo, dado um hash configurado da seguinte forma:

../_images/collision.png

Se houver um pedido para preencher a posição 0 com 70, como a posição 0 não está vazia, o endereçamento aberto encontra a próxima posição disponível no dicionário para atender este pedido. Esta pesquisa sequencial por uma localização alternativa chama-se sondagem. Existem vários algoritmos de sondagem sequencial, mas o MicroPython utiliza a sondagem linear descrita na próxima secção.

Sondagem linear

A sondagem linear é um dos métodos para encontrar um endereço ou posição disponível num dicionário. No MicroPython, é utilizada com endereçamento aberto. Para atender o pedido descrito acima, ao contrário de outros algoritmos de sondagem, a sondagem linear assume um intervalo fixo de 1 entre sondagens. O pedido será portanto atendido colocando o elemento na próxima posição livre, que é a posição 4 no nosso exemplo:

../_images/linprob.png

Os mesmos métodos, ou seja, endereçamento aberto e sondagem linear, são utilizados para pesquisar um elemento num dicionário. Suponha que queremos pesquisar o elemento de dados 33. O valor de hash calculado será 2. Ao olhar para a posição 2, encontramos 33. Neste ponto, retornamos True. A pesquisa por 70 é bastante 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 pesquisa sequencial a partir do ponto 1 até que o elemento 70 seja encontrado ou encontremos uma posição livre. Esta é a forma geral de realizar pesquisas 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;
}