【问题标题】:What exactly are hashtables?哈希表到底是什么?
【发布时间】:2010-04-12 20:24:32
【问题描述】:
  • 它们是什么以及它们是如何工作的?
  • 它们在哪里使用?
  • 什么时候应该(不)使用它们?

我一遍又一遍地听到这个词,但我不知道它的确切含义。

我听说他们允许关联数组,方法是通过哈希函数发送数组键,将其转换为 int,然后使用常规数组。我说得对吗?

(注意:这不是我的作业;我也上过学,但他们只教我们信息学的基础知识)

【问题讨论】:

  • 我怀疑他们不会告诉你很多关于哈希表的事情。它们实际上很难分析(你需要一个概率正常情况论证,而不是最坏情况论证)并且依赖于很多魔法。大多数算法课的老师更喜欢使用理论上更漂亮的结构,比如平衡树,因为它们展示了递归论证。实际代码虽然使用哈希表;效果很好。

标签: hashtable


【解决方案1】:

Wikipedia 似乎对它们是什么有一个很好的答案。

当您想通过某个索引查找值时应该使用它们。

至于什么时候你不应该使用它们……你不想通过某个索引来查找值时(例如,如果你只想遍历它们。)

【讨论】:

  • 在接收“abc”“myCatIsFat”或“101010”作为输入时,怎么会有一个哈希函数总是输出正确的整数,如 0 1 2 3?!
  • @keg 哈希函数通常返回一个或多或少看起来随机的值,而不是顺序整数。为什么要问?
  • @key 这将是 wiki 文章中描述的完美哈希函数。阅读它以了解为什么这个函数很难找到,以及如何使这些东西至少是半最优的。
  • 写一个好的哈希函数非常非常。写一个坏的很容易,而且文献也不是很好(关于密码散列函数的内容要广泛得多)。输入语言也很重要,一些散列函数在理论上很好,但在实践中很慢。
  • @keg 例如,一个散列函数,比如说,只返回输入的字符串表示的长度,将返回任意输入的整数。请注意,这不是一个很好的哈希函数,请参阅@PeterMmm 评论
【解决方案2】:

你已经明白了。它们是一种非常从任意事物(键)映射到任意事物(值)的好方法。这个想法是您应用一个函数(哈希函数),将键转换为索引到存储值的数组中;散列函数的速度通常与键的大小成线性关系,当键大小远小于条目数时(即典型情况),这非常有用。

棘手的一点是哈希函数通常是不完美的。 (完美的散列函数存在,但往往非常特定于特定的应用程序和特定的数据集;它们几乎不值得。)处理这个问题有两种方法,每种方法都需要存储带有值的键:一种(开放寻址) 是使用预先确定的模式从数组中的位置向前看,其中 空闲的地方的哈希值,另一个(链接)是存储一个链表,挂在每个条目上数组(因此您可以对希望是短列表的内容进行线性查找)。我读过源代码的生产代码案例都使用了链式,当负载因子过大时动态重建哈希表。

【讨论】:

    【解决方案3】:

    良好的散列函数是一种允许您从任何给定输入创建分布式值的方法。因此,您将获得每个输入值的一些唯一值。它们也是可重复的,因此任何输入都将始终生成相同的输出。

    一个好的散列函数的例子是 SHA1 或 SHA256。

    假设您有一个用户数据库表。这些列是idlast_namefirst_nametelephone_numberaddress

    虽然这些列中的任何一个都可能有重复,但我们假设没有完全相同的行。

    在这种情况下,id 只是我们制作的唯一主键(代理键)。 id 字段实际上不包含任何用户数据,因为我们找不到对用户来说唯一的自然键,但我们使用 id 字段与其他表建立外键关系。

    我们可以像这样从我们的数据库中查找用户记录:

    SELECT * FROM users
    WHERE last_name = 'Adams'
    AND first_name = 'Marcus'
    AND address = '1234 Main St'
    AND telephone_number = '555-1212';
    

    我们必须使用 4 个不同的索引搜索 4 个不同的列,才能找到我的记录。

    但是,您可以创建一个新的“散列”列,并存储所有四列组合的散列值。

    String myHash = myHashFunction("Marcus" + "Adams" + "1234 Main St" + "555-1212");
    

    您可能会得到一个像 AE32ABC31234CAD984EA8 这样的哈希值。

    您将此哈希值作为列存储在数据库中并在其上建立索引。您现在只需搜索一个索引。

    SELECT * FROM users
    WHERE hash_value = 'AE32ABC31234CAD984EA8';
    

    一旦我们获得了所请求用户的 id,我们就可以使用该值在其他表中查找相关数据。

    这个想法是散列函数从数据库服务器卸载工作。

    不太可能发生碰撞。如果两个用户的哈希值相同,则很可能他们有重复的数据。

    【讨论】:

    • 7 年后,但我来发布我自己的问题并找到了这个。我不知道为什么你没有任何赞成票(我的是第一个)。我认为对于那些对该主题知之甚少或一无所知的人来说,您的最清晰,最容易理解。但是:如果我知道 pk,我可以查找所有信息,所以我仍然认为哈希没有优势,我也必须查找 - 特别是如果我冒着碰撞的风险,我不会使用 pk .我不明白这是如何卸载数据库服务器的。如果散列和值都在数据库中,你不是还在打数据库吗?
    • 我很久以前就写了这个答案,在我真正研究碰撞之前。坦率地说,你不会发生碰撞。您不必担心它们。虽然理论上可能发生冲突,但从来没有人找到过(对于 SHA1 或 SHA256),我怀疑如果找到了,它不会在两个人类可读文本字符串之间。它从数据库中卸载工作,因为数据库服务器不必做太多的搜索。它正在搜索一个索引而不是多个索引。
    猜你喜欢
    • 1970-01-01
    • 2011-01-22
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多