https://labuladong.online/algo/data-structure-basic/linear-probing-code/
今天是學習的第 15 天,主要學習了線性探查法的兩種程式碼實現:
這種作法的思路是 remove
刪除元素後,重新整理後續元素的位置,以保持元素的連續性,搬移資料的這個過程也稱為 rehash。
remove(key) {
const index = this.findKeyIndex(key);
if (!this.table[index]) {
return;
}
this.table[index] = null;
// 保持元素的連續性,搬移資料(這個過程稱為 rehash)
let nextIndex = (index + 1) % this.table.length;
while (this.table[nextIndex]) {
const entry = this.table[nextIndex];
this.table[nextIndex] = null;
// 這個操作是關鍵,利用 put 方法,將鍵值對重新插入
this.put(entry.key, entry.val);
nextIndex = (nextIndex + 1) % this.table.length;
}
}
這種作法的思路是通過一個 DELETE
特殊值作為佔位符,來標記被刪除的元素。
remove(key) {
const index = this.findKeyIndex(key);
if (index === -1) {
// key 不存在,不需要 remove
return;
}
// 直接用佔位符表示刪除
this.table[index] = this.DELETED;
}
當我們使用 findIndexKey
方法查找索引的時候,需要對 DELETED
做特殊處理。
// 線性探查法查找 key 在 table 中的索引
// 如果找不到,返回 -1
findKeyIndex(key) {
// 因為標記刪除元素時只是標記為 DELETE,並不是真的刪除,所以 table 可能會被填滿,導致死循環
// step 用來記錄查找的步數,防止死循環
let step = 0;
// 注意環形陣列特性
for (let i = this.hash(key); this.table[i] !== null; i = (i + 1 ) % this.table.length) {
// 防止死循環
if (++step > this.table.length) {
return -1;
}
// 遇到佔位符直接跳過
if (this.table[i] === this.DELETED) {
continue;
}
if (this.table[i].key === key) {
return i;
}
}
return -1;
}
使用 DUMMY
佔位符來標記已刪除的位置。
// 被刪除的 KVNode 的佔位符
DUMMY = new KVNode(null, null);
remove(key) {
...
// 開始 remove
// 直接用佔位符表示刪除
this.table[index] = this.DUMMY;
...
}
DELETE
特殊值作為佔位符,來標記被刪除的元素DUMMY
來標記已刪除的位置