This commit is contained in:
krahets
2024-05-02 01:46:20 +08:00
parent 5e90519796
commit 23353e7960
324 changed files with 420 additions and 419 deletions
+1 -1
View File
@@ -4737,7 +4737,7 @@ aria-label="Footer"
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2022-2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
Copyright &copy; 2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
</div>
+4 -4
View File
@@ -3683,7 +3683,7 @@
</ol>
<p>There are mainly two methods for improving the structure of hash tables: "Separate Chaining" and "Open Addressing".</p>
<h2 id="621-separate-chaining">6.2.1 &nbsp; Separate chaining<a class="headerlink" href="#621-separate-chaining" title="Permanent link">&para;</a></h2>
<p>In the original hash table, each bucket can store only one key-value pair. "Separate chaining" transforms individual elements into a linked list, with key-value pairs as list nodes, storing all colliding key-value pairs in the same list. Figure 6-5 shows an example of a hash table with separate chaining.</p>
<p>In the original hash table, each bucket can store only one key-value pair. <u>Separate chaining</u> transforms individual elements into a linked list, with key-value pairs as list nodes, storing all colliding key-value pairs in the same list. Figure 6-5 shows an example of a hash table with separate chaining.</p>
<p><a class="glightbox" href="../hash_collision.assets/hash_table_chaining.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Separate chaining hash table" class="animation-figure" src="../hash_collision.assets/hash_table_chaining.png" /></a></p>
<p align="center"> Figure 6-5 &nbsp; Separate chaining hash table </p>
@@ -5176,7 +5176,7 @@
</details>
<p>It's worth noting that when the list is very long, the query efficiency <span class="arithmatex">\(O(n)\)</span> is poor. <strong>At this point, the list can be converted to an "AVL tree" or "Red-Black tree"</strong> to optimize the time complexity of the query operation to <span class="arithmatex">\(O(\log n)\)</span>.</p>
<h2 id="622-open-addressing">6.2.2 &nbsp; Open addressing<a class="headerlink" href="#622-open-addressing" title="Permanent link">&para;</a></h2>
<p>"Open addressing" does not introduce additional data structures but uses "multiple probes" to handle hash collisions. The probing methods mainly include linear probing, quadratic probing, and double hashing.</p>
<p><u>Open addressing</u> does not introduce additional data structures but uses "multiple probes" to handle hash collisions. The probing methods mainly include linear probing, quadratic probing, and double hashing.</p>
<p>Let's use linear probing as an example to introduce the mechanism of open addressing hash tables.</p>
<h3 id="1-linear-probing">1. &nbsp; Linear probing<a class="headerlink" href="#1-linear-probing" title="Permanent link">&para;</a></h3>
<p>Linear probing uses a fixed-step linear search for probing, differing from ordinary hash tables.</p>
@@ -5193,7 +5193,7 @@
<p><a class="glightbox" href="../hash_collision.assets/hash_table_open_addressing_deletion.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Query issues caused by deletion in open addressing" class="animation-figure" src="../hash_collision.assets/hash_table_open_addressing_deletion.png" /></a></p>
<p align="center"> Figure 6-7 &nbsp; Query issues caused by deletion in open addressing </p>
<p>To solve this problem, we can use a "lazy deletion" mechanism: instead of directly removing elements from the hash table, <strong>use a constant <code>TOMBSTONE</code> to mark the bucket</strong>. In this mechanism, both <code>None</code> and <code>TOMBSTONE</code> represent empty buckets and can hold key-value pairs. However, when linear probing encounters <code>TOMBSTONE</code>, it should continue traversing since there may still be key-value pairs below it.</p>
<p>To solve this problem, we can use a <u>lazy deletion</u> mechanism: instead of directly removing elements from the hash table, <strong>use a constant <code>TOMBSTONE</code> to mark the bucket</strong>. In this mechanism, both <code>None</code> and <code>TOMBSTONE</code> represent empty buckets and can hold key-value pairs. However, when linear probing encounters <code>TOMBSTONE</code>, it should continue traversing since there may still be key-value pairs below it.</p>
<p>However, <strong>lazy deletion may accelerate the degradation of hash table performance</strong>. Every deletion operation produces a delete mark, and as <code>TOMBSTONE</code> increases, so does the search time, as linear probing may have to skip multiple <code>TOMBSTONE</code> to find the target element.</p>
<p>Therefore, consider recording the index of the first <code>TOMBSTONE</code> encountered during linear probing and swapping the target element found with this <code>TOMBSTONE</code>. The advantage of this is that each time a query or addition is performed, the element is moved to a bucket closer to the ideal position (starting point of probing), thereby optimizing the query efficiency.</p>
<p>The code below implements an open addressing (linear probing) hash table with lazy deletion. To make fuller use of the hash table space, we treat the hash table as a "circular array," continuing to traverse from the beginning when the end of the array is passed.</p>
@@ -7119,7 +7119,7 @@ aria-label="Footer"
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2022-2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
Copyright &copy; 2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
</div>
+6 -6
View File
@@ -3609,7 +3609,7 @@
<!-- Page content -->
<h1 id="61-hash-table">6.1 &nbsp; Hash table<a class="headerlink" href="#61-hash-table" title="Permanent link">&para;</a></h1>
<p>A "hash table", also known as a "hash map", achieves efficient element querying by establishing a mapping between keys and values. Specifically, when we input a <code>key</code> into the hash table, we can retrieve the corresponding <code>value</code> in <span class="arithmatex">\(O(1)\)</span> time.</p>
<p>A <u>hash table</u> achieves efficient element querying by establishing a mapping between keys and values. Specifically, when we input a <code>key</code> into the hash table, we can retrieve the corresponding <code>value</code> in <span class="arithmatex">\(O(1)\)</span> time.</p>
<p>As shown in Figure 6-1, given <span class="arithmatex">\(n\)</span> students, each with two pieces of data: "name" and "student number". If we want to implement a query feature that returns the corresponding name when given a student number, we can use the hash table shown in Figure 6-1.</p>
<p><a class="glightbox" href="../hash_map.assets/hash_table_lookup.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Abstract representation of a hash table" class="animation-figure" src="../hash_map.assets/hash_table_lookup.png" /></a></p>
<p align="center"> Figure 6-1 &nbsp; Abstract representation of a hash table </p>
@@ -4073,8 +4073,8 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E5%93%88%E5%B8%8C%E8%A1%A8%0A%20%20%20%20hmap%20%3D%20%7B%7D%0A%20%20%20%20%0A%20%20%20%20%23%20%E6%B7%BB%E5%8A%A0%E6%93%8D%E4%BD%9C%0A%20%20%20%20%23%20%E5%9C%A8%E5%93%88%E5%B8%8C%E8%A1%A8%E4%B8%AD%E6%B7%BB%E5%8A%A0%E9%94%AE%E5%80%BC%E5%AF%B9%20%28key,%20value%29%0A%20%20%20%20hmap%5B12836%5D%20%3D%20%22%E5%B0%8F%E5%93%88%22%0A%20%20%20%20hmap%5B15937%5D%20%3D%20%22%E5%B0%8F%E5%95%B0%22%0A%20%20%20%20hmap%5B16750%5D%20%3D%20%22%E5%B0%8F%E7%AE%97%22%0A%20%20%20%20hmap%5B13276%5D%20%3D%20%22%E5%B0%8F%E6%B3%95%22%0A%20%20%20%20hmap%5B10583%5D%20%3D%20%22%E5%B0%8F%E9%B8%AD%22%0A%20%20%20%20%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E5%93%88%E5%B8%8C%E8%A1%A8%0A%20%20%20%20%23%20%E9%81%8D%E5%8E%86%E9%94%AE%E5%80%BC%E5%AF%B9%20key-%3Evalue%0A%20%20%20%20for%20key,%20value%20in%20hmap.items%28%29%3A%0A%20%20%20%20%20%20%20%20print%28key,%20%22-%3E%22,%20value%29%0A%20%20%20%20%23%20%E5%8D%95%E7%8B%AC%E9%81%8D%E5%8E%86%E9%94%AE%20key%0A%20%20%20%20for%20key%20in%20hmap.keys%28%29%3A%0A%20%20%20%20%20%20%20%20print%28key%29%0A%20%20%20%20%23%20%E5%8D%95%E7%8B%AC%E9%81%8D%E5%8E%86%E5%80%BC%20value%0A%20%20%20%20for%20value%20in%20hmap.values%28%29%3A%0A%20%20%20%20%20%20%20%20print%28value%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=8&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Full Screen &gt;</a></div></p>
</details>
<h2 id="612-simple-implementation-of-hash-table">6.1.2 &nbsp; Simple implementation of hash table<a class="headerlink" href="#612-simple-implementation-of-hash-table" title="Permanent link">&para;</a></h2>
<p>First, let's consider the simplest case: <strong>implementing a hash table using just an array</strong>. In the hash table, each empty slot in the array is called a "bucket", and each bucket can store one key-value pair. Therefore, the query operation involves finding the bucket corresponding to the <code>key</code> and retrieving the <code>value</code> from it.</p>
<p>So, how do we locate the appropriate bucket based on the <code>key</code>? This is achieved through a "hash function". The role of the hash function is to map a larger input space to a smaller output space. In a hash table, the input space is all possible keys, and the output space is all buckets (array indices). In other words, input a <code>key</code>, <strong>and we can use the hash function to determine the storage location of the corresponding key-value pair in the array</strong>.</p>
<p>First, let's consider the simplest case: <strong>implementing a hash table using just an array</strong>. In the hash table, each empty slot in the array is called a <u>bucket</u>, and each bucket can store one key-value pair. Therefore, the query operation involves finding the bucket corresponding to the <code>key</code> and retrieving the <code>value</code> from it.</p>
<p>So, how do we locate the appropriate bucket based on the <code>key</code>? This is achieved through a <u>hash function</u>. The role of the hash function is to map a larger input space to a smaller output space. In a hash table, the input space is all possible keys, and the output space is all buckets (array indices). In other words, input a <code>key</code>, <strong>and we can use the hash function to determine the storage location of the corresponding key-value pair in the array</strong>.</p>
<p>The calculation process of the hash function for a given <code>key</code> is divided into the following two steps:</p>
<ol>
<li>Calculate the hash value using a certain hash algorithm <code>hash()</code>.</li>
@@ -5362,7 +5362,7 @@
<div class="highlight"><pre><span></span><code><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a><span class="m">12836</span><span class="w"> </span>%<span class="w"> </span><span class="nv">100</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">36</span>
<a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a><span class="m">20336</span><span class="w"> </span>%<span class="w"> </span><span class="nv">100</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">36</span>
</code></pre></div>
<p>As shown in Figure 6-3, both student numbers point to the same name, which is obviously incorrect. This situation where multiple inputs correspond to the same output is known as "hash collision".</p>
<p>As shown in Figure 6-3, both student numbers point to the same name, which is obviously incorrect. This situation where multiple inputs correspond to the same output is known as <u>hash collision</u>.</p>
<p><a class="glightbox" href="../hash_map.assets/hash_collision.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="Example of hash collision" class="animation-figure" src="../hash_map.assets/hash_collision.png" /></a></p>
<p align="center"> Figure 6-3 &nbsp; Example of hash collision </p>
@@ -5372,7 +5372,7 @@
<p align="center"> Figure 6-4 &nbsp; Hash table expansion </p>
<p>Similar to array expansion, resizing a hash table requires migrating all key-value pairs from the original hash table to the new one, which is time-consuming. Furthermore, since the capacity <code>capacity</code> of the hash table changes, we need to recalculate the storage positions of all key-value pairs using the hash function, which adds to the computational overhead of the resizing process. Therefore, programming languages often reserve a sufficiently large capacity for the hash table to prevent frequent resizing.</p>
<p>The "load factor" is an important concept for hash tables. It is defined as the ratio of the number of elements in the hash table to the number of buckets. It is used to measure the severity of hash collisions and <strong>is often used as a trigger for resizing the hash table</strong>. For example, in Java, when the load factor exceeds <span class="arithmatex">\(0.75\)</span>, the system will resize the hash table to twice its original size.</p>
<p>The <u>load factor</u> is an important concept for hash tables. It is defined as the ratio of the number of elements in the hash table to the number of buckets. It is used to measure the severity of hash collisions and <strong>is often used as a trigger for resizing the hash table</strong>. For example, in Java, when the load factor exceeds <span class="arithmatex">\(0.75\)</span>, the system will resize the hash table to twice its original size.</p>
<!-- Source file information -->
@@ -5560,7 +5560,7 @@ aria-label="Footer"
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2022-2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
Copyright &copy; 2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
</div>
+1 -1
View File
@@ -3724,7 +3724,7 @@ aria-label="Footer"
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2022-2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
Copyright &copy; 2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
</div>
+1 -1
View File
@@ -3809,7 +3809,7 @@ aria-label="Footer"
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2022-2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
Copyright &copy; 2024 krahets<br>The website content is licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a>
</div>