Мапи та словники#

Словники та мапи MicroPython використовують техніки, що називаються відкритою адресацією та лінійним зондуванням. Цей розділ детально описує обидва ці методи.

Відкрита адресація#

Відкрита адресація використовується для вирішення колізій. Колізії є дуже поширеними явищами і виникають, коли два елементи отримують однаковий хеш-слот або місцезнаходження. Наприклад, при наступному налаштуванні хешу:

../../_images/collision.png

Якщо надходить запит на заповнення слоту 0 значенням 70, оскільки слот 0 не є порожнім, відкрита адресація знаходить наступний доступний слот у словнику для обслуговування цього запиту. Цей послідовний пошук альтернативного місця називається зондуванням. Існує кілька алгоритмів послідовного зондування, але MicroPython використовує лінійне зондування, описане в наступному розділі.

Лінійне зондування#

Лінійне зондування — один з методів пошуку доступної адреси або слоту у словнику. У MicroPython воно використовується разом з відкритою адресацією. Для обслуговування описаного вище запиту, на відміну від інших алгоритмів зондування, лінійне зондування передбачає фіксований інтервал 1 між зондами. Тому запит буде оброблено шляхом розміщення елемента в наступному вільному слоті, яким є слот 4 у нашому прикладі:

../../_images/linprob.png

Ті самі методи, тобто відкрита адресація та лінійне зондування, використовуються для пошуку елемента у словнику. Припустимо, ми хочемо знайти елемент даних 33. Обчислене хеш-значення буде 2. Перевіряючи слот 2, знаходимо 33. У цьому випадку повертаємо True. Пошук 70 суттєво відрізняється, оскільки під час вставки виникла колізія. Тому обчислене хеш-значення дорівнює 0, а в цьому слоті наразі знаходиться 44. Замість простого повернення False виконується послідовний пошук починаючи з позиції 1 до знаходження елемента 70 або зустрічі вільного слоту. Це загальний спосіб виконання пошуку в хешах:

// 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;
}