Решение о необходимости перестроения (рехеширования) хэш-таблицы принимается на основе значения нагрузки (load factor). Нагрузка — это отношение количества элементов в хэш-таблице к количеству бакетов (размеру массива).
🚩Порог нагрузки
Для каждой хэш-таблицы обычно определяется пороговое значение нагрузки. Когда фактическая нагрузка превышает это пороговое значение, происходит рехеширование.
Формула нагрузки:
\text{load factor} = \frac{\text{number of elements}}{\text{size of table}} Типичные пороговые значения: Пороговое значение нагрузки часто устанавливается в пределах от 0.5 до 1.0, в зависимости от реализации. Например,
std::unordered_map в стандартной библиотеке C++ по умолчанию использует пороговое значение 1.0.🚩Процесс рехеширования
1⃣Увеличение размера таблицы
Размер массива увеличивается, часто в два раза.
2⃣Перераспределение элементов
Все существующие элементы перераспределяются в новую таблицу с использованием новой хэш-функции или той же хэш-функции, но с новым размером таблицы.
🚩Пример
#include <iostream>
#include <list>
#include <vector>
class HashTable {
private:
int currentSize;
int numberOfElements;
double loadFactorThreshold;
std::vector<std::list<std::pair<int, std::string>>> table;
void rehash() {
int oldSize = currentSize;
currentSize *= 2; // Увеличиваем размер таблицы
std::vector<std::list<std::pair<int, std::string>>> newTable(currentSize);
for (const auto& list : table) {
for (const auto& pair : list) {
int hashValue = pair.first % currentSize;
newTable[hashValue].emplace_back(pair.first, pair.second);
}
}
table = std::move(newTable);
}
public:
HashTable(int size = 10, double threshold = 0.75)
: currentSize(size), numberOfElements(0), loadFactorThreshold(threshold) {
table.resize(currentSize);
}
int hashFunction(int key) {
return key % currentSize;
}
void insertItem(int key, std::string value) {
int hashValue = hashFunction(key);
table[hashValue].emplace_back(key, value);
numberOfElements++;
// Проверяем, нужно ли выполнять рехеширование
if (static_cast<double>(numberOfElements) / currentSize > loadFactorThreshold) {
rehash();
}
}
void displayTable() {
for (int i = 0; i < currentSize; i++) {
if (!table[i].empty()) {
std::cout << "Bucket " << i << ": ";
for (auto& pair : table[i]) {
std::cout << "[" << pair.first << ": " << pair.second << "] ";
}
std::cout << std::endl;
}
}
}
};
int main() {
HashTable ht;
ht.insertItem(1, "one");
ht.insertItem(2, "two");
ht.insertItem(11, "eleven"); // Триггер рехеширования при необходимости
ht.displayTable();
// Вывод:
// Bucket 1: [1: one]
// Bucket 2: [2: two]
// Bucket 11: [11: eleven]
return 0;
}
🚩Когда происходит
Рехеширование обычно инициируется в момент, когда после добавления нового элемента нагрузка превышает установленное пороговое значение. Это гарантирует, что хэш-таблица будет эффективно обрабатывать операции поиска, вставки и удаления, поддерживая амортизированное постоянное время для этих операций.
Ставь 👍 и забирай 📚 Базу знаний