diff --git a/404.html b/404.html index a323ab7bd..2578f49ad 100644 --- a/404.html +++ b/404.html @@ -938,6 +938,8 @@ + + @@ -967,7 +969,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -993,9 +995,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_appendix/contribution/index.html b/chapter_appendix/contribution/index.html index b1ed4d112..0b3909eca 100644 --- a/chapter_appendix/contribution/index.html +++ b/chapter_appendix/contribution/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_appendix/installation/index.html b/chapter_appendix/installation/index.html index 25bdf16e2..d61cee445 100644 --- a/chapter_appendix/installation/index.html +++ b/chapter_appendix/installation/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_array_and_linkedlist/array/index.html b/chapter_array_and_linkedlist/array/index.html index bd1d8640c..ec8fe4d32 100644 --- a/chapter_array_and_linkedlist/array/index.html +++ b/chapter_array_and_linkedlist/array/index.html @@ -1013,6 +1013,8 @@ + + @@ -1042,7 +1044,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1068,9 +1070,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_array_and_linkedlist/index.html b/chapter_array_and_linkedlist/index.html index a53ef95ad..0b1ec39a0 100644 --- a/chapter_array_and_linkedlist/index.html +++ b/chapter_array_and_linkedlist/index.html @@ -951,6 +951,8 @@ + + @@ -980,7 +982,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1006,9 +1008,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_array_and_linkedlist/linked_list/index.html b/chapter_array_and_linkedlist/linked_list/index.html index 3667916d1..ac4fdf690 100644 --- a/chapter_array_and_linkedlist/linked_list/index.html +++ b/chapter_array_and_linkedlist/linked_list/index.html @@ -1013,6 +1013,8 @@ + + @@ -1042,7 +1044,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1068,9 +1070,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_array_and_linkedlist/list/index.html b/chapter_array_and_linkedlist/list/index.html index a11bf8daf..c7dfda934 100644 --- a/chapter_array_and_linkedlist/list/index.html +++ b/chapter_array_and_linkedlist/list/index.html @@ -999,6 +999,8 @@ + + @@ -1028,7 +1030,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1054,9 +1056,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_array_and_linkedlist/summary/index.html b/chapter_array_and_linkedlist/summary/index.html index d758ca946..8ac2d2dcd 100644 --- a/chapter_array_and_linkedlist/summary/index.html +++ b/chapter_array_and_linkedlist/summary/index.html @@ -992,6 +992,8 @@ + + @@ -1021,7 +1023,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1047,9 +1049,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_backtracking/backtracking_algorithm/index.html b/chapter_backtracking/backtracking_algorithm/index.html index 7df4b6c31..9b6450ffc 100644 --- a/chapter_backtracking/backtracking_algorithm/index.html +++ b/chapter_backtracking/backtracking_algorithm/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_backtracking/index.html b/chapter_backtracking/index.html index f35117a4e..3fabaa04e 100644 --- a/chapter_backtracking/index.html +++ b/chapter_backtracking/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_backtracking/n_queens_problem/index.html b/chapter_backtracking/n_queens_problem/index.html index 8f27093d2..79f27f046 100644 --- a/chapter_backtracking/n_queens_problem/index.html +++ b/chapter_backtracking/n_queens_problem/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_backtracking/permutations_problem/index.html b/chapter_backtracking/permutations_problem/index.html index 627d3f0dc..39e7bd225 100644 --- a/chapter_backtracking/permutations_problem/index.html +++ b/chapter_backtracking/permutations_problem/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_computational_complexity/index.html b/chapter_computational_complexity/index.html index 25e2a4008..cd56b2c25 100644 --- a/chapter_computational_complexity/index.html +++ b/chapter_computational_complexity/index.html @@ -951,6 +951,8 @@ + + @@ -980,7 +982,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1006,9 +1008,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_computational_complexity/performance_evaluation/index.html b/chapter_computational_complexity/performance_evaluation/index.html index a26b2902e..612069a9d 100644 --- a/chapter_computational_complexity/performance_evaluation/index.html +++ b/chapter_computational_complexity/performance_evaluation/index.html @@ -1026,6 +1026,8 @@ + + @@ -1055,7 +1057,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1081,9 +1083,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_computational_complexity/space_complexity/index.html b/chapter_computational_complexity/space_complexity/index.html index dcebabbc7..0d0feeda3 100644 --- a/chapter_computational_complexity/space_complexity/index.html +++ b/chapter_computational_complexity/space_complexity/index.html @@ -1054,6 +1054,8 @@ + + @@ -1083,7 +1085,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1109,9 +1111,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_computational_complexity/summary/index.html b/chapter_computational_complexity/summary/index.html index 3fbd869c3..2fd0ad911 100644 --- a/chapter_computational_complexity/summary/index.html +++ b/chapter_computational_complexity/summary/index.html @@ -992,6 +992,8 @@ + + @@ -1021,7 +1023,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1047,9 +1049,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_computational_complexity/time_complexity/index.html b/chapter_computational_complexity/time_complexity/index.html index 614265436..15a4428f0 100644 --- a/chapter_computational_complexity/time_complexity/index.html +++ b/chapter_computational_complexity/time_complexity/index.html @@ -1102,6 +1102,8 @@ + + @@ -1131,7 +1133,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1157,9 +1159,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_data_structure/basic_data_types/index.html b/chapter_data_structure/basic_data_types/index.html index 3879ea056..e3338a5ce 100644 --- a/chapter_data_structure/basic_data_types/index.html +++ b/chapter_data_structure/basic_data_types/index.html @@ -961,6 +961,8 @@ + + @@ -990,7 +992,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1016,9 +1018,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_data_structure/character_encoding/index.html b/chapter_data_structure/character_encoding/index.html index f43451469..9583d4a35 100644 --- a/chapter_data_structure/character_encoding/index.html +++ b/chapter_data_structure/character_encoding/index.html @@ -1020,6 +1020,8 @@ + + @@ -1049,7 +1051,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1075,9 +1077,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_data_structure/classification_of_data_structure/index.html b/chapter_data_structure/classification_of_data_structure/index.html index 7f1f4ee85..4e9217189 100644 --- a/chapter_data_structure/classification_of_data_structure/index.html +++ b/chapter_data_structure/classification_of_data_structure/index.html @@ -999,6 +999,8 @@ + + @@ -1028,7 +1030,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1054,9 +1056,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_data_structure/index.html b/chapter_data_structure/index.html index b44e4662d..c178e4fd2 100644 --- a/chapter_data_structure/index.html +++ b/chapter_data_structure/index.html @@ -951,6 +951,8 @@ + + @@ -980,7 +982,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1006,9 +1008,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_data_structure/number_encoding/index.html b/chapter_data_structure/number_encoding/index.html index 0777be90e..7923d1bbb 100644 --- a/chapter_data_structure/number_encoding/index.html +++ b/chapter_data_structure/number_encoding/index.html @@ -999,6 +999,8 @@ + + @@ -1028,7 +1030,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1054,9 +1056,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_data_structure/summary/index.html b/chapter_data_structure/summary/index.html index 99b329b15..9301af8bd 100644 --- a/chapter_data_structure/summary/index.html +++ b/chapter_data_structure/summary/index.html @@ -992,6 +992,8 @@ + + @@ -1021,7 +1023,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1047,9 +1049,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_graph/graph/index.html b/chapter_graph/graph/index.html index f0298d170..c9c4eb3fd 100644 --- a/chapter_graph/graph/index.html +++ b/chapter_graph/graph/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_graph/graph_operations/index.html b/chapter_graph/graph_operations/index.html index a8f9ae894..18a03eee9 100644 --- a/chapter_graph/graph_operations/index.html +++ b/chapter_graph/graph_operations/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • @@ -2249,7 +2265,7 @@ // 向顶点列表中添加新顶点的值 vertices.push_back(val); // 在邻接矩阵中添加一行 - adjMat.emplace_back(n, 0); + adjMat.emplace_back(vector<int>(n, 0)); // 在邻接矩阵中添加一列 for (vector<int> &row : adjMat) { row.push_back(0); diff --git a/chapter_graph/graph_traversal/index.html b/chapter_graph/graph_traversal/index.html index 9c4b2bb66..5981f9c66 100644 --- a/chapter_graph/graph_traversal/index.html +++ b/chapter_graph/graph_traversal/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_graph/index.html b/chapter_graph/index.html index 460b7c911..acd4f7497 100644 --- a/chapter_graph/index.html +++ b/chapter_graph/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_graph/summary/index.html b/chapter_graph/summary/index.html index 411e80015..bb39c66c4 100644 --- a/chapter_graph/summary/index.html +++ b/chapter_graph/summary/index.html @@ -949,6 +949,8 @@ + + @@ -978,7 +980,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1004,9 +1006,23 @@ +
  • + + 6.3.   哈希算法(New) + +
  • + + + + + + + + +
  • - 6.3.   小结 + 6.4.   小结
  • diff --git a/chapter_hashing/hash_algorithm.assets/hash_collision_best_worst_condition.png b/chapter_hashing/hash_algorithm.assets/hash_collision_best_worst_condition.png new file mode 100644 index 000000000..5d65b9270 Binary files /dev/null and b/chapter_hashing/hash_algorithm.assets/hash_collision_best_worst_condition.png differ diff --git a/chapter_hashing/hash_algorithm/index.html b/chapter_hashing/hash_algorithm/index.html new file mode 100644 index 000000000..550d65416 --- /dev/null +++ b/chapter_hashing/hash_algorithm/index.html @@ -0,0 +1,2641 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6.3.   哈希算法(New) - Hello 算法 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + 跳转至 + + +
    +
    + +
    + + + + + + +
    + + +
    + +
    + + + + + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    + + + + + + + +
    +
    + + + + + + + + + + + + +

    6.3.   哈希算法

    +

    在上两节中,我们了解了哈希表的工作原理,以及哈希冲突的处理方法。然而,无论是开放寻址还是链地址法,它们只能保证哈希表可以在发生冲突时正常工作,但无法减少哈希冲突的发生

    +

    如果哈希冲突过于频繁,哈希表的性能则会急剧劣化。例如对于链地址哈希表,理想情况下键值对平均分布在各个桶中,达到最好的查询效率;最差情况下全部键值都被存储到同一个桶中,时间复杂度退化至 \(O(n)\)

    +

    哈希冲突的最佳与最差情况

    +

    Fig. 哈希冲突的最佳与最差情况

    + +

    键值对的分布情况是由哈希函数决定的。回忆哈希函数的计算步骤,先计算哈希值,再对数组长度取模:

    +
    index = hash(key) % capacity
    +
    +

    观察以上公式,当哈希表容量 capacity 固定时,哈希算法 hash() 决定了输出值,进而决定了键值对在哈希表中的分布。因此,为了减小哈希冲突的发生概率,我们需要将注意力集中在哈希算法 hash() 的设计上。

    +

    6.3.1.   哈希算法的目标

    +

    为了在编程语言中实现“既快又稳”的哈希表数据结构,哈希算法应包含以下特点:

    +
      +
    • 确定性:对于相同的输入,哈希算法应始终产生相同的输出。这样才能确保哈希表是可靠的。
    • +
    • 效率高:计算哈希值的过程应该足够快。计算开销越小,哈希表的实用性越高。
    • +
    • 均匀分布:哈希算法应使得键值对平均分布在哈希表中。分布越平均,哈希冲突的概率就越低。
    • +
    +

    实际上,哈希算法除了可以用于实现哈希表,还广泛应用于其他领域中,包括:

    +
      +
    • 密码存储:为了保护用户密码的安全,系统通常不会直接存储用户的明文密码,而是存储密码的哈希值。当用户输入密码时,系统会对输入的密码计算哈希值,然后与存储的哈希值进行比较。如果两者匹配,那么密码就被视为正确。
    • +
    • 数据完整性检查:数据发送方可以计算数据的哈希值并将其一同发送;接收方可以重新计算接收到的数据的哈希值,并与接收到的哈希值进行比较。如果两者匹配,那么数据就被视为完整的。
    • +
    +

    对于密码学的相关应用,哈希算法需要满足更高的安全标准,以防止从哈希值推导出原始密码等逆向工程,包括:

    +
      +
    • 抗碰撞性:应当极其困难找到两个不同的输入,使得它们的哈希值相同。
    • +
    • 雪崩效应:输入的微小变化应当导致输出的显著且不可预测的变化。
    • +
    +

    注意,“均匀分布”与“抗碰撞性”是两个独立的概念,满足均匀分布不一定满足抗碰撞性。例如,在随机输入 key 下,哈希函数 key % 100 可以产生均匀分布的输出。然而,该哈希算法过于简单,所有后两位相等的 key 的输出都相同,因此我们可以很容易地从哈希值反推出可用的 key ,从而破解密码。

    +

    6.3.2.   哈希算法的设计

    +

    哈希算法的设计是一个复杂且需要考虑许多因素的问题。然而,对于一些简单场景,我们也能设计一些简单的哈希算法,以字符串哈希为例:

    +
      +
    • 加法哈希:对输入的每个字符的 ASCII 码进行相加,将得到的总和作为哈希值。
    • +
    • 乘法哈希:利用了乘法的不相关性,每轮乘以一个常数,将各个字符的 ASCII 码累积到哈希值中。
    • +
    • 异或哈希:将输入数据的每个元素通过异或操作累积到一个哈希值中。
    • +
    • 旋转哈希:将每个字符的 ASCII 码累积到一个哈希值中,每次累积之前都会对哈希值进行旋转操作。
    • +
    +
    +
    +
    +
    simple_hash.java
    [class]{simple_hash}-[func]{addHash}
    +
    +[class]{simple_hash}-[func]{mulHash}
    +
    +[class]{simple_hash}-[func]{xorHash}
    +
    +[class]{simple_hash}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.cpp
    [class]{}-[func]{addHash}
    +
    +[class]{}-[func]{mulHash}
    +
    +[class]{}-[func]{xorHash}
    +
    +[class]{}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.py
    def add_hash(key: str) -> int:
    +    """加法哈希"""
    +    hash = 0
    +    modulus = 1000000007
    +    for c in key:
    +        hash += ord(c)
    +    return hash % modulus
    +
    +def mul_hash(key: str) -> int:
    +    """乘法哈希"""
    +    hash = 0
    +    modulus = 1000000007
    +    for c in key:
    +        hash = 31 * hash + ord(c)
    +    return hash % modulus
    +
    +def xor_hash(key: str) -> int:
    +    """异或哈希"""
    +    hash = 0
    +    modulus = 1000000007
    +    for c in key:
    +        hash ^= ord(c)
    +    return hash % modulus
    +
    +def rot_hash(key: str) -> int:
    +    """旋转哈希"""
    +    hash = 0
    +    modulus = 1000000007
    +    for c in key:
    +        hash = (hash << 4) ^ (hash >> 28) ^ ord(c)
    +    return hash % modulus
    +
    +
    +
    +
    simple_hash.go
    [class]{}-[func]{addHash}
    +
    +[class]{}-[func]{mulHash}
    +
    +[class]{}-[func]{xorHash}
    +
    +[class]{}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.js
    [class]{}-[func]{addHash}
    +
    +[class]{}-[func]{mulHash}
    +
    +[class]{}-[func]{xorHash}
    +
    +[class]{}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.ts
    [class]{}-[func]{addHash}
    +
    +[class]{}-[func]{mulHash}
    +
    +[class]{}-[func]{xorHash}
    +
    +[class]{}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.c
    [class]{}-[func]{addHash}
    +
    +[class]{}-[func]{mulHash}
    +
    +[class]{}-[func]{xorHash}
    +
    +[class]{}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.cs
    [class]{simple_hash}-[func]{addHash}
    +
    +[class]{simple_hash}-[func]{mulHash}
    +
    +[class]{simple_hash}-[func]{xorHash}
    +
    +[class]{simple_hash}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.swift
    [class]{}-[func]{addHash}
    +
    +[class]{}-[func]{mulHash}
    +
    +[class]{}-[func]{xorHash}
    +
    +[class]{}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.zig
    [class]{}-[func]{addHash}
    +
    +[class]{}-[func]{mulHash}
    +
    +[class]{}-[func]{xorHash}
    +
    +[class]{}-[func]{rotHash}
    +
    +
    +
    +
    simple_hash.dart
    [class]{}-[func]{add_hash}
    +
    +[class]{}-[func]{mul_hash}
    +
    +[class]{}-[func]{xor_hash}
    +
    +[class]{}-[func]{rot_hash}
    +
    +
    +
    +
    +

    观察发现,每种哈希算法的最后一步都是对大质数 \(1000000007\) 取模,以确保哈希值在合适的范围内。值得思考的是,为什么要强调对质数取模,对合数取模的弊端是什么?这是一个有趣的问题。

    +

    先抛出结论:当我们使用大质数作为模数时,可以最大化地保证哈希值的均匀分布。因为质数不会与其他数字存在公约数,可以减少因取模操作而产生的周期性模式,从而避免哈希冲突。

    +

    举个例子,假设我们选择合数 \(9\) 作为模数,它可以被 \(3\) 整除。那么所有可以被 \(3\) 整除的 key 都会被映射到 \(0\) , \(3\) , \(6\) 这三个哈希值。

    +
    \[ +\begin{aligned} +\text{modulus} & = 9 \newline +\text{key} & = \{ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, \cdots \} \newline +\text{hash} & = \{ 0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6,\cdots \} +\end{aligned} +\]
    +

    如果输入 key 恰好满足这种等差数列的数据分布,那么哈希值就会出现聚堆,从而加重哈希冲突。现在,假设将 modulus 替换为质数 \(13\) ,由于 keymodulus 之间不存在公约数,输出的哈希值的均匀性会明显提升。

    +
    \[ +\begin{aligned} +\text{modulus} & = 13 \newline +\text{key} & = \{ 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, \cdots \} \newline +\text{hash} & = \{ 0, 3, 6, 9, 12, 2, 5, 8, 11, 1, 4, 7, \cdots \} +\end{aligned} +\]
    +

    值得强调的是,如果能够保证 key 是随机均匀分布的,那么选择质数或者合数作为模数都是可以的,它们都能输出均匀分布的哈希值。而当 key 的分布存在某种周期性时,对合数取模更容易出现聚集现象。

    +

    总而言之,我们通常选取质数作为模数,并且这个质数最好大一些,以提升哈希算法的稳健性。

    +

    6.3.3.   常见哈希算法

    +

    不难发现,以上介绍的简单哈希算法都比较“脆弱”,远远没有达到哈希算法的设计目标。例如,由于加法和异或满足交换律,因此加法哈希和异或哈希无法区分内容相同但顺序不同的字符串,这可能会加剧哈希冲突,并引起一些安全问题。

    +

    在实际中,我们通常会用一些标准哈希算法,例如 MD5, SHA-1, SHA-2, SHA3 等。它们可以将任意长度的输入数据映射到恒定长度的哈希值。近一个世纪以来,哈希算法处在不断升级与优化的过程中。一部分研究人员努力提升哈希算法的性能,另一部分研究人员和黑客则致力于寻找哈希算法的安全性问题。

    +

    直至目前,MD5 和 SHA-1 已多次被成功攻击,因此它们被各类安全应用弃用。SHA-2 系列中的 SHA-256 是最安全的哈希算法之一,仍未出现成功的攻击案例,因此常被用在各类安全应用与协议中。SHA-3 相较 SHA-2 的实现开销更低、计算效率更高,但目前使用覆盖度不如 SHA-2 系列。

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MD5SHA-1SHA-2SHA-3
    推出时间1992199520022008
    输出长度128 bits160 bits256 / 512 bits224/256/384/512 bits
    哈希冲突较多较多很少很少
    安全等级低,已被成功攻击低,已被成功攻击
    应用已被弃用,仍用于数据完整性检查已被弃用加密货币交易验证、数字签名等可用于替代 SHA-2
    +

    6.3.4.   数据结构的哈希值

    +

    我们知道,哈希表的 key 可以是整数、小数或字符串等数据类型。编程语言通常会为这些数据类型提供内置的哈希算法 hash() ,用于计算哈希表中的桶索引。以 Python 为例:

    +
      +
    • 整数和布尔量的哈希值就是其本身。
    • +
    • 浮点数和字符串的哈希值计算较为复杂,有兴趣的同学请自行学习。
    • +
    • 元组的哈希值是对其中每一个元素进行哈希,然后将这些哈希值组合起来,得到单一的哈希值。
    • +
    • 对象的哈希值基于其内存地址生成。通过重写对象的哈希方法,可实现基于内容生成哈希值。
    • +
    +
    +
    +
    +
    built_in_hash.java
    
    +
    +
    +
    +
    built_in_hash.cpp
    
    +
    +
    +
    +
    built_in_hash.py
    num = 3
    +hash_num = hash(num)
    +# 整数 3 的哈希值为 3
    +
    +bol = True
    +hash_bol = hash(bol)
    +# 布尔量 True 的哈希值为 1
    +
    +dec = 3.14159
    +hash_dec = hash(dec) 
    +# 小数 3.14159 的哈希值为 326484311674566659
    +
    +str = "Hello 算法"
    +hash_str = hash(str)
    +# 字符串 Hello 算法 的哈希值为 4617003410720528961
    +
    +tup = (12836, "小哈")
    +hash_tup = hash(tup)
    +# 元组 (12836, '小哈') 的哈希值为 1029005403108185979
    +
    +obj = ListNode(0)
    +hash_obj = hash(obj)
    +# 节点对象 <ListNode object at 0x1058fd810> 的哈希值为 274267521
    +
    +
    +
    +
    built_in_hash.go
    
    +
    +
    +
    +
    built_in_hash.js
    
    +
    +
    +
    +
    built_in_hash.ts
    
    +
    +
    +
    +
    built_in_hash.c
    
    +
    +
    +
    +
    built_in_hash.cs
    
    +
    +
    +
    +
    built_in_hash.swift
    
    +
    +
    +
    +
    built_in_hash.zig
    
    +
    +
    +
    +
    built_in_hash.dart
    
    +
    +
    +
    +
    +

    在大多数编程语言中,只有不可变对象才可作为哈希表的 key 。假如我们将列表(动态数组)作为 key ,当列表的内容发生变化时,它的哈希值也随之改变,我们就无法在哈希表中查询到原先的 value 了。

    +

    虽然自定义对象(例如链表节点)的成员变量是可变的,但它是可哈希的,这是因为对象的哈希值默认基于内存地址生成。即使对象的内容发生了变化,但它的内存地址不变,哈希值仍然是不变的。

    +
    +

    向哈希函数加盐

    +

    Python 解释器在每次启动时,都会为字符串哈希函数加入一个随机的盐(Salt)值。因此在不同的 Python 运行实例中,同一字符串的哈希值通常是不同的。此做法可以有效防止 HashDoS 攻击,提升哈希算法的安全性。

    +
    + + + + + +

    评论

    + + + + + + +
    +
    + + + + +
    + + + +
    + + + +
    +
    +
    +
    + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/chapter_hashing/hash_collision/index.html b/chapter_hashing/hash_collision/index.html index 928e9081d..cdd44e76d 100644 --- a/chapter_hashing/hash_collision/index.html +++ b/chapter_hashing/hash_collision/index.html @@ -18,7 +18,7 @@ - + @@ -951,6 +951,8 @@ + + @@ -980,7 +982,7 @@
  • - 6.1.   哈希表 + 6.1.   哈希表(New)
  • @@ -1028,24 +1030,17 @@
  • - 6.2.1.   哈希表扩容 + 6.2.1.   链式地址
  • - 6.2.2.   链式地址 + 6.2.2.   开放寻址 -
  • - -
  • - - 6.2.3.   开放寻址 - - -