From 7b18d3838ca10e90c442235dd2791b6146033efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Sun, 6 Aug 2023 20:35:34 +0800 Subject: [PATCH 1/5] refactor(chapter_hashing): Remove unnecessary chaining operator --- codes/javascript/chapter_hashing/array_hash_map.js | 4 ++-- codes/typescript/chapter_hashing/array_hash_map.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codes/javascript/chapter_hashing/array_hash_map.js b/codes/javascript/chapter_hashing/array_hash_map.js index 270825e8a5..cb0a9bd2f0 100644 --- a/codes/javascript/chapter_hashing/array_hash_map.js +++ b/codes/javascript/chapter_hashing/array_hash_map.js @@ -62,7 +62,7 @@ class ArrayHashMap { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { if (this.#buckets[i]) { - arr.push(this.#buckets[i]?.key); + arr.push(this.#buckets[i].key); } } return arr; @@ -73,7 +73,7 @@ class ArrayHashMap { let arr = []; for (let i = 0; i < this.#buckets.length; i++) { if (this.#buckets[i]) { - arr.push(this.#buckets[i]?.val); + arr.push(this.#buckets[i].val); } } return arr; diff --git a/codes/typescript/chapter_hashing/array_hash_map.ts b/codes/typescript/chapter_hashing/array_hash_map.ts index a039ea9358..eba8e69be1 100644 --- a/codes/typescript/chapter_hashing/array_hash_map.ts +++ b/codes/typescript/chapter_hashing/array_hash_map.ts @@ -66,7 +66,7 @@ class ArrayHashMap { let arr: (number | undefined)[] = []; for (let i = 0; i < this.buckets.length; i++) { if (this.buckets[i]) { - arr.push(this.buckets[i]?.key); + arr.push(this.buckets[i].key); } } return arr; @@ -77,7 +77,7 @@ class ArrayHashMap { let arr: (string | undefined)[] = []; for (let i = 0; i < this.buckets.length; i++) { if (this.buckets[i]) { - arr.push(this.buckets[i]?.val); + arr.push(this.buckets[i].val); } } return arr; From 7594188de52b3dd268b7c34ed021c046302637c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Sun, 6 Aug 2023 20:35:59 +0800 Subject: [PATCH 2/5] feat(chapter_hashing): Add js and ts codes for chapter 6 --- .../chapter_hashing/hash_map_chaining.js | 144 +++++++++++++++ .../hash_map_open_addressing.js | 162 +++++++++++++++++ .../javascript/chapter_hashing/simple_hash.js | 60 +++++++ .../chapter_hashing/hash_map_chaining.ts | 148 ++++++++++++++++ .../hash_map_open_addressing.ts | 166 ++++++++++++++++++ .../typescript/chapter_hashing/simple_hash.ts | 60 +++++++ 6 files changed, 740 insertions(+) create mode 100644 codes/javascript/chapter_hashing/hash_map_chaining.js create mode 100644 codes/javascript/chapter_hashing/hash_map_open_addressing.js create mode 100644 codes/javascript/chapter_hashing/simple_hash.js create mode 100644 codes/typescript/chapter_hashing/hash_map_chaining.ts create mode 100644 codes/typescript/chapter_hashing/hash_map_open_addressing.ts create mode 100644 codes/typescript/chapter_hashing/simple_hash.ts diff --git a/codes/javascript/chapter_hashing/hash_map_chaining.js b/codes/javascript/chapter_hashing/hash_map_chaining.js new file mode 100644 index 0000000000..2ee61706eb --- /dev/null +++ b/codes/javascript/chapter_hashing/hash_map_chaining.js @@ -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) { + 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; + } + } + } + + /* 扩容哈希表 */ + #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) { + this.put(pair.key, pair.val); + } + } + } + + /* 打印哈希表 */ + print() { + for (let bucket of this.#buckets) { + let res = []; + for (let pair of bucket) { + 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(); diff --git a/codes/javascript/chapter_hashing/hash_map_open_addressing.js b/codes/javascript/chapter_hashing/hash_map_open_addressing.js new file mode 100644 index 0000000000..402c42d0ea --- /dev/null +++ b/codes/javascript/chapter_hashing/hash_map_open_addressing.js @@ -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 + ) + 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) { + 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) { + 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) { + if (pair !== null && pair.key !== this.#removed.key) { + this.put(pair.key, pair.val); + } + } + } + + /* 打印哈希表 */ + print() { + for (let pair of this.#buckets) { + 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(); diff --git a/codes/javascript/chapter_hashing/simple_hash.js b/codes/javascript/chapter_hashing/simple_hash.js new file mode 100644 index 0000000000..7971feef93 --- /dev/null +++ b/codes/javascript/chapter_hashing/simple_hash.js @@ -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) { + hash = (hash + c.charCodeAt(0)) % MODULUS; + } + return hash; +} + +/* 乘法哈希 */ +function mulHash(key) { + let hash = 0; + const MODULUS = 1000000007; + for (let c of key) { + hash = (31 * hash + c.charCodeAt(0)) % MODULUS; + } + return hash; +} + +/* 异或哈希 */ +function xorHash(key) { + let hash = 0; + const MODULUS = 1000000007; + for (let c of key) { + hash ^= c.charCodeAt(0); + } + return hash & MODULUS; +} + +/* 旋转哈希 */ +function rotHash(key) { + let hash = 0; + const MODULUS = 1000000007; + for (let c of key) { + 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); diff --git a/codes/typescript/chapter_hashing/hash_map_chaining.ts b/codes/typescript/chapter_hashing/hash_map_chaining.ts new file mode 100644 index 0000000000..14e4cc982b --- /dev/null +++ b/codes/typescript/chapter_hashing/hash_map_chaining.ts @@ -0,0 +1,148 @@ +/** + * File: hash_map_chaining.ts + * Created Time: 2023-08-06 + * Author: yuan0221 (yl1452491917@gmail.com) + */ + +/* 键值对 Number -> String */ +class Pair { + key: number; + val: string; + constructor(key: number, val: string) { + this.key = key; + this.val = val; + } +} + +/* 链式地址哈希表 */ +class HashMapChaining { + #size: number; // 键值对数量 + #capacity: number; // 哈希表容量 + #loadThres: number; // 触发扩容的负载因子阈值 + #extendRatio: number; // 扩容倍数 + #buckets: Pair[][]; // 桶数组 + + /* 构造方法 */ + 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: number): number { + return key % this.#capacity; + } + + /* 负载因子 */ + #loadFactor(): number { + return this.#size / this.#capacity; + } + + /* 查询操作 */ + get(key: number): string | null { + 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: number, val: string): void { + // 当负载因子超过阈值时,执行扩容 + if (this.#loadFactor() > this.#loadThres) { + this.#extend(); + } + const index = this.#hashFunc(key); + const bucket = this.#buckets[index]; + // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 + for (let pair of bucket) { + if (pair.key === key) { + pair.val = val; + return; + } + } + // 若无该 key ,则将键值对添加至尾部 + const pair = new Pair(key, val); + bucket.push(pair); + this.#size++; + } + + /* 删除操作 */ + remove(key: number): void { + 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; + } + } + } + + /* 扩容哈希表 */ + #extend(): void { + // 暂存原哈希表 + 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) { + this.put(pair.key, pair.val); + } + } + } + + /* 打印哈希表 */ + print() { + for (let bucket of this.#buckets) { + let res = []; + for (let pair of bucket) { + 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(); + +export {}; diff --git a/codes/typescript/chapter_hashing/hash_map_open_addressing.ts b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts new file mode 100644 index 0000000000..4d8786265d --- /dev/null +++ b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts @@ -0,0 +1,166 @@ +/** + * File: hash_map_open_addressing.ts + * Created Time: 2023-08-06 + * Author: yuan0221 (yl1452491917@gmail.com) + */ + +/* 键值对 Number -> String */ +class Pair { + key: number; + val: string; + constructor(key: number, val: string) { + this.key = key; + this.val = val; + } +} + +/* 开放寻址哈希表 */ +class HashMapOpenAddressing { + #size: number; // 键值对数量 + #capacity: number; // 哈希表容量 + #loadThres: number; // 触发扩容的负载因子阈值 + #extendRatio: number; // 扩容倍数 + #buckets: Pair[]; // 桶数组 + #removed: Pair; // 删除标记 + + /* 构造方法 */ + 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: number): number { + return key % this.#capacity; + } + + /* 负载因子 */ + #loadFactor(): number { + return this.#size / this.#capacity; + } + + /* 查询操作 */ + get(key: number): string | null { + 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 + ) + return this.#buckets[j].val; + } + return null; + } + + /* 添加操作 */ + put(key: number, val: string): void { + // 当负载因子超过阈值时,执行扩容 + 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) { + this.#buckets[j].val = val; + return; + } + } + } + + /* 删除操作 */ + remove(key: number): void { + 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) { + this.#buckets[j] = this.#removed; + this.#size -= 1; + return; + } + } + } + + /* 扩容哈希表 */ + #extend(): void { + // 暂存原哈希表 + const bucketsTmp = this.#buckets; + // 初始化扩容后的新哈希表 + this.#capacity *= this.#extendRatio; + this.#buckets = new Array(this.#capacity).fill(null); + this.#size = 0; + // 将键值对从原哈希表搬运至新哈希表 + for (let pair of bucketsTmp) { + if (pair !== null && pair.key !== this.#removed.key) { + this.put(pair.key, pair.val); + } + } + } + + /* 打印哈希表 */ + print() { + for (let pair of this.#buckets) { + 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(); + +export {}; diff --git a/codes/typescript/chapter_hashing/simple_hash.ts b/codes/typescript/chapter_hashing/simple_hash.ts new file mode 100644 index 0000000000..3a70560b44 --- /dev/null +++ b/codes/typescript/chapter_hashing/simple_hash.ts @@ -0,0 +1,60 @@ +/** + * File: simple_hash.ts + * Created Time: 2023-08-06 + * Author: yuan0221 (yl1452491917@gmail.com) + */ + +/* 加法哈希 */ +function addHash(key: string): number { + let hash = 0; + const MODULUS = 1000000007; + for (let c of key) { + hash = (hash + c.charCodeAt(0)) % MODULUS; + } + return hash; +} + +/* 乘法哈希 */ +function mulHash(key: string): number { + let hash = 0; + const MODULUS = 1000000007; + for (let c of key) { + hash = (31 * hash + c.charCodeAt(0)) % MODULUS; + } + return hash; +} + +/* 异或哈希 */ +function xorHash(key: string): number { + let hash = 0; + const MODULUS = 1000000007; + for (let c of key) { + hash ^= c.charCodeAt(0); + } + return hash & MODULUS; +} + +/* 旋转哈希 */ +function rotHash(key: string): number { + let hash = 0; + const MODULUS = 1000000007; + for (let c of key) { + 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); From 9357dadd4ef25646a6345a27d42649e64e297bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Tue, 8 Aug 2023 00:03:03 +0800 Subject: [PATCH 3/5] refactor(chapter_hashing): Optimize the remove function logic --- .../chapter_hashing/hash_map_chaining.js | 22 +++++++++---------- .../javascript/chapter_hashing/simple_hash.js | 8 +++---- .../chapter_hashing/hash_map_chaining.ts | 22 +++++++++---------- .../hash_map_open_addressing.ts | 2 +- .../typescript/chapter_hashing/simple_hash.ts | 8 +++---- 5 files changed, 29 insertions(+), 33 deletions(-) diff --git a/codes/javascript/chapter_hashing/hash_map_chaining.js b/codes/javascript/chapter_hashing/hash_map_chaining.js index 2ee61706eb..7d4bd79c91 100644 --- a/codes/javascript/chapter_hashing/hash_map_chaining.js +++ b/codes/javascript/chapter_hashing/hash_map_chaining.js @@ -44,7 +44,7 @@ class HashMapChaining { const index = this.#hashFunc(key); const bucket = this.#buckets[index]; // 遍历桶,若找到 key 则返回对应 val - for (let pair of bucket) { + for (const pair of bucket) { if (pair.key === key) { return pair.val; } @@ -62,7 +62,7 @@ class HashMapChaining { const index = this.#hashFunc(key); const bucket = this.#buckets[index]; // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 - for (let pair of bucket) { + for (const pair of bucket) { if (pair.key === key) { pair.val = val; return; @@ -79,12 +79,10 @@ class HashMapChaining { 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--; + for (let i = 0; i < bucket.length; i++) { + if (bucket[i].key === key) { + bucket.splice(i, 1); + this.size--; break; } } @@ -99,8 +97,8 @@ class HashMapChaining { this.#buckets = new Array(this.#capacity).fill(null).map((x) => []); this.#size = 0; // 将键值对从原哈希表搬运至新哈希表 - for (let bucket of bucketsTmp) { - for (let pair of bucket) { + for (const bucket of bucketsTmp) { + for (const pair of bucket) { this.put(pair.key, pair.val); } } @@ -108,9 +106,9 @@ class HashMapChaining { /* 打印哈希表 */ print() { - for (let bucket of this.#buckets) { + for (const bucket of this.#buckets) { let res = []; - for (let pair of bucket) { + for (const pair of bucket) { res.push(pair.key + ' -> ' + pair.val); } console.log(res); diff --git a/codes/javascript/chapter_hashing/simple_hash.js b/codes/javascript/chapter_hashing/simple_hash.js index 7971feef93..5c2a654093 100644 --- a/codes/javascript/chapter_hashing/simple_hash.js +++ b/codes/javascript/chapter_hashing/simple_hash.js @@ -8,7 +8,7 @@ function addHash(key) { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash = (hash + c.charCodeAt(0)) % MODULUS; } return hash; @@ -18,7 +18,7 @@ function addHash(key) { function mulHash(key) { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash = (31 * hash + c.charCodeAt(0)) % MODULUS; } return hash; @@ -28,7 +28,7 @@ function mulHash(key) { function xorHash(key) { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash ^= c.charCodeAt(0); } return hash & MODULUS; @@ -38,7 +38,7 @@ function xorHash(key) { function rotHash(key) { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash = ((hash << 4) ^ (hash >> 28) ^ c.charCodeAt(0)) % MODULUS; } return hash; diff --git a/codes/typescript/chapter_hashing/hash_map_chaining.ts b/codes/typescript/chapter_hashing/hash_map_chaining.ts index 14e4cc982b..3da27403e3 100644 --- a/codes/typescript/chapter_hashing/hash_map_chaining.ts +++ b/codes/typescript/chapter_hashing/hash_map_chaining.ts @@ -46,7 +46,7 @@ class HashMapChaining { const index = this.#hashFunc(key); const bucket = this.#buckets[index]; // 遍历桶,若找到 key 则返回对应 val - for (let pair of bucket) { + for (const pair of bucket) { if (pair.key === key) { return pair.val; } @@ -64,7 +64,7 @@ class HashMapChaining { const index = this.#hashFunc(key); const bucket = this.#buckets[index]; // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 - for (let pair of bucket) { + for (const pair of bucket) { if (pair.key === key) { pair.val = val; return; @@ -81,11 +81,9 @@ class HashMapChaining { 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 - ); + for (let i = 0; i < bucket.length; i++) { + if (bucket[i].key === key) { + bucket.splice(i, 1); this.#size--; break; } @@ -101,18 +99,18 @@ class HashMapChaining { this.#buckets = new Array(this.#capacity).fill(null).map((x) => []); this.#size = 0; // 将键值对从原哈希表搬运至新哈希表 - for (let bucket of bucketsTmp) { - for (let pair of bucket) { + for (const bucket of bucketsTmp) { + for (const pair of bucket) { this.put(pair.key, pair.val); } } } /* 打印哈希表 */ - print() { - for (let bucket of this.#buckets) { + print(): void { + for (const bucket of this.#buckets) { let res = []; - for (let pair of bucket) { + for (const pair of bucket) { res.push(pair.key + ' -> ' + pair.val); } console.log(res); diff --git a/codes/typescript/chapter_hashing/hash_map_open_addressing.ts b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts index 4d8786265d..cd44435701 100644 --- a/codes/typescript/chapter_hashing/hash_map_open_addressing.ts +++ b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts @@ -127,7 +127,7 @@ class HashMapOpenAddressing { } /* 打印哈希表 */ - print() { + print(): void { for (let pair of this.#buckets) { if (pair !== null) { console.log(pair.key + ' -> ' + pair.val); diff --git a/codes/typescript/chapter_hashing/simple_hash.ts b/codes/typescript/chapter_hashing/simple_hash.ts index 3a70560b44..9d2be67c18 100644 --- a/codes/typescript/chapter_hashing/simple_hash.ts +++ b/codes/typescript/chapter_hashing/simple_hash.ts @@ -8,7 +8,7 @@ function addHash(key: string): number { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash = (hash + c.charCodeAt(0)) % MODULUS; } return hash; @@ -18,7 +18,7 @@ function addHash(key: string): number { function mulHash(key: string): number { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash = (31 * hash + c.charCodeAt(0)) % MODULUS; } return hash; @@ -28,7 +28,7 @@ function mulHash(key: string): number { function xorHash(key: string): number { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash ^= c.charCodeAt(0); } return hash & MODULUS; @@ -38,7 +38,7 @@ function xorHash(key: string): number { function rotHash(key: string): number { let hash = 0; const MODULUS = 1000000007; - for (let c of key) { + for (const c of key) { hash = ((hash << 4) ^ (hash >> 28) ^ c.charCodeAt(0)) % MODULUS; } return hash; From e8d237a2e1e1a92691371af29b97790410fb9586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Tue, 8 Aug 2023 00:16:26 +0800 Subject: [PATCH 4/5] refactor(chapter_hashing): Remove unnecessary chaining operator --- .../chapter_hashing/hash_map_open_addressing.js | 8 ++++---- .../chapter_hashing/hash_map_open_addressing.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/codes/javascript/chapter_hashing/hash_map_open_addressing.js b/codes/javascript/chapter_hashing/hash_map_open_addressing.js index 402c42d0ea..23cee90be3 100644 --- a/codes/javascript/chapter_hashing/hash_map_open_addressing.js +++ b/codes/javascript/chapter_hashing/hash_map_open_addressing.js @@ -52,8 +52,8 @@ class HashMapOpenAddressing { if (this.#buckets[j] === null) return null; // 若遇到指定 key ,则返回对应 val if ( - this.#buckets[j]?.key === key && - this.#buckets[j]?.[key] !== this.#removed.key + this.#buckets[j].key === key && + this.#buckets[j][key] !== this.#removed.key ) return this.#buckets[j].val; } @@ -81,7 +81,7 @@ class HashMapOpenAddressing { return; } // 若遇到指定 key ,则更新对应 val - if (this.#buckets[j]?.key === key) { + if (this.#buckets[j].key === key) { this.#buckets[j].val = val; return; } @@ -100,7 +100,7 @@ class HashMapOpenAddressing { return; } // 若遇到指定 key ,则标记删除并返回 - if (this.#buckets[j]?.key === key) { + if (this.#buckets[j].key === key) { this.#buckets[j] = this.#removed; this.#size -= 1; return; diff --git a/codes/typescript/chapter_hashing/hash_map_open_addressing.ts b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts index cd44435701..194ee490c0 100644 --- a/codes/typescript/chapter_hashing/hash_map_open_addressing.ts +++ b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts @@ -54,8 +54,8 @@ class HashMapOpenAddressing { if (this.#buckets[j] === null) return null; // 若遇到指定 key ,则返回对应 val if ( - this.#buckets[j]?.key === key && - this.#buckets[j]?.[key] !== this.#removed.key + this.#buckets[j].key === key && + this.#buckets[j][key] !== this.#removed.key ) return this.#buckets[j].val; } @@ -83,7 +83,7 @@ class HashMapOpenAddressing { return; } // 若遇到指定 key ,则更新对应 val - if (this.#buckets[j]?.key === key) { + if (this.#buckets[j].key === key) { this.#buckets[j].val = val; return; } @@ -102,7 +102,7 @@ class HashMapOpenAddressing { return; } // 若遇到指定 key ,则标记删除并返回 - if (this.#buckets[j]?.key === key) { + if (this.#buckets[j].key === key) { this.#buckets[j] = this.#removed; this.#size -= 1; return; From 675841d00cd06c21c86cb77d80062ce406620493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Tue, 8 Aug 2023 10:05:33 +0800 Subject: [PATCH 5/5] refactor(chapter_hashing): use const instead of let --- codes/javascript/chapter_hashing/hash_map_open_addressing.js | 4 ++-- codes/typescript/chapter_hashing/hash_map_open_addressing.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codes/javascript/chapter_hashing/hash_map_open_addressing.js b/codes/javascript/chapter_hashing/hash_map_open_addressing.js index 23cee90be3..9d03a84d5a 100644 --- a/codes/javascript/chapter_hashing/hash_map_open_addressing.js +++ b/codes/javascript/chapter_hashing/hash_map_open_addressing.js @@ -117,7 +117,7 @@ class HashMapOpenAddressing { this.#buckets = new Array(this.#capacity).fill(null); this.#size = 0; // 将键值对从原哈希表搬运至新哈希表 - for (let pair of bucketsTmp) { + for (const pair of bucketsTmp) { if (pair !== null && pair.key !== this.#removed.key) { this.put(pair.key, pair.val); } @@ -126,7 +126,7 @@ class HashMapOpenAddressing { /* 打印哈希表 */ print() { - for (let pair of this.#buckets) { + for (const pair of this.#buckets) { if (pair !== null) { console.log(pair.key + ' -> ' + pair.val); } else { diff --git a/codes/typescript/chapter_hashing/hash_map_open_addressing.ts b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts index 194ee490c0..adca37ce1b 100644 --- a/codes/typescript/chapter_hashing/hash_map_open_addressing.ts +++ b/codes/typescript/chapter_hashing/hash_map_open_addressing.ts @@ -119,7 +119,7 @@ class HashMapOpenAddressing { this.#buckets = new Array(this.#capacity).fill(null); this.#size = 0; // 将键值对从原哈希表搬运至新哈希表 - for (let pair of bucketsTmp) { + for (const pair of bucketsTmp) { if (pair !== null && pair.key !== this.#removed.key) { this.put(pair.key, pair.val); } @@ -128,7 +128,7 @@ class HashMapOpenAddressing { /* 打印哈希表 */ print(): void { - for (let pair of this.#buckets) { + for (const pair of this.#buckets) { if (pair !== null) { console.log(pair.key + ' -> ' + pair.val); } else {