Мапи та словники¶
Словники та мапи MicroPython використовують техніки, що називаються відкритою адресацією та лінійним зондуванням. Цей розділ детально описує обидва ці методи.
Відкрита адресація¶
Відкрита адресація використовується для вирішення колізій. Колізії є дуже поширеними явищами і виникають, коли два елементи отримують однаковий хеш-слот або місцезнаходження. Наприклад, при наступному налаштуванні хешу:
Якщо надходить запит на заповнення слоту 0 значенням 70, оскільки слот 0 не є порожнім, відкрита адресація знаходить наступний доступний слот у словнику для обслуговування цього запиту. Цей послідовний пошук альтернативного місця називається зондуванням. Існує кілька алгоритмів послідовного зондування, але MicroPython використовує лінійне зондування, описане в наступному розділі.
Лінійне зондування¶
Лінійне зондування — один з методів пошуку доступної адреси або слоту у словнику. У MicroPython воно використовується разом з відкритою адресацією. Для обслуговування описаного вище запиту, на відміну від інших алгоритмів зондування, лінійне зондування передбачає фіксований інтервал 1 між зондами. Тому запит буде оброблено шляхом розміщення елемента в наступному вільному слоті, яким є слот 4 у нашому прикладі:
Ті самі методи, тобто відкрита адресація та лінійне зондування, використовуються для пошуку елемента у словнику. Припустимо, ми хочемо знайти елемент даних 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;
}