This commit is contained in:
krahets 2023-03-15 03:12:57 +08:00
parent 000a583f92
commit 683e7ee872
7 changed files with 138 additions and 130 deletions

View file

@ -1562,9 +1562,9 @@ comments: true
const Self = @This(); const Self = @This();
nums: []T = undefined, // 数组(存储列表元素) nums: []T = undefined, // 数组(存储列表元素)
numsCapacity: usize = 10, // 列表容量 nums_capacity: usize = 10, // 列表容量
numSize: usize = 0, // 列表长度(即当前元素数量) num_size: usize = 0, // 列表长度(即当前元素数量)
extendRatio: usize = 2, // 每次列表扩容的倍数 extend_ratio: usize = 2, // 每次列表扩容的倍数
mem_arena: ?std.heap.ArenaAllocator = null, mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器 mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@ -1574,7 +1574,7 @@ comments: true
self.mem_arena = std.heap.ArenaAllocator.init(allocator); self.mem_arena = std.heap.ArenaAllocator.init(allocator);
self.mem_allocator = self.mem_arena.?.allocator(); self.mem_allocator = self.mem_arena.?.allocator();
} }
self.nums = try self.mem_allocator.alloc(T, self.numsCapacity); self.nums = try self.mem_allocator.alloc(T, self.nums_capacity);
std.mem.set(T, self.nums, @as(T, 0)); std.mem.set(T, self.nums, @as(T, 0));
} }
@ -1586,12 +1586,12 @@ comments: true
// 获取列表长度(即当前元素数量) // 获取列表长度(即当前元素数量)
pub fn size(self: *Self) usize { pub fn size(self: *Self) usize {
return self.numSize; return self.num_size;
} }
// 获取列表容量 // 获取列表容量
pub fn capacity(self: *Self) usize { pub fn capacity(self: *Self) usize {
return self.numsCapacity; return self.nums_capacity;
} }
// 访问元素 // 访问元素
@ -1614,7 +1614,7 @@ comments: true
if (self.size() == self.capacity()) try self.extendCapacity(); if (self.size() == self.capacity()) try self.extendCapacity();
self.nums[self.size()] = num; self.nums[self.size()] = num;
// 更新元素数量 // 更新元素数量
self.numSize += 1; self.num_size += 1;
} }
// 中间插入元素 // 中间插入元素
@ -1629,7 +1629,7 @@ comments: true
} }
self.nums[index] = num; self.nums[index] = num;
// 更新元素数量 // 更新元素数量
self.numSize += 1; self.num_size += 1;
} }
// 删除元素 // 删除元素
@ -1642,22 +1642,22 @@ comments: true
self.nums[j] = self.nums[j + 1]; self.nums[j] = self.nums[j + 1];
} }
// 更新元素数量 // 更新元素数量
self.numSize -= 1; self.num_size -= 1;
// 返回被删除元素 // 返回被删除元素
return num; return num;
} }
// 列表扩容 // 列表扩容
pub fn extendCapacity(self: *Self) !void { pub fn extendCapacity(self: *Self) !void {
// 新建一个长度为 size * extendRatio 的数组,并将原数组拷贝到新数组 // 新建一个长度为 size * extend_ratio 的数组,并将原数组拷贝到新数组
var newCapacity = self.capacity() * self.extendRatio; var newCapacity = self.capacity() * self.extend_ratio;
var extend = try self.mem_allocator.alloc(T, newCapacity); var extend = try self.mem_allocator.alloc(T, newCapacity);
std.mem.set(T, extend, @as(T, 0)); std.mem.set(T, extend, @as(T, 0));
// 将原数组中的所有元素复制到新数组 // 将原数组中的所有元素复制到新数组
std.mem.copy(T, extend, self.nums); std.mem.copy(T, extend, self.nums);
self.nums = extend; self.nums = extend;
// 更新列表容量 // 更新列表容量
self.numsCapacity = newCapacity; self.nums_capacity = newCapacity;
} }
// 将列表转换为数组 // 将列表转换为数组

View file

@ -952,7 +952,9 @@ comments: true
/* 打印邻接表 */ /* 打印邻接表 */
void print() { void print() {
cout << "邻接表 =" << endl; cout << "邻接表 =" << endl;
for (auto& [key, vec] : adjList) { for (auto& adj : adjList) {
const auto& key= adj.first;
const auto& vec = adj.second;
cout << key->val << ": "; cout << key->val << ": ";
PrintUtil::printVector(vetsToVals(vec)); PrintUtil::printVector(vetsToVals(vec));
} }

View file

@ -6,15 +6,15 @@ comments: true
理想情况下,哈希函数应该为每个输入产生唯一的输出,使得 key 和 value 一一对应。而实际上,往往存在向哈希函数输入不同的 key 而产生相同输出的情况,这种情况被称为「哈希冲突 Hash Collision」。哈希冲突会导致查询结果错误从而严重影响哈希表的可用性。 理想情况下,哈希函数应该为每个输入产生唯一的输出,使得 key 和 value 一一对应。而实际上,往往存在向哈希函数输入不同的 key 而产生相同输出的情况,这种情况被称为「哈希冲突 Hash Collision」。哈希冲突会导致查询结果错误从而严重影响哈希表的可用性。
那么,为什么会出现哈希冲突呢?本质上看,**由于哈希函数的输入空间往往远大于输出空间**,因此不可避免地会出现多个输入产生相同输出的情况,即为哈希冲突。比如,输入空间是全体整数,输出空间是一个固定大小的桶(数组)的索引范围,那么必定会有多个整数同时映射到一个桶索引。 那么,为什么会出现哈希冲突呢?本质上看,**由于哈希函数的输入空间往往远大于输出空间**,因此不可避免地会出现多个输入产生相同输出的情况,即为哈希冲突。比如,输入空间是全体整数,输出空间是一个固定大小的数组,那么必定会有多个整数映射到同一个数组索引。
为了缓解哈希冲突,一方面,**我们可以通过哈希表扩容来减小冲突概率**。极端情况下,当输入空间和输出空间大小相等时,哈希表就等价于数组了,可谓“大力出奇迹”。 为了缓解哈希冲突,一方面,**我们可以通过哈希表扩容来减小冲突概率**。极端情况下,当输入空间和输出空间大小相等时,哈希表就等价于数组了,每个 key 都对应唯一的数组索引,可谓“大力出奇迹”。
另一方面,**考虑通过优化哈希表的表示方式以缓解哈希冲突**,常见的方法有「链式地址」和「开放寻址」。 另一方面,**考虑通过优化哈希表的缓解哈希冲突**,常见的方法有「链式地址」和「开放寻址」。
## 6.2.1. &nbsp; 哈希表扩容 ## 6.2.1. &nbsp; 哈希表扩容
「负载因子 Load Factor」定义为 **哈希表中元素数量除以桶数量(即数组大小)**,代表哈希冲突的严重程度。 「负载因子 Load Factor」定义为 **哈希表中元素数量除以桶数量(即数组大小)**,代表哈希冲突的严重程度。
**负载因子常用作哈希表扩容的触发条件**。比如在 Java 中,当负载因子 $> 0.75$ 时则触发扩容,将 HashMap 大小扩充至原先的 $2$ 倍。 **负载因子常用作哈希表扩容的触发条件**。比如在 Java 中,当负载因子 $> 0.75$ 时则触发扩容,将 HashMap 大小扩充至原先的 $2$ 倍。
@ -22,7 +22,7 @@ comments: true
## 6.2.2. &nbsp; 链式地址 ## 6.2.2. &nbsp; 链式地址
在原始哈希表中,桶内的每个地址只能存储一个元素(即键值对)。**考虑将单个元素转化成一个链表,将所有冲突元素都存储在一个链表中**。 在原始哈希表中,每个桶只能存储一个元素(即键值对)。**考虑将单个元素转化成一个链表,将所有冲突元素都存储在一个链表中**。
![链式地址](hash_collision.assets/hash_collision_chaining.png) ![链式地址](hash_collision.assets/hash_collision_chaining.png)
@ -30,7 +30,7 @@ comments: true
链式地址下,哈希表操作方法为: 链式地址下,哈希表操作方法为:
- **查询元素**先将 key 输入到哈希函数得到桶内索引,即可访问链表头结点,再通过遍历链表查找对应 value - **查询元素**输入 key ,经过哈希函数得到数组索引,即可访问链表头结点,再通过遍历链表并对比 key 来查找键值对
- **添加元素**:先通过哈希函数访问链表头部,再将结点(即键值对)添加到链表头部即可。 - **添加元素**:先通过哈希函数访问链表头部,再将结点(即键值对)添加到链表头部即可。
- **删除元素**:同样先根据哈希函数结果访问链表头部,再遍历链表查找对应结点,删除之即可。 - **删除元素**:同样先根据哈希函数结果访问链表头部,再遍历链表查找对应结点,删除之即可。
@ -62,8 +62,8 @@ comments: true
线性探测存在以下缺陷: 线性探测存在以下缺陷:
- **不能直接删除元素**。删除元素会导致内出现一个空位,在查找其他元素时,该空位有可能导致程序认为元素不存在(即上述第 `2.` 种情况)。因此需要借助一个标志位来标记删除元素。 - **不能直接删除元素**。删除元素会导致数组内出现一个空位,在查找其他元素时,该空位有可能导致程序认为元素不存在(即上述第 `2.` 种情况)。因此需要借助一个标志位来标记删除元素。
- **容易产生聚集**内被占用的连续位置越长,这些连续位置发生哈希冲突的可能性越大,从而进一步促进这一位置的“聚堆生长”,最终导致增删查改操作效率的劣化。 - **容易产生聚集**数组内被占用的连续位置越长,这些连续位置发生哈希冲突的可能性越大,从而进一步促进这一位置的“聚堆生长”,最终导致增删查改操作效率的劣化。
### 多次哈希 ### 多次哈希
@ -83,3 +83,5 @@ comments: true
Java 采用「链式地址」。在 JDK 1.8 之后HashMap 内数组长度大于 64 时,长度大于 8 的链表会被转化为「红黑树」,以提升查找性能。 Java 采用「链式地址」。在 JDK 1.8 之后HashMap 内数组长度大于 64 时,长度大于 8 的链表会被转化为「红黑树」,以提升查找性能。
Python 采用「开放寻址」。字典 dict 使用伪随机数进行探测。 Python 采用「开放寻址」。字典 dict 使用伪随机数进行探测。
Golang 采用「链式地址」。Go 规定每个桶最多存储 8 个键值对,超出容量则连接一个溢出桶;当溢出桶过多时,会执行一次特殊的等量扩容操作,以保证性能。

View file

@ -396,14 +396,16 @@ comments: true
## 6.1.3. &nbsp; 哈希函数 ## 6.1.3. &nbsp; 哈希函数
哈希表中存储元素的数据结构被称为「桶 Bucket」底层实现可能是数组、链表、二叉树红黑树或是它们的组合 哈希表的底层实现是数组,并且可能包含链表、二叉树(红黑树)等数据结构,以提升查询性能(下节会讨论)
最简单地,**我们可以仅用一个「数组」来实现哈希表**。首先,将所有 value 放入数组中,那么每个 value 在数组中都有唯一的「索引」。显然,访问 value 需要给定索引,而为了 **建立 key 和索引之间的映射关系**,我们需要使用「哈希函数 Hash Function」 首先考虑最简单的情况,**即仅用一个「数组」来实现哈希表**。根据习惯,我们将数组中的每个空位称为「桶 Bucket」用于存储键值对
设数组为 `bucket` ,哈希函数为 `f(x)` ,输入键为 `key` 。那么获取 value 的步骤为: 我们将键值对 key, value 包装成一个类 `Entry` ,并将所有 `Entry` 都放入数组中,那么每个 `Entry` 在数组中都有唯一的索引。显然,访问 `Entry` 需要给定索引,而为了 **建立 key 和索引之间的映射关系**,我们需要使用「哈希函数 Hash Function」。
具体地,设数组为 `buckets` ,哈希函数为 `f(x)` ,输入键为 `key` 。那么获取 value 的步骤为:
1. 通过哈希函数计算出索引,即 `index = f(key)` 1. 通过哈希函数计算出索引,即 `index = f(key)`
2. 通过索引在数组中获取值,即 `value = bucket[index]` 2. 通过索引在数组中获取键值对,即 `Entry = buckets[index]`
以上述学生数据 `key 学号 -> value 姓名` 为例,我们可以将「哈希函数」设计为 以上述学生数据 `key 学号 -> value 姓名` 为例,我们可以将「哈希函数」设计为
@ -411,6 +413,8 @@ $$
f(x) = x \% 100 f(x) = x \% 100
$$ $$
如下图所示,输入一个学号 key ,经过哈希函数计算就能访问到对应的姓名 value 。
![简单哈希函数示例](hash_map.assets/hash_function.png) ![简单哈希函数示例](hash_map.assets/hash_function.png)
<p align="center"> Fig. 简单哈希函数示例 </p> <p align="center"> Fig. 简单哈希函数示例 </p>
@ -430,12 +434,12 @@ $$
/* 基于数组简易实现的哈希表 */ /* 基于数组简易实现的哈希表 */
class ArrayHashMap { class ArrayHashMap {
private List<Entry> bucket; private List<Entry> buckets;
public ArrayHashMap() { public ArrayHashMap() {
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
bucket = new ArrayList<>(); buckets = new ArrayList<>();
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
bucket.add(null); buckets.add(null);
} }
} }
@ -448,7 +452,7 @@ $$
/* 查询操作 */ /* 查询操作 */
public String get(int key) { public String get(int key) {
int index = hashFunc(key); int index = hashFunc(key);
Entry pair = bucket.get(index); Entry pair = buckets.get(index);
if (pair == null) return null; if (pair == null) return null;
return pair.val; return pair.val;
} }
@ -457,20 +461,20 @@ $$
public void put(int key, String val) { public void put(int key, String val) {
Entry pair = new Entry(key, val); Entry pair = new Entry(key, val);
int index = hashFunc(key); int index = hashFunc(key);
bucket.set(index, pair); buckets.set(index, pair);
} }
/* 删除操作 */ /* 删除操作 */
public void remove(int key) { public void remove(int key) {
int index = hashFunc(key); int index = hashFunc(key);
// 置为 null ,代表删除 // 置为 null ,代表删除
bucket.set(index, null); buckets.set(index, null);
} }
/* 获取所有键值对 */ /* 获取所有键值对 */
public List<Entry> entrySet() { public List<Entry> entrySet() {
List<Entry> entrySet = new ArrayList<>(); List<Entry> entrySet = new ArrayList<>();
for (Entry pair : bucket) { for (Entry pair : buckets) {
if (pair != null) if (pair != null)
entrySet.add(pair); entrySet.add(pair);
} }
@ -480,7 +484,7 @@ $$
/* 获取所有键 */ /* 获取所有键 */
public List<Integer> keySet() { public List<Integer> keySet() {
List<Integer> keySet = new ArrayList<>(); List<Integer> keySet = new ArrayList<>();
for (Entry pair : bucket) { for (Entry pair : buckets) {
if (pair != null) if (pair != null)
keySet.add(pair.key); keySet.add(pair.key);
} }
@ -490,7 +494,7 @@ $$
/* 获取所有值 */ /* 获取所有值 */
public List<String> valueSet() { public List<String> valueSet() {
List<String> valueSet = new ArrayList<>(); List<String> valueSet = new ArrayList<>();
for (Entry pair : bucket) { for (Entry pair : buckets) {
if (pair != null) if (pair != null)
valueSet.add(pair.val); valueSet.add(pair.val);
} }
@ -523,11 +527,11 @@ $$
/* 基于数组简易实现的哈希表 */ /* 基于数组简易实现的哈希表 */
class ArrayHashMap { class ArrayHashMap {
private: private:
vector<Entry*> bucket; vector<Entry*> buckets;
public: public:
ArrayHashMap() { ArrayHashMap() {
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
bucket= vector<Entry*>(100); buckets= vector<Entry*>(100);
} }
/* 哈希函数 */ /* 哈希函数 */
@ -539,7 +543,7 @@ $$
/* 查询操作 */ /* 查询操作 */
string get(int key) { string get(int key) {
int index = hashFunc(key); int index = hashFunc(key);
Entry* pair = bucket[index]; Entry* pair = buckets[index];
if (pair == nullptr) if (pair == nullptr)
return nullptr; return nullptr;
return pair->val; return pair->val;
@ -549,20 +553,20 @@ $$
void put(int key, string val) { void put(int key, string val) {
Entry* pair = new Entry(key, val); Entry* pair = new Entry(key, val);
int index = hashFunc(key); int index = hashFunc(key);
bucket[index] = pair; buckets[index] = pair;
} }
/* 删除操作 */ /* 删除操作 */
void remove(int key) { void remove(int key) {
int index = hashFunc(key); int index = hashFunc(key);
// 置为 nullptr ,代表删除 // 置为 nullptr ,代表删除
bucket[index] = nullptr; buckets[index] = nullptr;
} }
/* 获取所有键值对 */ /* 获取所有键值对 */
vector<Entry*> entrySet() { vector<Entry*> entrySet() {
vector<Entry*> entrySet; vector<Entry*> entrySet;
for (Entry* pair: bucket) { for (Entry* pair: buckets) {
if (pair != nullptr) { if (pair != nullptr) {
entrySet.push_back(pair); entrySet.push_back(pair);
} }
@ -573,7 +577,7 @@ $$
/* 获取所有键 */ /* 获取所有键 */
vector<int> keySet() { vector<int> keySet() {
vector<int> keySet; vector<int> keySet;
for (Entry* pair: bucket) { for (Entry* pair: buckets) {
if (pair != nullptr) { if (pair != nullptr) {
keySet.push_back(pair->key); keySet.push_back(pair->key);
} }
@ -584,7 +588,7 @@ $$
/* 获取所有值 */ /* 获取所有值 */
vector<string> valueSet() { vector<string> valueSet() {
vector<string> valueSet; vector<string> valueSet;
for (Entry* pair: bucket) { for (Entry* pair: buckets) {
if (pair != nullptr){ if (pair != nullptr){
valueSet.push_back(pair->val); valueSet.push_back(pair->val);
} }
@ -615,7 +619,7 @@ $$
def __init__(self): def __init__(self):
""" 构造方法 """ """ 构造方法 """
# 初始化一个长度为 100 的桶(数组) # 初始化一个长度为 100 的桶(数组)
self.bucket: List[Optional[Entry]] = [None] * 100 self.buckets: List[Optional[Entry]] = [None] * 100
def hash_func(self, key: int) -> int: def hash_func(self, key: int) -> int:
""" 哈希函数 """ """ 哈希函数 """
@ -625,7 +629,7 @@ $$
def get(self, key: int) -> str: def get(self, key: int) -> str:
""" 查询操作 """ """ 查询操作 """
index: int = self.hash_func(key) index: int = self.hash_func(key)
pair: Entry = self.bucket[index] pair: Entry = self.buckets[index]
if pair is None: if pair is None:
return None return None
return pair.val return pair.val
@ -634,18 +638,18 @@ $$
""" 添加操作 """ """ 添加操作 """
pair = Entry(key, val) pair = Entry(key, val)
index: int = self.hash_func(key) index: int = self.hash_func(key)
self.bucket[index] = pair self.buckets[index] = pair
def remove(self, key: int) -> None: def remove(self, key: int) -> None:
""" 删除操作 """ """ 删除操作 """
index: int = self.hash_func(key) index: int = self.hash_func(key)
# 置为 None ,代表删除 # 置为 None ,代表删除
self.bucket[index] = None self.buckets[index] = None
def entry_set(self) -> List[Entry]: def entry_set(self) -> List[Entry]:
""" 获取所有键值对 """ """ 获取所有键值对 """
result: List[Entry] = [] result: List[Entry] = []
for pair in self.bucket: for pair in self.buckets:
if pair is not None: if pair is not None:
result.append(pair) result.append(pair)
return result return result
@ -653,7 +657,7 @@ $$
def key_set(self) -> List[int]: def key_set(self) -> List[int]:
""" 获取所有键 """ """ 获取所有键 """
result: List[int] = [] result: List[int] = []
for pair in self.bucket: for pair in self.buckets:
if pair is not None: if pair is not None:
result.append(pair.key) result.append(pair.key)
return result return result
@ -661,14 +665,14 @@ $$
def value_set(self) -> List[str]: def value_set(self) -> List[str]:
""" 获取所有值 """ """ 获取所有值 """
result: List[str] = [] result: List[str] = []
for pair in self.bucket: for pair in self.buckets:
if pair is not None: if pair is not None:
result.append(pair.val) result.append(pair.val)
return result return result
def print(self) -> None: def print(self) -> None:
""" 打印哈希表 """ """ 打印哈希表 """
for pair in self.bucket: for pair in self.buckets:
if pair is not None: if pair is not None:
print(pair.key, "->", pair.val) print(pair.key, "->", pair.val)
``` ```
@ -684,14 +688,14 @@ $$
/* 基于数组简易实现的哈希表 */ /* 基于数组简易实现的哈希表 */
type arrayHashMap struct { type arrayHashMap struct {
bucket []*entry buckets []*entry
} }
/* 初始化哈希表 */ /* 初始化哈希表 */
func newArrayHashMap() *arrayHashMap { func newArrayHashMap() *arrayHashMap {
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
bucket := make([]*entry, 100) buckets := make([]*entry, 100)
return &arrayHashMap{bucket: bucket} return &arrayHashMap{buckets: buckets}
} }
/* 哈希函数 */ /* 哈希函数 */
@ -703,7 +707,7 @@ $$
/* 查询操作 */ /* 查询操作 */
func (a *arrayHashMap) get(key int) string { func (a *arrayHashMap) get(key int) string {
index := a.hashFunc(key) index := a.hashFunc(key)
pair := a.bucket[index] pair := a.buckets[index]
if pair == nil { if pair == nil {
return "Not Found" return "Not Found"
} }
@ -714,20 +718,20 @@ $$
func (a *arrayHashMap) put(key int, val string) { func (a *arrayHashMap) put(key int, val string) {
pair := &entry{key: key, val: val} pair := &entry{key: key, val: val}
index := a.hashFunc(key) index := a.hashFunc(key)
a.bucket[index] = pair a.buckets[index] = pair
} }
/* 删除操作 */ /* 删除操作 */
func (a *arrayHashMap) remove(key int) { func (a *arrayHashMap) remove(key int) {
index := a.hashFunc(key) index := a.hashFunc(key)
// 置为 nil ,代表删除 // 置为 nil ,代表删除
a.bucket[index] = nil a.buckets[index] = nil
} }
/* 获取所有键对 */ /* 获取所有键对 */
func (a *arrayHashMap) entrySet() []*entry { func (a *arrayHashMap) entrySet() []*entry {
var pairs []*entry var pairs []*entry
for _, pair := range a.bucket { for _, pair := range a.buckets {
if pair != nil { if pair != nil {
pairs = append(pairs, pair) pairs = append(pairs, pair)
} }
@ -738,7 +742,7 @@ $$
/* 获取所有键 */ /* 获取所有键 */
func (a *arrayHashMap) keySet() []int { func (a *arrayHashMap) keySet() []int {
var keys []int var keys []int
for _, pair := range a.bucket { for _, pair := range a.buckets {
if pair != nil { if pair != nil {
keys = append(keys, pair.key) keys = append(keys, pair.key)
} }
@ -749,7 +753,7 @@ $$
/* 获取所有值 */ /* 获取所有值 */
func (a *arrayHashMap) valueSet() []string { func (a *arrayHashMap) valueSet() []string {
var values []string var values []string
for _, pair := range a.bucket { for _, pair := range a.buckets {
if pair != nil { if pair != nil {
values = append(values, pair.val) values = append(values, pair.val)
} }
@ -759,7 +763,7 @@ $$
/* 打印哈希表 */ /* 打印哈希表 */
func (a *arrayHashMap) print() { func (a *arrayHashMap) print() {
for _, pair := range a.bucket { for _, pair := range a.buckets {
if pair != nil { if pair != nil {
fmt.Println(pair.key, "->", pair.val) fmt.Println(pair.key, "->", pair.val)
} }
@ -780,10 +784,10 @@ $$
/* 基于数组简易实现的哈希表 */ /* 基于数组简易实现的哈希表 */
class ArrayHashMap { class ArrayHashMap {
#bucket; #buckets;
constructor() { constructor() {
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
this.#bucket = new Array(100).fill(null); this.#buckets = new Array(100).fill(null);
} }
/* 哈希函数 */ /* 哈希函数 */
@ -794,7 +798,7 @@ $$
/* 查询操作 */ /* 查询操作 */
get(key) { get(key) {
let index = this.#hashFunc(key); let index = this.#hashFunc(key);
let entry = this.#bucket[index]; let entry = this.#buckets[index];
if (entry === null) return null; if (entry === null) return null;
return entry.val; return entry.val;
} }
@ -802,22 +806,22 @@ $$
/* 添加操作 */ /* 添加操作 */
set(key, val) { set(key, val) {
let index = this.#hashFunc(key); let index = this.#hashFunc(key);
this.#bucket[index] = new Entry(key, val); this.#buckets[index] = new Entry(key, val);
} }
/* 删除操作 */ /* 删除操作 */
delete(key) { delete(key) {
let index = this.#hashFunc(key); let index = this.#hashFunc(key);
// 置为 null ,代表删除 // 置为 null ,代表删除
this.#bucket[index] = null; this.#buckets[index] = null;
} }
/* 获取所有键值对 */ /* 获取所有键值对 */
entries() { entries() {
let arr = []; let arr = [];
for (let i = 0; i < this.#bucket.length; i++) { for (let i = 0; i < this.#buckets.length; i++) {
if (this.#bucket[i]) { if (this.#buckets[i]) {
arr.push(this.#bucket[i]); arr.push(this.#buckets[i]);
} }
} }
return arr; return arr;
@ -826,9 +830,9 @@ $$
/* 获取所有键 */ /* 获取所有键 */
keys() { keys() {
let arr = []; let arr = [];
for (let i = 0; i < this.#bucket.length; i++) { for (let i = 0; i < this.#buckets.length; i++) {
if (this.#bucket[i]) { if (this.#buckets[i]) {
arr.push(this.#bucket[i]?.key); arr.push(this.#buckets[i]?.key);
} }
} }
return arr; return arr;
@ -837,9 +841,9 @@ $$
/* 获取所有值 */ /* 获取所有值 */
values() { values() {
let arr = []; let arr = [];
for (let i = 0; i < this.#bucket.length; i++) { for (let i = 0; i < this.#buckets.length; i++) {
if (this.#bucket[i]) { if (this.#buckets[i]) {
arr.push(this.#bucket[i]?.val); arr.push(this.#buckets[i]?.val);
} }
} }
return arr; return arr;
@ -873,11 +877,11 @@ $$
/* 基于数组简易实现的哈希表 */ /* 基于数组简易实现的哈希表 */
class ArrayHashMap { class ArrayHashMap {
private readonly bucket: (Entry | null)[]; private readonly buckets: (Entry | null)[];
constructor() { constructor() {
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
this.bucket = (new Array(100)).fill(null); this.buckets = (new Array(100)).fill(null);
} }
/* 哈希函数 */ /* 哈希函数 */
@ -888,7 +892,7 @@ $$
/* 查询操作 */ /* 查询操作 */
public get(key: number): string | null { public get(key: number): string | null {
let index = this.hashFunc(key); let index = this.hashFunc(key);
let entry = this.bucket[index]; let entry = this.buckets[index];
if (entry === null) return null; if (entry === null) return null;
return entry.val; return entry.val;
} }
@ -896,22 +900,22 @@ $$
/* 添加操作 */ /* 添加操作 */
public set(key: number, val: string) { public set(key: number, val: string) {
let index = this.hashFunc(key); let index = this.hashFunc(key);
this.bucket[index] = new Entry(key, val); this.buckets[index] = new Entry(key, val);
} }
/* 删除操作 */ /* 删除操作 */
public delete(key: number) { public delete(key: number) {
let index = this.hashFunc(key); let index = this.hashFunc(key);
// 置为 null ,代表删除 // 置为 null ,代表删除
this.bucket[index] = null; this.buckets[index] = null;
} }
/* 获取所有键值对 */ /* 获取所有键值对 */
public entries(): (Entry | null)[] { public entries(): (Entry | null)[] {
let arr: (Entry | null)[] = []; let arr: (Entry | null)[] = [];
for (let i = 0; i < this.bucket.length; i++) { for (let i = 0; i < this.buckets.length; i++) {
if (this.bucket[i]) { if (this.buckets[i]) {
arr.push(this.bucket[i]); arr.push(this.buckets[i]);
} }
} }
return arr; return arr;
@ -920,9 +924,9 @@ $$
/* 获取所有键 */ /* 获取所有键 */
public keys(): (number | undefined)[] { public keys(): (number | undefined)[] {
let arr: (number | undefined)[] = []; let arr: (number | undefined)[] = [];
for (let i = 0; i < this.bucket.length; i++) { for (let i = 0; i < this.buckets.length; i++) {
if (this.bucket[i]) { if (this.buckets[i]) {
arr.push(this.bucket[i]?.key); arr.push(this.buckets[i]?.key);
} }
} }
return arr; return arr;
@ -931,9 +935,9 @@ $$
/* 获取所有值 */ /* 获取所有值 */
public values(): (string | undefined)[] { public values(): (string | undefined)[] {
let arr: (string | undefined)[] = []; let arr: (string | undefined)[] = [];
for (let i = 0; i < this.bucket.length; i++) { for (let i = 0; i < this.buckets.length; i++) {
if (this.bucket[i]) { if (this.buckets[i]) {
arr.push(this.bucket[i]?.val); arr.push(this.buckets[i]?.val);
} }
} }
return arr; return arr;
@ -976,14 +980,14 @@ $$
/* 基于数组简易实现的哈希表 */ /* 基于数组简易实现的哈希表 */
class ArrayHashMap class ArrayHashMap
{ {
private List<Entry?> bucket; private List<Entry?> buckets;
public ArrayHashMap() public ArrayHashMap()
{ {
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
bucket = new(); buckets = new();
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
{ {
bucket.Add(null); buckets.Add(null);
} }
} }
@ -998,7 +1002,7 @@ $$
public String? get(int key) public String? get(int key)
{ {
int index = hashFunc(key); int index = hashFunc(key);
Entry? pair = bucket[index]; Entry? pair = buckets[index];
if (pair == null) return null; if (pair == null) return null;
return pair.val; return pair.val;
} }
@ -1008,7 +1012,7 @@ $$
{ {
Entry pair = new Entry(key, val); Entry pair = new Entry(key, val);
int index = hashFunc(key); int index = hashFunc(key);
bucket[index] = pair; buckets[index] = pair;
} }
/* 删除操作 */ /* 删除操作 */
@ -1016,14 +1020,14 @@ $$
{ {
int index = hashFunc(key); int index = hashFunc(key);
// 置为 null ,代表删除 // 置为 null ,代表删除
bucket[index] = null; buckets[index] = null;
} }
/* 获取所有键值对 */ /* 获取所有键值对 */
public List<Entry> entrySet() public List<Entry> entrySet()
{ {
List<Entry> entrySet = new(); List<Entry> entrySet = new();
foreach (Entry? pair in bucket) foreach (Entry? pair in buckets)
{ {
if (pair != null) if (pair != null)
entrySet.Add(pair); entrySet.Add(pair);
@ -1035,7 +1039,7 @@ $$
public List<int> keySet() public List<int> keySet()
{ {
List<int> keySet = new(); List<int> keySet = new();
foreach (Entry? pair in bucket) foreach (Entry? pair in buckets)
{ {
if (pair != null) if (pair != null)
keySet.Add(pair.key); keySet.Add(pair.key);
@ -1047,7 +1051,7 @@ $$
public List<String> valueSet() public List<String> valueSet()
{ {
List<String> valueSet = new(); List<String> valueSet = new();
foreach (Entry? pair in bucket) foreach (Entry? pair in buckets)
{ {
if (pair != null) if (pair != null)
valueSet.Add(pair.val); valueSet.Add(pair.val);
@ -1082,12 +1086,12 @@ $$
/* 基于数组简易实现的哈希表 */ /* 基于数组简易实现的哈希表 */
class ArrayHashMap { class ArrayHashMap {
private var bucket: [Entry?] = [] private var buckets: [Entry?] = []
init() { init() {
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
for _ in 0 ..< 100 { for _ in 0 ..< 100 {
bucket.append(nil) buckets.append(nil)
} }
} }
@ -1100,7 +1104,7 @@ $$
/* 查询操作 */ /* 查询操作 */
func get(key: Int) -> String? { func get(key: Int) -> String? {
let index = hashFunc(key: key) let index = hashFunc(key: key)
let pair = bucket[index] let pair = buckets[index]
return pair?.val return pair?.val
} }
@ -1108,20 +1112,20 @@ $$
func put(key: Int, val: String) { func put(key: Int, val: String) {
let pair = Entry(key: key, val: val) let pair = Entry(key: key, val: val)
let index = hashFunc(key: key) let index = hashFunc(key: key)
bucket[index] = pair buckets[index] = pair
} }
/* 删除操作 */ /* 删除操作 */
func remove(key: Int) { func remove(key: Int) {
let index = hashFunc(key: key) let index = hashFunc(key: key)
// 置为 nil ,代表删除 // 置为 nil ,代表删除
bucket[index] = nil buckets[index] = nil
} }
/* 获取所有键值对 */ /* 获取所有键值对 */
func entrySet() -> [Entry] { func entrySet() -> [Entry] {
var entrySet: [Entry] = [] var entrySet: [Entry] = []
for pair in bucket { for pair in buckets {
if let pair = pair { if let pair = pair {
entrySet.append(pair) entrySet.append(pair)
} }
@ -1132,7 +1136,7 @@ $$
/* 获取所有键 */ /* 获取所有键 */
func keySet() -> [Int] { func keySet() -> [Int] {
var keySet: [Int] = [] var keySet: [Int] = []
for pair in bucket { for pair in buckets {
if let pair = pair { if let pair = pair {
keySet.append(pair.key) keySet.append(pair.key)
} }
@ -1143,7 +1147,7 @@ $$
/* 获取所有值 */ /* 获取所有值 */
func valueSet() -> [String] { func valueSet() -> [String] {
var valueSet: [String] = [] var valueSet: [String] = []
for pair in bucket { for pair in buckets {
if let pair = pair { if let pair = pair {
valueSet.append(pair.val) valueSet.append(pair.val)
} }
@ -1179,7 +1183,7 @@ $$
// 基于数组简易实现的哈希表 // 基于数组简易实现的哈希表
fn ArrayHashMap(comptime T: type) type { fn ArrayHashMap(comptime T: type) type {
return struct { return struct {
bucket: ?std.ArrayList(?T) = null, buckets: ?std.ArrayList(?T) = null,
mem_allocator: std.mem.Allocator = undefined, mem_allocator: std.mem.Allocator = undefined,
const Self = @This(); const Self = @This();
@ -1188,16 +1192,16 @@ $$
pub fn init(self: *Self, allocator: std.mem.Allocator) !void { pub fn init(self: *Self, allocator: std.mem.Allocator) !void {
self.mem_allocator = allocator; self.mem_allocator = allocator;
// 初始化一个长度为 100 的桶(数组) // 初始化一个长度为 100 的桶(数组)
self.bucket = std.ArrayList(?T).init(self.mem_allocator); self.buckets = std.ArrayList(?T).init(self.mem_allocator);
var i: i32 = 0; var i: i32 = 0;
while (i < 100) : (i += 1) { while (i < 100) : (i += 1) {
try self.bucket.?.append(null); try self.buckets.?.append(null);
} }
} }
// 析构方法 // 析构方法
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
if (self.bucket != null) self.bucket.?.deinit(); if (self.buckets != null) self.buckets.?.deinit();
} }
// 哈希函数 // 哈希函数
@ -1209,7 +1213,7 @@ $$
// 查询操作 // 查询操作
pub fn get(self: *Self, key: usize) []const u8 { pub fn get(self: *Self, key: usize) []const u8 {
var index = hashFunc(key); var index = hashFunc(key);
var pair = self.bucket.?.items[index]; var pair = self.buckets.?.items[index];
return pair.?.val; return pair.?.val;
} }
@ -1217,20 +1221,20 @@ $$
pub fn put(self: *Self, key: usize, val: []const u8) !void { pub fn put(self: *Self, key: usize, val: []const u8) !void {
var pair = Entry.init(key, val); var pair = Entry.init(key, val);
var index = hashFunc(key); var index = hashFunc(key);
self.bucket.?.items[index] = pair; self.buckets.?.items[index] = pair;
} }
// 删除操作 // 删除操作
pub fn remove(self: *Self, key: usize) !void { pub fn remove(self: *Self, key: usize) !void {
var index = hashFunc(key); var index = hashFunc(key);
// 置为 null ,代表删除 // 置为 null ,代表删除
self.bucket.?.items[index] = null; self.buckets.?.items[index] = null;
} }
// 获取所有键值对 // 获取所有键值对
pub fn entrySet(self: *Self) !*std.ArrayList(T) { pub fn entrySet(self: *Self) !*std.ArrayList(T) {
var entry_set = std.ArrayList(T).init(self.mem_allocator); var entry_set = std.ArrayList(T).init(self.mem_allocator);
for (self.bucket.?.items) |item| { for (self.buckets.?.items) |item| {
if (item == null) continue; if (item == null) continue;
try entry_set.append(item.?); try entry_set.append(item.?);
} }
@ -1240,7 +1244,7 @@ $$
// 获取所有键 // 获取所有键
pub fn keySet(self: *Self) !*std.ArrayList(usize) { pub fn keySet(self: *Self) !*std.ArrayList(usize) {
var key_set = std.ArrayList(usize).init(self.mem_allocator); var key_set = std.ArrayList(usize).init(self.mem_allocator);
for (self.bucket.?.items) |item| { for (self.buckets.?.items) |item| {
if (item == null) continue; if (item == null) continue;
try key_set.append(item.?.key); try key_set.append(item.?.key);
} }
@ -1250,7 +1254,7 @@ $$
// 获取所有值 // 获取所有值
pub fn valueSet(self: *Self) !*std.ArrayList([]const u8) { pub fn valueSet(self: *Self) !*std.ArrayList([]const u8) {
var value_set = std.ArrayList([]const u8).init(self.mem_allocator); var value_set = std.ArrayList([]const u8).init(self.mem_allocator);
for (self.bucket.?.items) |item| { for (self.buckets.?.items) |item| {
if (item == null) continue; if (item == null) continue;
try value_set.append(item.?.val); try value_set.append(item.?.val);
} }

View file

@ -141,10 +141,10 @@ comments: true
```zig title="my_heap.zig" ```zig title="my_heap.zig"
// 构造方法,根据输入列表建堆 // 构造方法,根据输入列表建堆
fn init(self: *Self, allocator: std.mem.Allocator, nums: []const T) !void { fn init(self: *Self, allocator: std.mem.Allocator, nums: []const T) !void {
if (self.maxHeap != null) return; if (self.max_heap != null) return;
self.maxHeap = std.ArrayList(T).init(allocator); self.max_heap = std.ArrayList(T).init(allocator);
// 将列表元素原封不动添加进堆 // 将列表元素原封不动添加进堆
try self.maxHeap.?.appendSlice(nums); try self.max_heap.?.appendSlice(nums);
// 堆化除叶结点以外的其他所有结点 // 堆化除叶结点以外的其他所有结点
var i: usize = parent(self.size() - 1) + 1; var i: usize = parent(self.size() - 1) + 1;
while (i > 0) : (i -= 1) { while (i > 0) : (i -= 1) {

View file

@ -594,7 +594,7 @@ comments: true
```zig title="my_heap.zig" ```zig title="my_heap.zig"
// 访问堆顶元素 // 访问堆顶元素
fn peek(self: *Self) T { fn peek(self: *Self) T {
return self.maxHeap.?.items[0]; return self.max_heap.?.items[0];
} }
``` ```
@ -855,7 +855,7 @@ comments: true
// 元素入堆 // 元素入堆
fn push(self: *Self, val: T) !void { fn push(self: *Self, val: T) !void {
// 添加结点 // 添加结点
try self.maxHeap.?.append(val); try self.max_heap.?.append(val);
// 从底至顶堆化 // 从底至顶堆化
try self.siftUp(self.size() - 1); try self.siftUp(self.size() - 1);
} }
@ -867,7 +867,7 @@ comments: true
// 获取结点 i 的父结点 // 获取结点 i 的父结点
var p = parent(i); var p = parent(i);
// 当“越过根结点”或“结点无需修复”时,结束堆化 // 当“越过根结点”或“结点无需修复”时,结束堆化
if (p < 0 or self.maxHeap.?.items[i] <= self.maxHeap.?.items[p]) break; if (p < 0 or self.max_heap.?.items[i] <= self.max_heap.?.items[p]) break;
// 交换两结点 // 交换两结点
try self.swap(i, p); try self.swap(i, p);
// 循环向上堆化 // 循环向上堆化
@ -1247,7 +1247,7 @@ comments: true
// 交换根结点与最右叶结点(即交换首元素与尾元素) // 交换根结点与最右叶结点(即交换首元素与尾元素)
try self.swap(0, self.size() - 1); try self.swap(0, self.size() - 1);
// 删除结点 // 删除结点
var val = self.maxHeap.?.pop(); var val = self.max_heap.?.pop();
// 从顶至底堆化 // 从顶至底堆化
try self.siftDown(0); try self.siftDown(0);
// 返回堆顶元素 // 返回堆顶元素
@ -1262,8 +1262,8 @@ comments: true
var l = left(i); var l = left(i);
var r = right(i); var r = right(i);
var ma = i; var ma = i;
if (l < self.size() and self.maxHeap.?.items[l] > self.maxHeap.?.items[ma]) ma = l; if (l < self.size() and self.max_heap.?.items[l] > self.max_heap.?.items[ma]) ma = l;
if (r < self.size() and self.maxHeap.?.items[r] > self.maxHeap.?.items[ma]) ma = r; if (r < self.size() and self.max_heap.?.items[r] > self.max_heap.?.items[ma]) ma = r;
// 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i) break; if (ma == i) break;
// 交换两结点 // 交换两结点

View file

@ -1541,7 +1541,7 @@ comments: true
nums: []T = undefined, // 用于存储队列元素的数组 nums: []T = undefined, // 用于存储队列元素的数组
cap: usize = 0, // 队列容量 cap: usize = 0, // 队列容量
front: usize = 0, // 队首指针,指向队首元素 front: usize = 0, // 队首指针,指向队首元素
queSize: usize = 0, // 尾指针,指向队尾 + 1 que_size: usize = 0, // 尾指针,指向队尾 + 1
mem_arena: ?std.heap.ArenaAllocator = null, mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器 mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@ -1569,12 +1569,12 @@ comments: true
// 获取队列的长度 // 获取队列的长度
pub fn size(self: *Self) usize { pub fn size(self: *Self) usize {
return self.queSize; return self.que_size;
} }
// 判断队列是否为空 // 判断队列是否为空
pub fn isEmpty(self: *Self) bool { pub fn isEmpty(self: *Self) bool {
return self.queSize == 0; return self.que_size == 0;
} }
// 入队 // 入队
@ -1585,10 +1585,10 @@ comments: true
} }
// 计算尾指针,指向队尾索引 + 1 // 计算尾指针,指向队尾索引 + 1
// 通过取余操作,实现 rear 越过数组尾部后回到头部 // 通过取余操作,实现 rear 越过数组尾部后回到头部
var rear = (self.front + self.queSize) % self.capacity(); var rear = (self.front + self.que_size) % self.capacity();
// 将 num 添加至队尾 // 将 num 添加至队尾
self.nums[rear] = num; self.nums[rear] = num;
self.queSize += 1; self.que_size += 1;
} }
// 出队 // 出队
@ -1596,7 +1596,7 @@ comments: true
var num = self.peek(); var num = self.peek();
// 队首指针向后移动一位,若越过尾部则返回到数组头部 // 队首指针向后移动一位,若越过尾部则返回到数组头部
self.front = (self.front + 1) % self.capacity(); self.front = (self.front + 1) % self.capacity();
self.queSize -= 1; self.que_size -= 1;
return num; return num;
} }