From e3366363b63a20dffacbc9d5f14af92b74ebc540 Mon Sep 17 00:00:00 2001 From: liuyuxin Date: Tue, 26 Sep 2023 11:04:13 +0800 Subject: [PATCH] feat(dart): add forLoopRecur and update HashMapOpenAddressing (#802) * feat(dart): add forLoopRecur * feat(dart): update HashMapOpenAddressing --- .../recursion.dart | 22 ++++ .../chapter_hashing/hash_map_chaining.dart | 7 +- .../hash_map_open_addressing.dart | 118 +++++++++--------- 3 files changed, 82 insertions(+), 65 deletions(-) diff --git a/codes/dart/chapter_computational_complexity/recursion.dart b/codes/dart/chapter_computational_complexity/recursion.dart index de33e72bb..e1689c511 100644 --- a/codes/dart/chapter_computational_complexity/recursion.dart +++ b/codes/dart/chapter_computational_complexity/recursion.dart @@ -14,6 +14,25 @@ int recur(int n) { return n + res; } +/* 使用迭代模拟递归 */ +int forLoopRecur(int n) { + // 使用一个显式的栈来模拟系统调用栈 + List stack = []; + int res = 0; + // 递:递归调用 + for (int i = n; i > 0; i--) { + // 通过“入栈操作”模拟“递” + stack.add(i); + } + // 归:返回结果 + while (!stack.isEmpty) { + // 通过“出栈操作”模拟“归” + res += stack.removeLast(); + } + // res = 1+2+3+...+n + return res; +} + /* 尾递归 */ int tailRecur(int n, int res) { // 终止条件 @@ -43,6 +62,9 @@ void main() { res = tailRecur(n, 0); print("\n尾递归函数的求和结果 res = $res"); + res = forLoopRecur(n); + print("\n使用迭代模拟递归求和结果 res = $res"); + res = fib(n); print("\n斐波那契数列的第 $n 项为 $res"); } diff --git a/codes/dart/chapter_hashing/hash_map_chaining.dart b/codes/dart/chapter_hashing/hash_map_chaining.dart index fcf3ab0d2..77221e3d3 100644 --- a/codes/dart/chapter_hashing/hash_map_chaining.dart +++ b/codes/dart/chapter_hashing/hash_map_chaining.dart @@ -4,12 +4,7 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 键值对 */ -class Pair { - int key; - String val; - Pair(this.key, this.val); -} +import 'array_hash_map.dart'; /* 链式地址哈希表 */ class HashMapChaining { diff --git a/codes/dart/chapter_hashing/hash_map_open_addressing.dart b/codes/dart/chapter_hashing/hash_map_open_addressing.dart index eb3cbbb1d..3dc831fea 100644 --- a/codes/dart/chapter_hashing/hash_map_open_addressing.dart +++ b/codes/dart/chapter_hashing/hash_map_open_addressing.dart @@ -4,30 +4,21 @@ * Author: liuyuxin (gvenusleo@gmail.com) */ -/* 键值对 */ -class Pair { - int key; - String val; - Pair(this.key, this.val); -} +import 'array_hash_map.dart'; /* 开放寻址哈希表 */ class HashMapOpenAddressing { late int _size; // 键值对数量 - late int _capacity; // 哈希表容量 - late double _loadThres; // 触发扩容的负载因子阈值 - late int _extendRatio; // 扩容倍数 + int _capacity = 4; // 哈希表容量 + double _loadThres = 2.0 / 3.0; // 触发扩容的负载因子阈值 + int _extendRatio = 2; // 扩容倍数 late List _buckets; // 桶数组 - late Pair _removed; // 删除标记 + Pair _TOMBSTONE = Pair(-1, "-1"); // 删除标记 /* 构造方法 */ HashMapOpenAddressing() { _size = 0; - _capacity = 4; - _loadThres = 2.0 / 3.0; - _extendRatio = 2; _buckets = List.generate(_capacity, (index) => null); - _removed = Pair(-1, "-1"); } /* 哈希函数 */ @@ -40,19 +31,42 @@ class HashMapOpenAddressing { return _size / _capacity; } - /* 查询操作 */ - String? get(int key) { + /* 搜索 key 对应的桶索引 */ + int findBucket(int key) { int index = hashFunc(key); - // 线性探测,从 index 开始向后遍历 - for (int i = 0; i < _capacity; i++) { + int firstTombstone = -1; + // 线性探测,当遇到空桶时跳出 + while (_buckets[index] != null) { + // 若遇到 key ,返回对应桶索引 + if (_buckets[index]!.key == key) { + // 若之前遇到了删除标记,则将键值对移动至该索引 + if (firstTombstone != -1) { + _buckets[firstTombstone] = _buckets[index]; + _buckets[index] = _TOMBSTONE; + return firstTombstone; // 返回移动后的桶索引 + } + return index; // 返回桶索引 + } + // 记录遇到的首个删除标记 + if (firstTombstone == -1 && _buckets[index] == _TOMBSTONE) { + firstTombstone = index; + } // 计算桶索引,越过尾部返回头部 - int j = (index + i) % _capacity; - // 若遇到空桶,说明无此 key ,则返回 null - if (_buckets[j] == null) return null; - // 若遇到指定 key ,则返回对应 val - if (_buckets[j]!.key == key && _buckets[j] != _removed) - return _buckets[j]!.val; + index = (index + 1) % _capacity; + } + // 若 key 不存在,则返回添加点的索引 + return firstTombstone == -1 ? index : firstTombstone; + } + + /* 查询操作 */ + String? get(int key) { + // 搜索 key 对应的桶索引 + int index = findBucket(key); + // 若找到键值对,则返回对应 val + if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) { + return _buckets[index]!.val; } + // 若键值对不存在,则返回 null return null; } @@ -62,42 +76,26 @@ class HashMapOpenAddressing { if (loadFactor() > _loadThres) { extend(); } - int index = hashFunc(key); - // 线性探测,从 index 开始向后遍历 - for (int i = 0; i < _capacity; i++) { - // 计算桶索引,越过尾部返回头部 - int j = (index + i) % _capacity; - // 若遇到空桶、或带有删除标记的桶,则将键值对放入该桶 - if (_buckets[j] == null || _buckets[j] == _removed) { - _buckets[j] = new Pair(key, val); - _size += 1; - return; - } - // 若遇到指定 key ,则更新对应 val - if (_buckets[j]!.key == key) { - _buckets[j]!.val = val; - return; - } + // 搜索 key 对应的桶索引 + int index = findBucket(key); + // 若找到键值对,则覆盖 val 并返回 + if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) { + _buckets[index]!.val = val; + return; } + // 若键值对不存在,则添加该键值对 + _buckets[index] = new Pair(key, val); + _size++; } /* 删除操作 */ void remove(int key) { - int index = hashFunc(key); - // 线性探测,从 index 开始向后遍历 - for (int i = 0; i < _capacity; i++) { - // 计算桶索引,越过尾部返回头部 - int j = (index + i) % _capacity; - // 若遇到空桶,说明无此 key ,则直接返回 - if (_buckets[j] == null) { - return; - } - // 若遇到指定 key ,则标记删除并返回 - if (_buckets[j]!.key == key) { - _buckets[j] = _removed; - _size -= 1; - return; - } + // 搜索 key 对应的桶索引 + int index = findBucket(key); + // 若找到键值对,则用删除标记覆盖它 + if (_buckets[index] != null && _buckets[index] != _TOMBSTONE) { + _buckets[index] = _TOMBSTONE; + _size--; } } @@ -111,7 +109,7 @@ class HashMapOpenAddressing { _size = 0; // 将键值对从原哈希表搬运至新哈希表 for (Pair? pair in bucketsTmp) { - if (pair != null && pair != _removed) { + if (pair != null && pair != _TOMBSTONE) { put(pair.key, pair.val); } } @@ -120,10 +118,12 @@ class HashMapOpenAddressing { /* 打印哈希表 */ void printHashMap() { for (Pair? pair in _buckets) { - if (pair != null) { - print("${pair.key} -> ${pair.val}"); + if (pair == null) { + print("null"); + } else if (pair == _TOMBSTONE) { + print("TOMBSTONE"); } else { - print(null); + print("${pair.key} -> ${pair.val}"); } } }