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.
This commit is contained in:
krahets 2023-06-26 23:06:15 +08:00
parent 7876e3e88c
commit 54dc288e61
18 changed files with 81 additions and 152 deletions

View File

@ -67,7 +67,7 @@ class MyList {
// 元素数量超出容量时,触发扩容机制 // 元素数量超出容量时,触发扩容机制
if (size() == capacity()) if (size() == capacity())
extendCapacity(); extendCapacity();
// 索引 i 以及之后的元素都向后移动一位 // 索引 index 以及之后的元素都向后移动一位
for (int j = size() - 1; j >= index; j--) { for (int j = size() - 1; j >= index; j--) {
nums[j + 1] = nums[j]; nums[j + 1] = nums[j];
} }

View File

@ -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_i permutations_i.cpp)
add_executable(permutations_ii permutations_ii.cpp) add_executable(permutations_ii permutations_ii.cpp)
add_executable(n_queens n_queens.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)

View File

@ -87,4 +87,4 @@ class GraphAdjList {
} }
}; };
// GraphAdjList 的测试样例在 graph_adjacency_list_test.cpp 文件中 // 测试样例请见 graph_adjacency_list_test.cpp

View File

@ -1,2 +1,6 @@
add_executable(array_hash_map array_hash_map.cpp)
add_executable(hash_map 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)

View File

@ -107,47 +107,4 @@ class ArrayHashMap {
} }
}; };
/* Driver Code */ // 测试样例请见 array_hash_map_test.cpp
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;
}

View File

@ -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;
}

View File

@ -4,18 +4,7 @@
* Author: Krahets (krahets@163.com) * Author: Krahets (krahets@163.com)
*/ */
#include "../utils/common.hpp" #include "./array_hash_map.cpp"
/* 键值对 */
struct Pair {
public:
int key;
string val;
Pair(int key, string val) {
this->key = key;
this->val = val;
}
};
/* 链式地址哈希表 */ /* 链式地址哈希表 */
class HashMapChaining { class HashMapChaining {

View File

@ -4,16 +4,7 @@
* Author: Krahets (krahets@163.com) * Author: Krahets (krahets@163.com)
*/ */
#include "../utils/common.hpp" #include "./array_hash_map.cpp"
/* 键值对 */
struct Pair {
int key;
string val;
Pair(int k, string v) : key(k), val(v) {
}
};
/* 开放寻址哈希表 */ /* 开放寻址哈希表 */
class HashMapOpenAddressing { class HashMapOpenAddressing {

View File

@ -69,7 +69,7 @@ func (l *myList) insert(num, index int) {
if l.numsSize == l.numsCapacity { if l.numsSize == l.numsCapacity {
l.extendCapacity() l.extendCapacity()
} }
// 索引 i 以及之后的元素都向后移动一位 // 索引 index 以及之后的元素都向后移动一位
for j := l.numsSize - 1; j >= index; j-- { for j := l.numsSize - 1; j >= index; j-- {
l.nums[j+1] = l.nums[j] l.nums[j+1] = l.nums[j]
} }

View File

@ -9,17 +9,6 @@ package chapter_hashing;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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 { class HashMapChaining {
int size; // 键值对数量 int size; // 键值对数量

View File

@ -6,17 +6,6 @@
package chapter_hashing; 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 { class HashMapOpenAddressing {
private int size; // 键值对数量 private int size; // 键值对数量

View File

@ -51,7 +51,7 @@ class MyList:
# 元素数量超出容量时,触发扩容机制 # 元素数量超出容量时,触发扩容机制
if self.__size == self.capacity(): if self.__size == self.capacity():
self.extend_capacity() self.extend_capacity()
# 索引 i 以及之后的元素都向后移动一位 # 索引 index 以及之后的元素都向后移动一位
for j in range(self.__size - 1, index - 1, -1): for j in range(self.__size - 1, index - 1, -1):
self.__nums[j + 1] = self.__nums[j] self.__nums[j + 1] = self.__nums[j]
self.__nums[index] = num self.__nums[index] = num

View File

@ -4,12 +4,10 @@ Created Time: 2023-06-13
Author: Krahets (krahets@163.com) Author: Krahets (krahets@163.com)
""" """
class Pair: import sys, os.path as osp
"""键值对"""
def __init__(self, key: int, val: str): sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
self.key = key from chapter_hashing.array_hash_map import Pair
self.val = val
class HashMapChaining: class HashMapChaining:

View File

@ -4,13 +4,10 @@ Created Time: 2023-06-13
Author: Krahets (krahets@163.com) Author: Krahets (krahets@163.com)
""" """
import sys, os.path as osp
class Pair: sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
"""键值对""" from chapter_hashing.array_hash_map import Pair
def __init__(self, key: int, val: str):
self.key = key
self.val = val
class HashMapOpenAddressing: class HashMapOpenAddressing:

View File

@ -71,7 +71,7 @@ pub fn MyList(comptime T: type) type {
if (index < 0 or index >= self.size()) @panic("索引越界"); if (index < 0 or index >= self.size()) @panic("索引越界");
// //
if (self.size() == self.capacity()) try self.extendCapacity(); if (self.size() == self.capacity()) try self.extendCapacity();
// i // index
var j = self.size() - 1; var j = self.size() - 1;
while (j >= index) : (j -= 1) { while (j >= index) : (j -= 1) {
self.nums[j + 1] = self.nums[j]; self.nums[j + 1] = self.nums[j];

View File

@ -34,88 +34,66 @@
=== "Java" === "Java"
```java title="hash_map_chaining.java" ```java title="hash_map_chaining.java"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "C++" === "C++"
```cpp title="hash_map_chaining.cpp" ```cpp title="hash_map_chaining.cpp"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "Python" === "Python"
```python title="hash_map_chaining.py" ```python title="hash_map_chaining.py"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "Go" === "Go"
```go title="hash_map_chaining.go" ```go title="hash_map_chaining.go"
[class]{pair}-[func]{}
[class]{hashMapChaining}-[func]{} [class]{hashMapChaining}-[func]{}
``` ```
=== "JavaScript" === "JavaScript"
```javascript title="hash_map_chaining.js" ```javascript title="hash_map_chaining.js"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "TypeScript" === "TypeScript"
```typescript title="hash_map_chaining.ts" ```typescript title="hash_map_chaining.ts"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "C" === "C"
```c title="hash_map_chaining.c" ```c title="hash_map_chaining.c"
[class]{pair}-[func]{}
[class]{hashMapChaining}-[func]{} [class]{hashMapChaining}-[func]{}
``` ```
=== "C#" === "C#"
```csharp title="hash_map_chaining.cs" ```csharp title="hash_map_chaining.cs"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "Swift" === "Swift"
```swift title="hash_map_chaining.swift" ```swift title="hash_map_chaining.swift"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "Zig" === "Zig"
```zig title="hash_map_chaining.zig" ```zig title="hash_map_chaining.zig"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
=== "Dart" === "Dart"
```dart title="hash_map_chaining.dart" ```dart title="hash_map_chaining.dart"
[class]{Pair}-[func]{}
[class]{HashMapChaining}-[func]{} [class]{HashMapChaining}-[func]{}
``` ```
@ -150,88 +128,66 @@
=== "Java" === "Java"
```java title="hash_map_open_addressing.java" ```java title="hash_map_open_addressing.java"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "C++" === "C++"
```cpp title="hash_map_open_addressing.cpp" ```cpp title="hash_map_open_addressing.cpp"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "Python" === "Python"
```python title="hash_map_open_addressing.py" ```python title="hash_map_open_addressing.py"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "Go" === "Go"
```go title="hash_map_open_addressing.go" ```go title="hash_map_open_addressing.go"
[class]{pair}-[func]{}
[class]{hashMapOpenAddressing}-[func]{} [class]{hashMapOpenAddressing}-[func]{}
``` ```
=== "JavaScript" === "JavaScript"
```javascript title="hash_map_open_addressing.js" ```javascript title="hash_map_open_addressing.js"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "TypeScript" === "TypeScript"
```typescript title="hash_map_open_addressing.ts" ```typescript title="hash_map_open_addressing.ts"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "C" === "C"
```c title="hash_map_open_addressing.c" ```c title="hash_map_open_addressing.c"
[class]{pair}-[func]{}
[class]{hashMapOpenAddressing}-[func]{} [class]{hashMapOpenAddressing}-[func]{}
``` ```
=== "C#" === "C#"
```csharp title="hash_map_open_addressing.cs" ```csharp title="hash_map_open_addressing.cs"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "Swift" === "Swift"
```swift title="hash_map_open_addressing.swift" ```swift title="hash_map_open_addressing.swift"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "Zig" === "Zig"
```zig title="hash_map_open_addressing.zig" ```zig title="hash_map_open_addressing.zig"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```
=== "Dart" === "Dart"
```dart title="hash_map_open_addressing.dart" ```dart title="hash_map_open_addressing.dart"
[class]{Pair}-[func]{}
[class]{HashMapOpenAddressing}-[func]{} [class]{HashMapOpenAddressing}-[func]{}
``` ```

View File

@ -6,7 +6,7 @@
给定一个长度为 $n$ 的有序数组 `nums` ,数组可能包含重复元素。请查找并返回元素 `target` 在数组中首次出现的索引。若数组中不包含该元素,则返回 $-1$ 。 给定一个长度为 $n$ 的有序数组 `nums` ,数组可能包含重复元素。请查找并返回元素 `target` 在数组中首次出现的索引。若数组中不包含该元素,则返回 $-1$ 。
## 简单方法 ## 线性方法
为了查找数组中最左边的 `target` ,我们可以分为两步: 为了查找数组中最左边的 `target` ,我们可以分为两步:
@ -15,11 +15,11 @@
![线性查找最左边的元素](binary_search_edge.assets/binary_search_left_edge_naive.png) ![线性查找最左边的元素](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``nums[m] > target` 时,说明还没有找到 `target` ,因此采取与上节代码相同的缩小区间操作,**从而使指针 $i$ 和 $j$ 向 `target` 靠近**。
- 当 `nums[m] == target` 时,说明“小于 `target` 的元素”在区间 $[i, m - 1]$ 中,因此采用 $j = m - 1$ 来缩小区间,**从而使指针 $j$ 向小于 `target` 的元素靠近**。 - 当 `nums[m] == target` 时,说明“小于 `target` 的元素”在区间 $[i, m - 1]$ 中,因此采用 $j = m - 1$ 来缩小区间,**从而使指针 $j$ 向小于 `target` 的元素靠近**。

View File

@ -38,6 +38,10 @@
回顾原始的快速排序,我们有可能会连续地递归长度较大的数组,最差情况下为 $n, n - 1, n - 2, ..., 2, 1$ ,从而递归深度为 $n$ 。尾递归优化可以避免这种情况的出现。 回顾原始的快速排序,我们有可能会连续地递归长度较大的数组,最差情况下为 $n, n - 1, n - 2, ..., 2, 1$ ,从而递归深度为 $n$ 。尾递归优化可以避免这种情况的出现。
!!! question "当数组中所有元素都相等时,快速排序的时间复杂度是 $O(n^2)$ 吗?该如何处理这种退化情况?"
是的。这种情况可以考虑通过哨兵划分将数组划分为三个部分:小于、等于、大于基准数。仅向下递归小于和大于的两部分。在该方法下,输入元素全部相等的数组,仅一轮哨兵划分即可完成排序。
!!! question "桶排序的最差时间复杂度为什么是 $O(n^2)$ " !!! question "桶排序的最差时间复杂度为什么是 $O(n^2)$ "
最差情况下,所有元素被分至同一个桶中。如果我们采用一个 $O(n^2)$ 算法来排序这些元素,则时间复杂度为 $O(n^2)$ 。 最差情况下,所有元素被分至同一个桶中。如果我们采用一个 $O(n^2)$ 算法来排序这些元素,则时间复杂度为 $O(n^2)$ 。