-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(chapter_hashing): Add js and ts codes for chapter hashing #675
Changes from 2 commits
7b18d38
7594188
9357dad
e8d237a
675841d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,144 @@ | ||||||||||
/** | ||||||||||
* File: hash_map_chaining.js | ||||||||||
* Created Time: 2023-08-06 | ||||||||||
* Author: yuan0221 (yl1452491917@gmail.com) | ||||||||||
*/ | ||||||||||
|
||||||||||
/* 键值对 Number -> String */ | ||||||||||
class Pair { | ||||||||||
constructor(key, val) { | ||||||||||
this.key = key; | ||||||||||
this.val = val; | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* 链式地址哈希表 */ | ||||||||||
class HashMapChaining { | ||||||||||
#size; // 键值对数量 | ||||||||||
#capacity; // 哈希表容量 | ||||||||||
#loadThres; // 触发扩容的负载因子阈值 | ||||||||||
#extendRatio; // 扩容倍数 | ||||||||||
#buckets; // 桶数组 | ||||||||||
|
||||||||||
/* 构造方法 */ | ||||||||||
constructor() { | ||||||||||
this.#size = 0; | ||||||||||
this.#capacity = 4; | ||||||||||
this.#loadThres = 2 / 3.0; | ||||||||||
this.#extendRatio = 2; | ||||||||||
this.#buckets = new Array(this.#capacity).fill(null).map((x) => []); | ||||||||||
} | ||||||||||
|
||||||||||
/* 哈希函数 */ | ||||||||||
#hashFunc(key) { | ||||||||||
return key % this.#capacity; | ||||||||||
} | ||||||||||
|
||||||||||
/* 负载因子 */ | ||||||||||
#loadFactor() { | ||||||||||
return this.#size / this.#capacity; | ||||||||||
} | ||||||||||
|
||||||||||
/* 查询操作 */ | ||||||||||
get(key) { | ||||||||||
const index = this.#hashFunc(key); | ||||||||||
const bucket = this.#buckets[index]; | ||||||||||
// 遍历桶,若找到 key 则返回对应 val | ||||||||||
for (let pair of bucket) { | ||||||||||
if (pair.key === key) { | ||||||||||
return pair.val; | ||||||||||
} | ||||||||||
} | ||||||||||
// 若未找到 key 则返回 null | ||||||||||
return null; | ||||||||||
} | ||||||||||
|
||||||||||
/* 添加操作 */ | ||||||||||
put(key, val) { | ||||||||||
// 当负载因子超过阈值时,执行扩容 | ||||||||||
if (this.#loadFactor() > this.#loadThres) { | ||||||||||
this.#extend(); | ||||||||||
} | ||||||||||
const index = this.#hashFunc(key); | ||||||||||
const bucket = this.#buckets[index]; | ||||||||||
// 遍历桶,若遇到指定 key ,则更新对应 val 并返回 | ||||||||||
for (let pair of bucket) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
if (pair.key === key) { | ||||||||||
pair.val = val; | ||||||||||
return; | ||||||||||
} | ||||||||||
} | ||||||||||
// 若无该 key ,则将键值对添加至尾部 | ||||||||||
const pair = new Pair(key, val); | ||||||||||
bucket.push(pair); | ||||||||||
this.#size++; | ||||||||||
} | ||||||||||
|
||||||||||
/* 删除操作 */ | ||||||||||
remove(key) { | ||||||||||
const index = this.#hashFunc(key); | ||||||||||
let bucket = this.#buckets[index]; | ||||||||||
// 遍历桶,从中删除键值对 | ||||||||||
for (let pair of bucket) { | ||||||||||
if (pair.key === key) { | ||||||||||
this.#buckets[index] = bucket.filter( | ||||||||||
(pair) => pair.key !== key | ||||||||||
); | ||||||||||
this.#size--; | ||||||||||
break; | ||||||||||
} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The filter method goes through every pair in the bucket twice (once for the for...of loop and once for the filter), splice will be better |
||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* 扩容哈希表 */ | ||||||||||
#extend() { | ||||||||||
// 暂存原哈希表 | ||||||||||
const bucketsTmp = this.#buckets; | ||||||||||
// 初始化扩容后的新哈希表 | ||||||||||
this.#capacity *= this.#extendRatio; | ||||||||||
this.#buckets = new Array(this.#capacity).fill(null).map((x) => []); | ||||||||||
this.#size = 0; | ||||||||||
// 将键值对从原哈希表搬运至新哈希表 | ||||||||||
for (let bucket of bucketsTmp) { | ||||||||||
for (let pair of bucket) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
this.put(pair.key, pair.val); | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* 打印哈希表 */ | ||||||||||
print() { | ||||||||||
for (let bucket of this.#buckets) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
let res = []; | ||||||||||
for (let pair of bucket) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
res.push(pair.key + ' -> ' + pair.val); | ||||||||||
} | ||||||||||
console.log(res); | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* Driver Code */ | ||||||||||
/* 初始化哈希表 */ | ||||||||||
const map = new HashMapChaining(); | ||||||||||
|
||||||||||
/* 添加操作 */ | ||||||||||
// 在哈希表中添加键值对 (key, value) | ||||||||||
map.put(12836, '小哈'); | ||||||||||
map.put(15937, '小啰'); | ||||||||||
map.put(16750, '小算'); | ||||||||||
map.put(13276, '小法'); | ||||||||||
map.put(10583, '小鸭'); | ||||||||||
console.log('\n添加完成后,哈希表为\nKey -> Value'); | ||||||||||
map.print(); | ||||||||||
|
||||||||||
/* 查询操作 */ | ||||||||||
// 向哈希表输入键 key ,得到值 value | ||||||||||
const name = map.get(13276); | ||||||||||
console.log('\n输入学号 13276 ,查询到姓名 ' + name); | ||||||||||
|
||||||||||
/* 删除操作 */ | ||||||||||
// 在哈希表中删除键值对 (key, value) | ||||||||||
map.remove(12836); | ||||||||||
console.log('\n删除 12836 后,哈希表为\nKey -> Value'); | ||||||||||
map.print(); |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,162 @@ | ||||||||||
/** | ||||||||||
* File: hash_map_open_addressing.js | ||||||||||
* Created Time: 2023-08-06 | ||||||||||
* Author: yuan0221 (yl1452491917@gmail.com) | ||||||||||
*/ | ||||||||||
|
||||||||||
/* 键值对 Number -> String */ | ||||||||||
class Pair { | ||||||||||
constructor(key, val) { | ||||||||||
this.key = key; | ||||||||||
this.val = val; | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* 开放寻址哈希表 */ | ||||||||||
class HashMapOpenAddressing { | ||||||||||
#size; // 键值对数量 | ||||||||||
#capacity; // 哈希表容量 | ||||||||||
#loadThres; // 触发扩容的负载因子阈值 | ||||||||||
#extendRatio; // 扩容倍数 | ||||||||||
#buckets; // 桶数组 | ||||||||||
#removed; // 删除标记 | ||||||||||
|
||||||||||
/* 构造方法 */ | ||||||||||
constructor() { | ||||||||||
this.#size = 0; | ||||||||||
this.#capacity = 4; | ||||||||||
this.#loadThres = 2.0 / 3.0; | ||||||||||
this.#extendRatio = 2; | ||||||||||
this.#buckets = new Array(this.#capacity).fill(null); | ||||||||||
this.#removed = new Pair(-1, '-1'); | ||||||||||
} | ||||||||||
|
||||||||||
/* 哈希函数 */ | ||||||||||
#hashFunc(key) { | ||||||||||
return key % this.#capacity; | ||||||||||
} | ||||||||||
|
||||||||||
/* 负载因子 */ | ||||||||||
#loadFactor() { | ||||||||||
return this.#size / this.#capacity; | ||||||||||
} | ||||||||||
|
||||||||||
/* 查询操作 */ | ||||||||||
get(key) { | ||||||||||
const index = this.#hashFunc(key); | ||||||||||
// 线性探测,从 index 开始向后遍历 | ||||||||||
for (let i = 0; i < this.#capacity; i++) { | ||||||||||
// 计算桶索引,越过尾部返回头部 | ||||||||||
const j = (index + i) % this.#capacity; | ||||||||||
// 若遇到空桶,说明无此 key ,则返回 null | ||||||||||
if (this.#buckets[j] === null) return null; | ||||||||||
// 若遇到指定 key ,则返回对应 val | ||||||||||
if ( | ||||||||||
this.#buckets[j]?.key === key && | ||||||||||
this.#buckets[j]?.[key] !== this.#removed.key | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
) | ||||||||||
return this.#buckets[j].val; | ||||||||||
} | ||||||||||
return null; | ||||||||||
} | ||||||||||
|
||||||||||
/* 添加操作 */ | ||||||||||
put(key, val) { | ||||||||||
// 当负载因子超过阈值时,执行扩容 | ||||||||||
if (this.#loadFactor() > this.#loadThres) { | ||||||||||
this.#extend(); | ||||||||||
} | ||||||||||
const index = this.#hashFunc(key); | ||||||||||
// 线性探测,从 index 开始向后遍历 | ||||||||||
for (let i = 0; i < this.#capacity; i++) { | ||||||||||
// 计算桶索引,越过尾部返回头部 | ||||||||||
let j = (index + i) % this.#capacity; | ||||||||||
// 若遇到空桶、或带有删除标记的桶,则将键值对放入该桶 | ||||||||||
if ( | ||||||||||
this.#buckets[j] === null || | ||||||||||
this.#buckets[j][key] === this.#removed.key | ||||||||||
) { | ||||||||||
this.#buckets[j] = new Pair(key, val); | ||||||||||
this.#size += 1; | ||||||||||
return; | ||||||||||
} | ||||||||||
// 若遇到指定 key ,则更新对应 val | ||||||||||
if (this.#buckets[j]?.key === key) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
this.#buckets[j].val = val; | ||||||||||
return; | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* 删除操作 */ | ||||||||||
remove(key) { | ||||||||||
const index = this.#hashFunc(key); | ||||||||||
// 线性探测,从 index 开始向后遍历 | ||||||||||
for (let i = 0; i < this.#capacity; i++) { | ||||||||||
// 计算桶索引,越过尾部返回头部 | ||||||||||
const j = (index + i) % this.#capacity; | ||||||||||
// 若遇到空桶,说明无此 key ,则直接返回 | ||||||||||
if (this.#buckets[j] === null) { | ||||||||||
return; | ||||||||||
} | ||||||||||
// 若遇到指定 key ,则标记删除并返回 | ||||||||||
if (this.#buckets[j]?.key === key) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
this.#buckets[j] = this.#removed; | ||||||||||
this.#size -= 1; | ||||||||||
return; | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* 扩容哈希表 */ | ||||||||||
#extend() { | ||||||||||
// 暂存原哈希表 | ||||||||||
const bucketsTmp = this.#buckets; | ||||||||||
// 初始化扩容后的新哈希表 | ||||||||||
this.#capacity *= this.#extendRatio; | ||||||||||
this.#buckets = new Array(this.#capacity).fill(null); | ||||||||||
this.#size = 0; | ||||||||||
// 将键值对从原哈希表搬运至新哈希表 | ||||||||||
for (let pair of bucketsTmp) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need to be updated |
||||||||||
if (pair !== null && pair.key !== this.#removed.key) { | ||||||||||
this.put(pair.key, pair.val); | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* 打印哈希表 */ | ||||||||||
print() { | ||||||||||
for (let pair of this.#buckets) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. need to be updated |
||||||||||
if (pair !== null) { | ||||||||||
console.log(pair.key + ' -> ' + pair.val); | ||||||||||
} else { | ||||||||||
console.log('null'); | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
/* Driver Code */ | ||||||||||
/* 初始化哈希表 */ | ||||||||||
let map = new HashMapOpenAddressing(); | ||||||||||
|
||||||||||
/* 添加操作 */ | ||||||||||
// 在哈希表中添加键值对 (key, value) | ||||||||||
map.put(12836, '小哈'); | ||||||||||
map.put(15937, '小啰'); | ||||||||||
map.put(16750, '小算'); | ||||||||||
map.put(13276, '小法'); | ||||||||||
map.put(10583, '小鸭'); | ||||||||||
console.log('\n添加完成后,哈希表为\nKey -> Value'); | ||||||||||
map.print(); | ||||||||||
|
||||||||||
/* 查询操作 */ | ||||||||||
// 向哈希表输入键 key ,得到值 value | ||||||||||
const name = map.get(13276); | ||||||||||
console.log('\n输入学号 13276 ,查询到姓名 ' + name); | ||||||||||
|
||||||||||
/* 删除操作 */ | ||||||||||
// 在哈希表中删除键值对 (key, value) | ||||||||||
map.remove(16750); | ||||||||||
console.log('\n删除 16750 后,哈希表为\nKey -> Value'); | ||||||||||
map.print(); |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,60 @@ | ||||||
/** | ||||||
* File: simple_hash.js | ||||||
* Created Time: 2023-08-06 | ||||||
* Author: yuan0221 (yl1452491917@gmail.com) | ||||||
*/ | ||||||
|
||||||
/* 加法哈希 */ | ||||||
function addHash(key) { | ||||||
let hash = 0; | ||||||
const MODULUS = 1000000007; | ||||||
for (let c of key) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
hash = (hash + c.charCodeAt(0)) % MODULUS; | ||||||
} | ||||||
return hash; | ||||||
} | ||||||
|
||||||
/* 乘法哈希 */ | ||||||
function mulHash(key) { | ||||||
let hash = 0; | ||||||
const MODULUS = 1000000007; | ||||||
for (let c of key) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
hash = (31 * hash + c.charCodeAt(0)) % MODULUS; | ||||||
} | ||||||
return hash; | ||||||
} | ||||||
|
||||||
/* 异或哈希 */ | ||||||
function xorHash(key) { | ||||||
let hash = 0; | ||||||
const MODULUS = 1000000007; | ||||||
for (let c of key) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
hash ^= c.charCodeAt(0); | ||||||
} | ||||||
return hash & MODULUS; | ||||||
} | ||||||
|
||||||
/* 旋转哈希 */ | ||||||
function rotHash(key) { | ||||||
let hash = 0; | ||||||
const MODULUS = 1000000007; | ||||||
for (let c of key) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
hash = ((hash << 4) ^ (hash >> 28) ^ c.charCodeAt(0)) % MODULUS; | ||||||
} | ||||||
return hash; | ||||||
} | ||||||
|
||||||
/* Driver Code */ | ||||||
const key = 'Hello 算法'; | ||||||
|
||||||
let hash = addHash(key); | ||||||
console.log('加法哈希值为 ' + hash); | ||||||
|
||||||
hash = mulHash(key); | ||||||
console.log('乘法哈希值为 ' + hash); | ||||||
|
||||||
hash = xorHash(key); | ||||||
console.log('异或哈希值为 ' + hash); | ||||||
|
||||||
hash = rotHash(key); | ||||||
console.log('旋转哈希值为 ' + hash); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.