mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-24 10:33:34 +08:00
deploy
This commit is contained in:
@@ -3532,32 +3532,20 @@
|
||||
<li>编程语言通常会为数据类型提供内置哈希算法,用于计算哈希表中的桶索引。通常情况下,只有不可变对象是可哈希的。</li>
|
||||
</ul>
|
||||
<h3 id="2-q-a">2. Q & A<a class="headerlink" href="#2-q-a" title="Permanent link">¶</a></h3>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">哈希表的时间复杂度在什么情况下是 <span class="arithmatex">\(O(n)\)</span> ?</p>
|
||||
<p><strong>Q</strong>:哈希表的时间复杂度在什么情况下是 <span class="arithmatex">\(O(n)\)</span> ?</p>
|
||||
<p>当哈希冲突比较严重时,哈希表的时间复杂度会退化至 <span class="arithmatex">\(O(n)\)</span> 。当哈希函数设计得比较好、容量设置比较合理、冲突比较平均时,时间复杂度是 <span class="arithmatex">\(O(1)\)</span> 。我们使用编程语言内置的哈希表时,通常认为时间复杂度是 <span class="arithmatex">\(O(1)\)</span> 。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">为什么不使用哈希函数 <span class="arithmatex">\(f(x) = x\)</span> 呢?这样就不会有冲突了</p>
|
||||
<p><strong>Q</strong>:为什么不使用哈希函数 <span class="arithmatex">\(f(x) = x\)</span> 呢?这样就不会有冲突了。</p>
|
||||
<p>在 <span class="arithmatex">\(f(x) = x\)</span> 哈希函数下,每个元素对应唯一的桶索引,这与数组等价。然而,输入空间通常远大于输出空间(数组长度),因此哈希函数的最后一步往往是对数组长度取模。换句话说,哈希表的目标是将一个较大的状态空间映射到一个较小的空间,并提供 <span class="arithmatex">\(O(1)\)</span> 的查询效率。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">哈希表底层实现是数组、链表、二叉树,但为什么效率可以比它们更高呢?</p>
|
||||
<p><strong>Q</strong>:哈希表底层实现是数组、链表、二叉树,但为什么效率可以比它们更高呢?</p>
|
||||
<p>首先,哈希表的时间效率变高,但空间效率变低了。哈希表有相当一部分内存未使用。</p>
|
||||
<p>其次,只是在特定使用场景下时间效率变高了。如果一个功能能够在相同的时间复杂度下使用数组或链表实现,那么通常比哈希表更快。这是因为哈希函数计算需要开销,时间复杂度的常数项更大。</p>
|
||||
<p>最后,哈希表的时间复杂度可能发生劣化。例如在链式地址中,我们采取在链表或红黑树中执行查找操作,仍然有退化至 <span class="arithmatex">\(O(n)\)</span> 时间的风险。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">多次哈希有不能直接删除元素的缺陷吗?标记为已删除的空间还能再次使用吗?</p>
|
||||
<p><strong>Q</strong>:多次哈希有不能直接删除元素的缺陷吗?标记为已删除的空间还能再次使用吗?</p>
|
||||
<p>多次哈希是开放寻址的一种,开放寻址法都有不能直接删除元素的缺陷,需要通过标记删除。标记为已删除的空间可以再次使用。当将新元素插入哈希表,并且通过哈希函数找到标记为已删除的位置时,该位置可以被新元素使用。这样做既能保持哈希表的探测序列不变,又能保证哈希表的空间使用率。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">为什么在线性探测中,查找元素的时候会出现哈希冲突呢?</p>
|
||||
<p><strong>Q</strong>:为什么在线性探测中,查找元素的时候会出现哈希冲突呢?</p>
|
||||
<p>查找的时候通过哈希函数找到对应的桶和键值对,发现 <code>key</code> 不匹配,这就代表有哈希冲突。因此,线性探测法会根据预先设定的步长依次向下查找,直至找到正确的键值对或无法找到跳出为止。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">为什么哈希表扩容能够缓解哈希冲突?</p>
|
||||
<p><strong>Q</strong>:为什么哈希表扩容能够缓解哈希冲突?</p>
|
||||
<p>哈希函数的最后一步往往是对数组长度 <span class="arithmatex">\(n\)</span> 取模(取余),让输出值落在数组索引范围内;在扩容后,数组长度 <span class="arithmatex">\(n\)</span> 发生变化,而 <code>key</code> 对应的索引也可能发生变化。原先落在同一个桶的多个 <code>key</code> ,在扩容后可能会被分配到多个桶中,从而实现哈希冲突的缓解。</p>
|
||||
</div>
|
||||
|
||||
<!-- Source file information -->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user