From 54dc288e61be9aa641b55ea0a2efa763b37b7d05 Mon Sep 17 00:00:00 2001 From: krahets Date: Mon, 26 Jun 2023 23:06:15 +0800 Subject: [PATCH] 1. Remove Pair class from hash coliision code. 2. Fix the comment in my_list code. 3. Add a Q&A to the summary of sorting. --- .../chapter_array_and_linkedlist/my_list.cpp | 2 +- codes/cpp/chapter_backtracking/CMakeLists.txt | 3 ++ .../chapter_graph/graph_adjacency_list.cpp | 2 +- codes/cpp/chapter_hashing/CMakeLists.txt | 6 ++- codes/cpp/chapter_hashing/array_hash_map.cpp | 45 +--------------- .../chapter_hashing/array_hash_map_test.cpp | 52 +++++++++++++++++++ .../cpp/chapter_hashing/hash_map_chaining.cpp | 13 +---- .../hash_map_open_addressing.cpp | 11 +--- .../chapter_array_and_linkedlist/my_list.go | 2 +- .../chapter_hashing/hash_map_chaining.java | 11 ---- .../hash_map_open_addressing.java | 11 ---- .../chapter_array_and_linkedlist/my_list.py | 2 +- .../chapter_hashing/hash_map_chaining.py | 8 ++- .../hash_map_open_addressing.py | 9 ++-- .../chapter_array_and_linkedlist/my_list.zig | 2 +- docs/chapter_hashing/hash_collision.md | 44 ---------------- docs/chapter_searching/binary_search_edge.md | 6 +-- docs/chapter_sorting/summary.md | 4 ++ 18 files changed, 81 insertions(+), 152 deletions(-) create mode 100644 codes/cpp/chapter_hashing/array_hash_map_test.cpp diff --git a/codes/cpp/chapter_array_and_linkedlist/my_list.cpp b/codes/cpp/chapter_array_and_linkedlist/my_list.cpp index a35920aa3..16d2f6d44 100644 --- a/codes/cpp/chapter_array_and_linkedlist/my_list.cpp +++ b/codes/cpp/chapter_array_and_linkedlist/my_list.cpp @@ -67,7 +67,7 @@ class MyList { // 元素数量超出容量时,触发扩容机制 if (size() == capacity()) extendCapacity(); - // 索引 i 以及之后的元素都向后移动一位 + // 将索引 index 以及之后的元素都向后移动一位 for (int j = size() - 1; j >= index; j--) { nums[j + 1] = nums[j]; } diff --git a/codes/cpp/chapter_backtracking/CMakeLists.txt b/codes/cpp/chapter_backtracking/CMakeLists.txt index 93565fe3d..6c271e330 100644 --- a/codes/cpp/chapter_backtracking/CMakeLists.txt +++ b/codes/cpp/chapter_backtracking/CMakeLists.txt @@ -5,3 +5,6 @@ add_executable(preorder_traversal_iii_template preorder_traversal_iii_template.c add_executable(permutations_i permutations_i.cpp) add_executable(permutations_ii permutations_ii.cpp) add_executable(n_queens n_queens.cpp) +add_executable(subset_sum_i_naive subset_sum_i_naive.cpp) +add_executable(subset_sum_i subset_sum_i.cpp) +add_executable(subset_sum_ii subset_sum_ii.cpp) diff --git a/codes/cpp/chapter_graph/graph_adjacency_list.cpp b/codes/cpp/chapter_graph/graph_adjacency_list.cpp index 0fad9ac7d..4fe4c4572 100644 --- a/codes/cpp/chapter_graph/graph_adjacency_list.cpp +++ b/codes/cpp/chapter_graph/graph_adjacency_list.cpp @@ -87,4 +87,4 @@ class GraphAdjList { } }; -// GraphAdjList 的测试样例在 graph_adjacency_list_test.cpp 文件中 +// 测试样例请见 graph_adjacency_list_test.cpp diff --git a/codes/cpp/chapter_hashing/CMakeLists.txt b/codes/cpp/chapter_hashing/CMakeLists.txt index f5be6e507..6b4bf536a 100644 --- a/codes/cpp/chapter_hashing/CMakeLists.txt +++ b/codes/cpp/chapter_hashing/CMakeLists.txt @@ -1,2 +1,6 @@ -add_executable(array_hash_map array_hash_map.cpp) add_executable(hash_map hash_map.cpp) +add_executable(array_hash_map_test array_hash_map_test.cpp) +add_executable(hash_map_chaining hash_map_chaining.cpp) +add_executable(hash_map_open_addressing hash_map_open_addressing.cpp) +add_executable(simple_hash simple_hash.cpp) +add_executable(built_in_hash built_in_hash.cpp) diff --git a/codes/cpp/chapter_hashing/array_hash_map.cpp b/codes/cpp/chapter_hashing/array_hash_map.cpp index ca8fa6f40..30489b67d 100644 --- a/codes/cpp/chapter_hashing/array_hash_map.cpp +++ b/codes/cpp/chapter_hashing/array_hash_map.cpp @@ -107,47 +107,4 @@ class ArrayHashMap { } }; -/* Driver Code */ -int main() { - /* 初始化哈希表 */ - ArrayHashMap map = ArrayHashMap(); - - /* 添加操作 */ - // 在哈希表中添加键值对 (key, value) - map.put(12836, "小哈"); - map.put(15937, "小啰"); - map.put(16750, "小算"); - map.put(13276, "小法"); - map.put(10583, "小鸭"); - cout << "\n添加完成后,哈希表为\nKey -> Value" << endl; - map.print(); - - /* 查询操作 */ - // 向哈希表输入键 key ,得到值 value - string name = map.get(15937); - cout << "\n输入学号 15937 ,查询到姓名 " << name << endl; - - /* 删除操作 */ - // 在哈希表中删除键值对 (key, value) - map.remove(10583); - cout << "\n删除 10583 后,哈希表为\nKey -> Value" << endl; - map.print(); - - /* 遍历哈希表 */ - cout << "\n遍历键值对 Key->Value" << endl; - for (auto kv : map.pairSet()) { - cout << kv->key << " -> " << kv->val << endl; - } - - cout << "\n单独遍历键 Key" << endl; - for (auto key : map.keySet()) { - cout << key << endl; - } - - cout << "\n单独遍历值 Value" << endl; - for (auto val : map.valueSet()) { - cout << val << endl; - } - - return 0; -} +// 测试样例请见 array_hash_map_test.cpp diff --git a/codes/cpp/chapter_hashing/array_hash_map_test.cpp b/codes/cpp/chapter_hashing/array_hash_map_test.cpp new file mode 100644 index 000000000..87afdca99 --- /dev/null +++ b/codes/cpp/chapter_hashing/array_hash_map_test.cpp @@ -0,0 +1,52 @@ +/** + * File: array_hash_map_test.cpp + * Created Time: 2022-12-14 + * Author: msk397 (machangxinq@gmail.com) + */ + +#include "./array_hash_map.cpp" + +/* Driver Code */ +int main() { + /* 初始化哈希表 */ + ArrayHashMap map = ArrayHashMap(); + + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.put(12836, "小哈"); + map.put(15937, "小啰"); + map.put(16750, "小算"); + map.put(13276, "小法"); + map.put(10583, "小鸭"); + cout << "\n添加完成后,哈希表为\nKey -> Value" << endl; + map.print(); + + /* 查询操作 */ + // 向哈希表输入键 key ,得到值 value + string name = map.get(15937); + cout << "\n输入学号 15937 ,查询到姓名 " << name << endl; + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(10583); + cout << "\n删除 10583 后,哈希表为\nKey -> Value" << endl; + map.print(); + + /* 遍历哈希表 */ + cout << "\n遍历键值对 Key->Value" << endl; + for (auto kv : map.pairSet()) { + cout << kv->key << " -> " << kv->val << endl; + } + + cout << "\n单独遍历键 Key" << endl; + for (auto key : map.keySet()) { + cout << key << endl; + } + + cout << "\n单独遍历值 Value" << endl; + for (auto val : map.valueSet()) { + cout << val << endl; + } + + return 0; +} diff --git a/codes/cpp/chapter_hashing/hash_map_chaining.cpp b/codes/cpp/chapter_hashing/hash_map_chaining.cpp index 03ebe16b6..17ca744cc 100644 --- a/codes/cpp/chapter_hashing/hash_map_chaining.cpp +++ b/codes/cpp/chapter_hashing/hash_map_chaining.cpp @@ -4,18 +4,7 @@ * Author: Krahets (krahets@163.com) */ -#include "../utils/common.hpp" - -/* 键值对 */ -struct Pair { - public: - int key; - string val; - Pair(int key, string val) { - this->key = key; - this->val = val; - } -}; +#include "./array_hash_map.cpp" /* 链式地址哈希表 */ class HashMapChaining { diff --git a/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp b/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp index 437273114..eac382f32 100644 --- a/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp +++ b/codes/cpp/chapter_hashing/hash_map_open_addressing.cpp @@ -4,16 +4,7 @@ * Author: Krahets (krahets@163.com) */ -#include "../utils/common.hpp" - -/* 键值对 */ -struct Pair { - int key; - string val; - - Pair(int k, string v) : key(k), val(v) { - } -}; +#include "./array_hash_map.cpp" /* 开放寻址哈希表 */ class HashMapOpenAddressing { diff --git a/codes/go/chapter_array_and_linkedlist/my_list.go b/codes/go/chapter_array_and_linkedlist/my_list.go index b4fbadf6a..a8e02a6da 100644 --- a/codes/go/chapter_array_and_linkedlist/my_list.go +++ b/codes/go/chapter_array_and_linkedlist/my_list.go @@ -69,7 +69,7 @@ func (l *myList) insert(num, index int) { if l.numsSize == l.numsCapacity { l.extendCapacity() } - // 索引 i 以及之后的元素都向后移动一位 + // 将索引 index 以及之后的元素都向后移动一位 for j := l.numsSize - 1; j >= index; j-- { l.nums[j+1] = l.nums[j] } diff --git a/codes/java/chapter_hashing/hash_map_chaining.java b/codes/java/chapter_hashing/hash_map_chaining.java index ff87d1db3..d1e455fae 100644 --- a/codes/java/chapter_hashing/hash_map_chaining.java +++ b/codes/java/chapter_hashing/hash_map_chaining.java @@ -9,17 +9,6 @@ package chapter_hashing; import java.util.ArrayList; import java.util.List; -/* 键值对 */ -class Pair { - public int key; - public String val; - - public Pair(int key, String val) { - this.key = key; - this.val = val; - } -} - /* 链式地址哈希表 */ class HashMapChaining { int size; // 键值对数量 diff --git a/codes/java/chapter_hashing/hash_map_open_addressing.java b/codes/java/chapter_hashing/hash_map_open_addressing.java index d63eff6df..64475ce4a 100644 --- a/codes/java/chapter_hashing/hash_map_open_addressing.java +++ b/codes/java/chapter_hashing/hash_map_open_addressing.java @@ -6,17 +6,6 @@ package chapter_hashing; -/* 键值对 */ -class Pair { - public int key; - public String val; - - public Pair(int key, String val) { - this.key = key; - this.val = val; - } -} - /* 开放寻址哈希表 */ class HashMapOpenAddressing { private int size; // 键值对数量 diff --git a/codes/python/chapter_array_and_linkedlist/my_list.py b/codes/python/chapter_array_and_linkedlist/my_list.py index 9e8749340..44ee897c9 100644 --- a/codes/python/chapter_array_and_linkedlist/my_list.py +++ b/codes/python/chapter_array_and_linkedlist/my_list.py @@ -51,7 +51,7 @@ class MyList: # 元素数量超出容量时,触发扩容机制 if self.__size == self.capacity(): self.extend_capacity() - # 索引 i 以及之后的元素都向后移动一位 + # 将索引 index 以及之后的元素都向后移动一位 for j in range(self.__size - 1, index - 1, -1): self.__nums[j + 1] = self.__nums[j] self.__nums[index] = num diff --git a/codes/python/chapter_hashing/hash_map_chaining.py b/codes/python/chapter_hashing/hash_map_chaining.py index dfe1ccaef..1667ad0d0 100644 --- a/codes/python/chapter_hashing/hash_map_chaining.py +++ b/codes/python/chapter_hashing/hash_map_chaining.py @@ -4,12 +4,10 @@ Created Time: 2023-06-13 Author: Krahets (krahets@163.com) """ -class Pair: - """键值对""" +import sys, os.path as osp - def __init__(self, key: int, val: str): - self.key = key - self.val = val +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) +from chapter_hashing.array_hash_map import Pair class HashMapChaining: diff --git a/codes/python/chapter_hashing/hash_map_open_addressing.py b/codes/python/chapter_hashing/hash_map_open_addressing.py index 64a2a233f..940eab622 100644 --- a/codes/python/chapter_hashing/hash_map_open_addressing.py +++ b/codes/python/chapter_hashing/hash_map_open_addressing.py @@ -4,13 +4,10 @@ Created Time: 2023-06-13 Author: Krahets (krahets@163.com) """ +import sys, os.path as osp -class Pair: - """键值对""" - - def __init__(self, key: int, val: str): - self.key = key - self.val = val +sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) +from chapter_hashing.array_hash_map import Pair class HashMapOpenAddressing: diff --git a/codes/zig/chapter_array_and_linkedlist/my_list.zig b/codes/zig/chapter_array_and_linkedlist/my_list.zig index 69b808de7..41388a25c 100644 --- a/codes/zig/chapter_array_and_linkedlist/my_list.zig +++ b/codes/zig/chapter_array_and_linkedlist/my_list.zig @@ -71,7 +71,7 @@ pub fn MyList(comptime T: type) type { if (index < 0 or index >= self.size()) @panic("索引越界"); // 元素数量超出容量时,触发扩容机制 if (self.size() == self.capacity()) try self.extendCapacity(); - // 索引 i 以及之后的元素都向后移动一位 + // 将索引 index 以及之后的元素都向后移动一位 var j = self.size() - 1; while (j >= index) : (j -= 1) { self.nums[j + 1] = self.nums[j]; diff --git a/docs/chapter_hashing/hash_collision.md b/docs/chapter_hashing/hash_collision.md index 9bee3c80d..3388628d8 100644 --- a/docs/chapter_hashing/hash_collision.md +++ b/docs/chapter_hashing/hash_collision.md @@ -34,88 +34,66 @@ === "Java" ```java title="hash_map_chaining.java" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "C++" ```cpp title="hash_map_chaining.cpp" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "Python" ```python title="hash_map_chaining.py" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "Go" ```go title="hash_map_chaining.go" - [class]{pair}-[func]{} - [class]{hashMapChaining}-[func]{} ``` === "JavaScript" ```javascript title="hash_map_chaining.js" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "TypeScript" ```typescript title="hash_map_chaining.ts" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "C" ```c title="hash_map_chaining.c" - [class]{pair}-[func]{} - [class]{hashMapChaining}-[func]{} ``` === "C#" ```csharp title="hash_map_chaining.cs" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "Swift" ```swift title="hash_map_chaining.swift" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "Zig" ```zig title="hash_map_chaining.zig" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` === "Dart" ```dart title="hash_map_chaining.dart" - [class]{Pair}-[func]{} - [class]{HashMapChaining}-[func]{} ``` @@ -150,88 +128,66 @@ === "Java" ```java title="hash_map_open_addressing.java" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "C++" ```cpp title="hash_map_open_addressing.cpp" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "Python" ```python title="hash_map_open_addressing.py" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "Go" ```go title="hash_map_open_addressing.go" - [class]{pair}-[func]{} - [class]{hashMapOpenAddressing}-[func]{} ``` === "JavaScript" ```javascript title="hash_map_open_addressing.js" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "TypeScript" ```typescript title="hash_map_open_addressing.ts" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "C" ```c title="hash_map_open_addressing.c" - [class]{pair}-[func]{} - [class]{hashMapOpenAddressing}-[func]{} ``` === "C#" ```csharp title="hash_map_open_addressing.cs" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "Swift" ```swift title="hash_map_open_addressing.swift" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "Zig" ```zig title="hash_map_open_addressing.zig" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` === "Dart" ```dart title="hash_map_open_addressing.dart" - [class]{Pair}-[func]{} - [class]{HashMapOpenAddressing}-[func]{} ``` diff --git a/docs/chapter_searching/binary_search_edge.md b/docs/chapter_searching/binary_search_edge.md index bc70f0873..a5bcbcf4d 100644 --- a/docs/chapter_searching/binary_search_edge.md +++ b/docs/chapter_searching/binary_search_edge.md @@ -6,7 +6,7 @@ 给定一个长度为 $n$ 的有序数组 `nums` ,数组可能包含重复元素。请查找并返回元素 `target` 在数组中首次出现的索引。若数组中不包含该元素,则返回 $-1$ 。 -## 简单方法 +## 线性方法 为了查找数组中最左边的 `target` ,我们可以分为两步: @@ -15,11 +15,11 @@ ![线性查找最左边的元素](binary_search_edge.assets/binary_search_left_edge_naive.png) -这个方法虽然有效,但由于包含线性查找,**其时间复杂度可能会劣化至 $O(n)$** 。 +这个方法虽然有效,但由于包含线性查找,时间复杂度为 $O(n)$ ,当存在很多重复的 `target` 时效率较低。 ## 二分方法 -实际上,我们可以仅通过二分查找解决以上问题。整体算法流程不变,先计算中点索引 $m$ ,再判断 `target` 和 `nums[m]` 大小关系: +考虑仅使用二分查找解决该问题。整体算法流程不变,先计算中点索引 $m$ ,再判断 `target` 和 `nums[m]` 大小关系: - 当 `nums[m] < target` 或 `nums[m] > target` 时,说明还没有找到 `target` ,因此采取与上节代码相同的缩小区间操作,**从而使指针 $i$ 和 $j$ 向 `target` 靠近**。 - 当 `nums[m] == target` 时,说明“小于 `target` 的元素”在区间 $[i, m - 1]$ 中,因此采用 $j = m - 1$ 来缩小区间,**从而使指针 $j$ 向小于 `target` 的元素靠近**。 diff --git a/docs/chapter_sorting/summary.md b/docs/chapter_sorting/summary.md index e91ef431a..492d4366d 100644 --- a/docs/chapter_sorting/summary.md +++ b/docs/chapter_sorting/summary.md @@ -38,6 +38,10 @@ 回顾原始的快速排序,我们有可能会连续地递归长度较大的数组,最差情况下为 $n, n - 1, n - 2, ..., 2, 1$ ,从而递归深度为 $n$ 。尾递归优化可以避免这种情况的出现。 +!!! question "当数组中所有元素都相等时,快速排序的时间复杂度是 $O(n^2)$ 吗?该如何处理这种退化情况?" + + 是的。这种情况可以考虑通过哨兵划分将数组划分为三个部分:小于、等于、大于基准数。仅向下递归小于和大于的两部分。在该方法下,输入元素全部相等的数组,仅一轮哨兵划分即可完成排序。 + !!! question "桶排序的最差时间复杂度为什么是 $O(n^2)$ ?" 最差情况下,所有元素被分至同一个桶中。如果我们采用一个 $O(n^2)$ 算法来排序这些元素,则时间复杂度为 $O(n^2)$ 。