【问题标题】:What are buckets in terms of hash functions?就哈希函数而言,桶是什么?
【发布时间】:2017-05-03 14:28:12
【问题描述】:

看书Mining of Massive Datasets,第1.3.2节有Hash Functions的概述。没有计算机科学背景,这对我来说很新鲜; Ruby 是我的第一语言,hash 似乎等同于Dictionary<object, object>。而且我从未考虑过如何将这种数据结构组合在一起。

本书提到了散列函数,作为实现这些字典数据结构的一种手段。本段:

首先,哈希函数 h 将哈希键值作为参数并产生 结果是一个桶号。桶号是一个整数,通常在 范围 0 到 B - 1,其中 B 是桶的数量。哈希键可以是任何 类型。哈希函数有一个直观的属性,它们“随机化” 哈希键

hash function 而言,桶究竟是什么?听起来桶是array-like 结构,而hash function 是某种算法/array-like-structure 搜索每次都会产生相同的桶号?这个比喻性的桶里有什么?

我一直读到 javascript 对象/ruby 哈希/等不保证顺序。在实践中,我发现键的顺序不会改变(实际上,我认为使用旧版本的 Mozilla 的 Rhino 解释器会改变 JS 对象顺序,但我不能确定......)。

这是否意味着这些 hash functions 无法解析哈希 (Ruby) / 对象 (JS)?

hashing 这个词是否会根据您使用计算机的水平而具有不同的含义?也就是说,看起来 Ruby 散列与 C++ 散列不同......

【问题讨论】:

    标签: hash-function


    【解决方案1】:

    当您散列一个值时,任何有用的散列函数通常范围都小于。这意味着在输入值的大列表(例如所有可能的字母组合)中,它将输出任何较小的值列表(以特定长度为上限的数字)。这意味着多个输入值可以映射到同一个输出值。

    在这种情况下,输出值被称为桶。

    考虑函数f(x) = x mod 2

    这会生成以下输出;

    1 => 1
    2 => 0
    3 => 1
    4 => 0
    

    在这种情况下,有两个桶(1 和 0),每个桶都有一堆输入值。

    一个好的散列函数将平等地填充所有这些“桶”,因此可以实现更快的搜索等。如果您采用任何数字的模式,您可以查看桶,因此必须搜索的结果少于如果您刚开始搜索,因为每个存储桶中的结果少于整个输入集。在理想情况下,哈希计算速度很快,每个桶中只有一个结果,这使得查找只需应用哈希函数所需的时间。

    这当然是一个简化的例子,但希望你明白吗?

    【讨论】:

    • 谢谢。这很有帮助。在使用保证唯一桶分配的哈希函数与允许在同一个桶中有多个值的哈希函数之间是否存在权衡?在这种情况下,听起来哈希表是由数组“覆盖”的(可以这么说),而存储桶是数组?
    • @ZachSmith 这会因实现而异,但通常不止一个输入会映射到同一个输出,这意味着如果在数据中使用散列函数,它们需要以某种形式的集合存储结构,这确实通常是一个数组 - 但不是在所有情况下。映射到每个输出的输入数量会因所使用的数据而异,这就是为什么一些哈希函数在某些用途上可能是“好”但在其他用途​​上却是垃圾
    • @ZachSmith 是的,散列是一个概念,因此可以用于多种用途,但实际上,在数据结构中使用时,通常以您假设的方式工作
    【解决方案2】:

    哈希函数的概念始终相同。它是一个计算一些数字来表示对象的函数。这个数字的属性应该是:

    • 计算成本相对较低
    • 所有对象都尽可能不同。

    让我们举一个非常人为的例子来说明我的意思以及为什么/如何通常使用哈希。

    取所有自然数。现在让我们假设检查 2 个数字是否相等是很昂贵的。

    我们也定义一个相对便宜的哈希函数如下:

    hash = number % 10
    

    思路很简单,只取数字的最后一位作为哈希。在你得到的解释中,这意味着我们将所有以 1 结尾的数字放入一个假想的 1 桶中,所有以 2 结尾的数字都放入 2 桶等等......

    这些存储桶并不真正作为数据结构存在。它们只是让哈希函数的推理变得容易。


    现在我们有了这个廉价的哈希函数,我们可以用它来降低其他事情的成本。例如,我们想创建一个新的数据结构来实现对数字的廉价搜索。我们称这个数据结构为 hashmap。

    这里我们实际上将所有带有hash=1 的数字放在一个列表/集合/...中,我们将带有hash=5 的数字放入它们自己的列表/集合...等等。

    如果我们想查找某个数字,我们首先计算它的哈希值。然后我们检查与这个哈希对应的列表/集合,然后只比较“相似”的数字来找到我们想要的确切数字。这意味着我们只需要进行廉价的哈希计算,然后必须使用昂贵的相等性检查来检查 1/10 的数字。

    注意这里我们使用散列函数来定义一个新的数据结构。哈希本身不是数据结构。

    【讨论】:

      【解决方案3】:

      让我简单地解释一下。使用链接技术(开放散列或封闭寻址)处理冲突时,桶会出现

      这里,每个数组条目对应一个桶,每个数组条目(如果非空)将有一个指向链表头部的指针。 (桶实现为链表)。

      散列表应使用散列函数来计算存储桶数组的索引,从中可以找到所需的值。

      也就是说,在检查一个元素是否在哈希表中时,首先对键进行哈希处理以找到要查找的正确存储桶。然后遍历对应的链表,定位到想要的元素。

      类似地,在添加或删除任何元素时,散列用于查找合适的存储桶。然后,检查桶是否存在所需元素,并通过遍历相应的链表将其从桶中添加/删除。

      【讨论】:

        【解决方案4】:

        考虑一下电话簿。

        假设您想在电话簿中查找唐老鸭。

        必须查看每个页面以及该页面上的每个条目会非常低效。因此,我们不这样做,而是做以下事情:

        • 我们创建一个索引

        • 我们创建了一种从名称中获取索引键的方法

        对于电话簿,索引从 A 到 Z,用于获取索引键的函数只是从姓氏中获取第一个字母。

        在这种情况下,散列函数采用Donald Duck 并为您提供D。 然后你拿D 去索引所有姓氏以D开头的人。

        这样说太简单了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-07
          • 2011-06-04
          • 2013-03-01
          • 1970-01-01
          • 2016-03-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多