Что такое открытая адресация? Используется ли этот метод в стандартной реализации `map` в Go?

Ответ

Открытая адресация (open addressing) — это метод разрешения коллизий в хеш-таблицах. Его суть в том, что при возникновении коллизии (когда хеш-функция указывает на уже занятую ячейку) новый элемент помещается в другую свободную ячейку этой же таблицы, найденную по определенному правилу.

Основные стратегии поиска свободной ячейки (пробирования):

  • Линейное пробирование: Последовательно проверяются ячейки (hash(key) + i) % size.
  • Квадратичное пробирование: Проверяются ячейки (hash(key) + i²) % size.
  • Двойное хеширование: Используется вторая хеш-функция: (hash1(key) + i * hash2(key)) % size.

Важный момент: Стандартная реализация map в Go не использует открытую адресацию. Вместо этого Go применяет метод цепочек (chaining). Каждая ячейка (bucket) в хеш-таблице Go может хранить до 8 пар ключ-значение. Если бакет переполняется, создается дополнительный бакет (overflow bucket), и он связывается с основным.

Пример реализации хеш-таблицы с открытой адресацией на Go (для иллюстрации концепции):

// Этот код демонстрирует концепцию и не является реализацией map в Go
type OpenAddrMap struct {
    keys   []string
    values []int
    size   int
}

func (m *OpenAddrMap) Set(key string, value int) {
    // Упрощенный хеш для примера
    idx := int(key[0]) % m.size 
    // Линейное пробирование для поиска свободной ячейки
    for m.keys[idx] != "" && m.keys[idx] != key {
        idx = (idx + 1) % m.size
    }
    m.keys[idx] = key
    m.values[idx] = value
}

Преимущества открытой адресации:

  • Лучшая производительность из-за локальности кэша (все данные хранятся в одном массиве).
  • Отсутствие накладных расходов на хранение указателей на списки или другие структуры.

Недостатки:

  • Производительность сильно деградирует при высоком коэффициенте заполнения (load factor).
  • Сложность при удалении элементов (требуется помечать ячейки как удаленные, а не просто очищать).