This commit is contained in:
krahets
2023-07-24 03:03:58 +08:00
parent a86a371780
commit 3e2ab6a857
19 changed files with 379 additions and 456 deletions
+1 -1
View File
@@ -3388,7 +3388,7 @@
<h1 id="118">11.8. &nbsp; 桶排序<a class="headerlink" href="#118" title="Permanent link">&para;</a></h1>
<p>前述的几种排序算法都属于“基于比较的排序算法”,它们通过比较元素间的大小来实现排序。此类排序算法的时间复杂度无法超越 <span class="arithmatex">\(O(n \log n)\)</span> 。接下来,我们将探讨几种“非比较排序算法”,它们的时间复杂度可以达到线性水平</p>
<p>前述的几种排序算法都属于“基于比较的排序算法”,它们通过比较元素间的大小来实现排序。此类排序算法的时间复杂度无法超越 <span class="arithmatex">\(O(n \log n)\)</span> 。接下来,我们将探讨几种“非比较排序算法”,它们的时间复杂度可以达到线性</p>
<p>「桶排序 Bucket Sort」是分治思想的一个典型应用。它通过设置一些具有大小顺序的桶,每个桶对应一个数据范围,将数据平均分配到各个桶中;然后,在每个桶内部分别执行排序;最终按照桶的顺序将所有数据合并。</p>
<h2 id="1181">11.8.1. &nbsp; 算法流程<a class="headerlink" href="#1181" title="Permanent link">&para;</a></h2>
<p>考虑一个长度为 <span class="arithmatex">\(n\)</span> 的数组,元素是范围 <span class="arithmatex">\([0, 1)\)</span> 的浮点数。桶排序的流程如下:</p>
+3 -5
View File
@@ -3368,13 +3368,11 @@
<li>桶排序包含三个步骤:数据分桶、桶内排序和合并结果。它同样体现了分治策略,适用于数据体量很大的情况。桶排序的关键在于对数据进行平均分配。</li>
<li>计数排序是桶排序的一个特例,它通过统计数据出现的次数来实现排序。计数排序适用于数据量大但数据范围有限的情况,并且要求数据能够转换为正整数。</li>
<li>基数排序通过逐位排序来实现数据排序,要求数据能够表示为固定位数的数字。</li>
<li>总的来说,我们希望找到一种排序算法,具有高效率、稳定、原地以及正向自适应性等优点。然而,正如其他数据结构和算法一样,没有一种排序算法能够同时满足所有这些条件。在实际应用中,我们需要根据数据的特性来选择合适的排序算法。</li>
</ul>
<p><img alt="排序算法对比" src="../summary.assets/sorting_algorithms_comparison.png" /></p>
<p align="center"> Fig. 排序算法对比 </p>
<ul>
<li>总的来说,我们希望找到一种排序算法,具有高效率、稳定、原地以及正向自适应性等优点。然而,正如其他数据结构和算法一样,没有一种排序算法能够同时满足所有这些条件。在实际应用中,我们需要根据数据的特性来选择合适的排序算法。</li>
</ul>
<h2 id="11111-q-a">11.11.1. &nbsp; Q &amp; A<a class="headerlink" href="#11111-q-a" title="Permanent link">&para;</a></h2>
<div class="admonition question">
<p class="admonition-title">排序算法稳定性在什么情况下是必须的?</p>
@@ -3390,8 +3388,8 @@
<p>再深入思考一下,如果我们选择 <code>nums[right]</code> 为基准数,那么正好反过来,必须先“从左往右查找”。</p>
</div>
<div class="admonition question">
<p class="admonition-title">关于尾递归优化,为什么选短的数组能保证递归深度不超过 <span class="arithmatex">\(log n\)</span> </p>
<p>递归深度就是当前未返回的递归方法的数量。每轮哨兵划分我们将原数组划分为两个子数组。在尾递归优化后,向下递归的子数组长度最大为原数组的一半长度。假设最差情况,一直为一半长度,那么最终的递归深度就是 <span class="arithmatex">\(log n\)</span></p>
<p class="admonition-title">关于尾递归优化,为什么选短的数组能保证递归深度不超过 <span class="arithmatex">\(\log n\)</span> </p>
<p>递归深度就是当前未返回的递归方法的数量。每轮哨兵划分我们将原数组划分为两个子数组。在尾递归优化后,向下递归的子数组长度最大为原数组的一半长度。假设最差情况,一直为一半长度,那么最终的递归深度就是 <span class="arithmatex">\(\log n\)</span></p>
<p>回顾原始的快速排序,我们有可能会连续地递归长度较大的数组,最差情况下为 <span class="arithmatex">\(n, n - 1, n - 2, ..., 2, 1\)</span> ,从而递归深度为 <span class="arithmatex">\(n\)</span> 。尾递归优化可以避免这种情况的出现。</p>
</div>
<div class="admonition question">