فاخته هشویی: یک تکنیک وضوح کارآمد برخورد با O (1) زمان جستجو

نمای کلی
Cuckoo Hashing یک تکنیک پیشرفته است که برای حل و فصل برخوردهای هش استفاده می شود. بر خلاف روشهای هشویی سنتی ، که ممکن است در بدترین حالت به O (n) تخریب شود ، فاخته هشویی ، پیچیدگی زمانی بدترین حالت O (1) را برای جستجوی ، درج و حذف تضمین می کند.
مفهوم فاخته
Cuckoo Hashing هنگامی که یک تصادف در هنگام درج رخ می دهد ، از یک استراتژی “شروع به کار” استفاده می کند. از دو جدول هش جداگانه (H1 و H2) و دو عملکرد هش (F1 (X) و F2 (x)) استفاده می کند. در صورت قرار دادن یک عنصر داده D1 به H1 ، در صورت بروز برخورد ، عنصر موجود در H1 جابجا می شود (بیرون رانده می شود) و بر اساس عملکرد هش دوم به H2 منتقل می شود. این فرآیند بین H1 و H2 تکرار می شود تا زمانی که موقعیت خالی پیدا شود.
برای جلوگیری از حلقه های نامتناهی در هنگام درج ، از ثابت از پیش تعریف شده (max_hash_loop) برای محدود کردن مجدد مجدد استفاده می شود. در صورت دستیابی به این حد ، جداول هش تغییر اندازه داده می شود ، و یک عملیات مجدد انجام می شود تا ضمن حفظ پیچیدگی زمان O (1) درج ، عناصر جدید را در خود جای دهد.
ویژگی های کلیدی:
- از دو جدول هش برای وضوح برخورد کارآمد استفاده می کند.
- برای تعیین قرار دادن داده ها از دو کارکرد هش مجزا استفاده می کند.
- از عملیات درج سریع ، جستجو و حذف پشتیبانی می کند.
- مکانیسم تجدید نظر را برای رسیدگی به حلقه های درج بی نهایت پیاده سازی می کند.
اجرای فاخته هش در C ++
#include
#include
#include
#include
using namespace std;
#define TABLE_SIZE 11 // Initial hash table size
#define MAX_REHASH 10 // Maximum reinsertion attempts before rehashing
class CuckooHashTable {
private:
vector table1, table2;
vector occupied1, occupied2;
int hash1(int key) { return key % TABLE_SIZE; }
int hash2(int key) { return (key / TABLE_SIZE) % TABLE_SIZE; }
void rehash() {
cout << "Rehashing required!" << endl;
vector oldTable1 = table1, oldTable2 = table2;
vector oldOccupied1 = occupied1, oldOccupied2 = occupied2;
int newSize = TABLE_SIZE * 2;
table1.assign(newSize, -1);
table2.assign(newSize, -1);
occupied1.assign(newSize, false);
occupied2.assign(newSize, false);
for (int i = 0; i < oldTable1.size(); i++) {
if (oldOccupied1[i]) insert(oldTable1[i]);
if (oldOccupied2[i]) insert(oldTable2[i]);
}
}
public:
CuckooHashTable() {
table1.assign(TABLE_SIZE, -1);
table2.assign(TABLE_SIZE, -1);
occupied1.assign(TABLE_SIZE, false);
occupied2.assign(TABLE_SIZE, false);
}
void insert(int key) {
int pos1 = hash1(key);
int pos2 = hash2(key);
int loopCounter = 0;
int currKey = key;
while (loopCounter < MAX_REHASH) {
if (!occupied1[pos1]) {
table1[pos1] = currKey;
occupied1[pos1] = true;
return;
}
swap(currKey, table1[pos1]);
if (!occupied2[pos2]) {
table2[pos2] = currKey;
occupied2[pos2] = true;
return;
}
swap(currKey, table2[pos2]);
pos1 = hash1(currKey);
pos2 = hash2(currKey);
loopCounter++;
}
rehash();
insert(currKey);
}
bool search(int key) {
return (occupied1[hash1(key)] && table1[hash1(key)] == key) ||
(occupied2[hash2(key)] && table2[hash2(key)] == key);
}
void remove(int key) {
if (occupied1[hash1(key)] && table1[hash1(key)] == key) {
occupied1[hash1(key)] = false;
table1[hash1(key)] = -1;
return;
}
if (occupied2[hash2(key)] && table2[hash2(key)] == key) {
occupied2[hash2(key)] = false;
table2[hash2(key)] = -1;
return;
}
cout << "Key not found!" << endl;
}
void display() {
cout << "Table 1: ";
for (int i = 0; i < TABLE_SIZE; i++)
cout << (occupied1[i] ? to_string(table1[i]) : "-") << " ";
cout << "\nTable 2: ";
for (int i = 0; i < TABLE_SIZE; i++)
cout << (occupied2[i] ? to_string(table2[i]) : "-") << " ";
cout << "\n";
}
};
int main() {
CuckooHashTable hashTable;
hashTable.insert(10);
hashTable.insert(20);
hashTable.insert(30);
hashTable.insert(25);
hashTable.insert(35);
hashTable.insert(40);
hashTable.insert(50);
hashTable.display();
cout << "Searching 25: " << (hashTable.search(25) ? "Found" : "Not Found") << endl;
cout << "Searching 100: " << (hashTable.search(100) ? "Found" : "Not Found") << endl;
hashTable.remove(30);
hashTable.display();
return 0;
}
توضیح:
نمای کلی ساختار داده ها:
- دو میز هش جداگانه (جدول 1 و جدول 2).
- بردارهای بولی (اشغال 1 و اشغال 2) شکاف های اشغال شده را دنبال می کنند.
توابع هش:
- HASH1 (کلید) = کلید ٪ table_size
- hash2 (کلید) = (key / table_size) ٪ table_size
فرآیند درج:
- سعی کنید در جدول 1 قرار دهید. در صورت اشغال ، با عنصر موجود مبادله کنید.
- سعی کنید عنصر جابجایی شده را در جدول 2 وارد کنید. در صورت اشغال ، به تعویض ادامه دهید.
- اگر یک حلقه مجدد تشخیص داده شود (MAX_REHASH به آن رسیده است) ، دوباره شروع می شود.
جستجو و حذف:
- جستجو هر دو جدول را بررسی می کند.
- حذف شکاف را به عنوان بدون استفاده نشان می دهد.
پایان
فاخته هشویی یک راه حل کارآمد برای حل برخورد هش با یک زمان جستجوی بدترین حالت O (1) ارائه می دهد. با استفاده از دو میز هش و مکانیسم ضربه زدن ، عملکرد بالایی را تضمین می کند و از توالی های طولانی کاوشی جلوگیری می کند. مکانیسم تجدید نظر در هنگام وقوع حلقه های درج ، تغییر اندازه پویا را امکان پذیر می کند و حتی در بارهای کاری پویا حفظ می کند. این روش به ویژه در برنامه هایی که زمان دسترسی سریع بسیار مهم است ، مانند حافظه پنهان ، برنامه های شبکه و سیستم های زمان واقعی مفید است.
منابع: