mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-06 20:54:19 +00:00
deploy
This commit is contained in:
@@ -3397,7 +3397,7 @@
|
||||
<!-- Page content -->
|
||||
<h1 id="113">11.3 冒泡排序<a class="headerlink" href="#113" title="Permanent link">¶</a></h1>
|
||||
<p>「冒泡排序 bubble sort」通过连续地比较与交换相邻元素实现排序。这个过程就像气泡从底部升到顶部一样,因此得名冒泡排序。</p>
|
||||
<p>如图 11-4 所示,冒泡过程可以利用元素交换操作来模拟:从数组最左端开始向右遍历,依次比较相邻元素大小,如果“左元素 > 右元素”就交换它俩。遍历完成后,最大的元素会被移动到数组的最右端。</p>
|
||||
<p>如图 11-4 所示,冒泡过程可以利用元素交换操作来模拟:从数组最左端开始向右遍历,依次比较相邻元素大小,如果“左元素 > 右元素”就交换二者。遍历完成后,最大的元素会被移动到数组的最右端。</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:7"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1"><1></label><label for="__tabbed_1_2"><2></label><label for="__tabbed_1_3"><3></label><label for="__tabbed_1_4"><4></label><label for="__tabbed_1_5"><5></label><label for="__tabbed_1_6"><6></label><label for="__tabbed_1_7"><7></label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3436,6 +3436,7 @@
|
||||
<p><a class="glightbox" href="../bubble_sort.assets/bubble_sort_overview.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="冒泡排序流程" class="animation-figure" src="../bubble_sort.assets/bubble_sort_overview.png" /></a></p>
|
||||
<p align="center"> 图 11-5 冒泡排序流程 </p>
|
||||
|
||||
<p>示例代码如下:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:12"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><input id="__tabbed_2_7" name="__tabbed_2" type="radio" /><input id="__tabbed_2_8" name="__tabbed_2" type="radio" /><input id="__tabbed_2_9" name="__tabbed_2" type="radio" /><input id="__tabbed_2_10" name="__tabbed_2" type="radio" /><input id="__tabbed_2_11" name="__tabbed_2" type="radio" /><input id="__tabbed_2_12" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">Python</label><label for="__tabbed_2_2">C++</label><label for="__tabbed_2_3">Java</label><label for="__tabbed_2_4">C#</label><label for="__tabbed_2_5">Go</label><label for="__tabbed_2_6">Swift</label><label for="__tabbed_2_7">JS</label><label for="__tabbed_2_8">TS</label><label for="__tabbed_2_9">Dart</label><label for="__tabbed_2_10">Rust</label><label for="__tabbed_2_11">C</label><label for="__tabbed_2_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3649,7 +3650,7 @@
|
||||
</div>
|
||||
<h2 id="1132">11.3.2 效率优化<a class="headerlink" href="#1132" title="Permanent link">¶</a></h2>
|
||||
<p>我们发现,如果某轮“冒泡”中没有执行任何交换操作,说明数组已经完成排序,可直接返回结果。因此,可以增加一个标志位 <code>flag</code> 来监测这种情况,一旦出现就立即返回。</p>
|
||||
<p>经过优化,冒泡排序的最差和平均时间复杂度仍为 <span class="arithmatex">\(O(n^2)\)</span> ;但当输入数组完全有序时,可达到最佳时间复杂度 <span class="arithmatex">\(O(n)\)</span> 。</p>
|
||||
<p>经过优化,冒泡排序的最差时间复杂度和平均时间复杂度仍为 <span class="arithmatex">\(O(n^2)\)</span> ;但当输入数组完全有序时,可达到最佳时间复杂度 <span class="arithmatex">\(O(n)\)</span> 。</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="3:12"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><input id="__tabbed_3_3" name="__tabbed_3" type="radio" /><input id="__tabbed_3_4" name="__tabbed_3" type="radio" /><input id="__tabbed_3_5" name="__tabbed_3" type="radio" /><input id="__tabbed_3_6" name="__tabbed_3" type="radio" /><input id="__tabbed_3_7" name="__tabbed_3" type="radio" /><input id="__tabbed_3_8" name="__tabbed_3" type="radio" /><input id="__tabbed_3_9" name="__tabbed_3" type="radio" /><input id="__tabbed_3_10" name="__tabbed_3" type="radio" /><input id="__tabbed_3_11" name="__tabbed_3" type="radio" /><input id="__tabbed_3_12" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">Python</label><label for="__tabbed_3_2">C++</label><label for="__tabbed_3_3">Java</label><label for="__tabbed_3_4">C#</label><label for="__tabbed_3_5">Go</label><label for="__tabbed_3_6">Swift</label><label for="__tabbed_3_7">JS</label><label for="__tabbed_3_8">TS</label><label for="__tabbed_3_9">Dart</label><label for="__tabbed_3_10">Rust</label><label for="__tabbed_3_11">C</label><label for="__tabbed_3_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 44 KiB |
@@ -3396,18 +3396,19 @@
|
||||
|
||||
<!-- Page content -->
|
||||
<h1 id="118">11.8 桶排序<a class="headerlink" href="#118" title="Permanent link">¶</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 算法流程<a class="headerlink" href="#1181" title="Permanent link">¶</a></h2>
|
||||
<p>考虑一个长度为 <span class="arithmatex">\(n\)</span> 的数组,元素是范围 <span class="arithmatex">\([0, 1)\)</span> 的浮点数。桶排序的流程如图 11-13 所示。</p>
|
||||
<p>考虑一个长度为 <span class="arithmatex">\(n\)</span> 的数组,其元素是范围 <span class="arithmatex">\([0, 1)\)</span> 内的浮点数。桶排序的流程如图 11-13 所示。</p>
|
||||
<ol>
|
||||
<li>初始化 <span class="arithmatex">\(k\)</span> 个桶,将 <span class="arithmatex">\(n\)</span> 个元素分配到 <span class="arithmatex">\(k\)</span> 个桶中。</li>
|
||||
<li>对每个桶分别执行排序(本文采用编程语言的内置排序函数)。</li>
|
||||
<li>按照桶的从小到大的顺序,合并结果。</li>
|
||||
<li>对每个桶分别执行排序(这里采用编程语言的内置排序函数)。</li>
|
||||
<li>按照桶从小到大的顺序合并结果。</li>
|
||||
</ol>
|
||||
<p><a class="glightbox" href="../bucket_sort.assets/bucket_sort_overview.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="桶排序算法流程" class="animation-figure" src="../bucket_sort.assets/bucket_sort_overview.png" /></a></p>
|
||||
<p align="center"> 图 11-13 桶排序算法流程 </p>
|
||||
|
||||
<p>代码如下所示:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:12"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3418,7 +3419,7 @@
|
||||
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a> <span class="n">buckets</span> <span class="o">=</span> <span class="p">[[]</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">k</span><span class="p">)]</span>
|
||||
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a> <span class="c1"># 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a> <span class="k">for</span> <span class="n">num</span> <span class="ow">in</span> <span class="n">nums</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a> <span class="c1"># 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a> <span class="c1"># 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a> <span class="n">i</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">num</span> <span class="o">*</span> <span class="n">k</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a> <span class="c1"># 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a> <span class="n">buckets</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
|
||||
@@ -3442,7 +3443,7 @@
|
||||
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="w"> </span><span class="n">vector</span><span class="o"><</span><span class="n">vector</span><span class="o"><</span><span class="kt">float</span><span class="o">>></span><span class="w"> </span><span class="n">buckets</span><span class="p">(</span><span class="n">k</span><span class="p">);</span>
|
||||
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">k</span><span class="p">;</span>
|
||||
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a><span class="w"> </span><span class="c1">// 将 num 添加进桶 bucket_idx</span>
|
||||
<a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a><span class="w"> </span><span class="n">buckets</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">num</span><span class="p">);</span>
|
||||
@@ -3473,7 +3474,7 @@
|
||||
<a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-2-12" name="__codelineno-2-12" href="#__codelineno-2-12"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="n">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">k</span><span class="p">);</span>
|
||||
<a id="__codelineno-2-13" name="__codelineno-2-13" href="#__codelineno-2-13"></a><span class="w"> </span><span class="c1">// 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-2-14" name="__codelineno-2-14" href="#__codelineno-2-14"></a><span class="w"> </span><span class="n">buckets</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="n">i</span><span class="p">).</span><span class="na">add</span><span class="p">(</span><span class="n">num</span><span class="p">);</span>
|
||||
@@ -3504,7 +3505,7 @@
|
||||
<a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="w"> </span><span class="k">foreach</span><span class="w"> </span><span class="p">(</span><span class="kt">float</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)(</span><span class="n">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">k</span><span class="p">);</span>
|
||||
<a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a><span class="w"> </span><span class="c1">// 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-3-14" name="__codelineno-3-14" href="#__codelineno-3-14"></a><span class="w"> </span><span class="n">buckets</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">Add</span><span class="p">(</span><span class="n">num</span><span class="p">);</span>
|
||||
@@ -3535,7 +3536,7 @@
|
||||
<a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">num</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">nums</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">int</span><span class="p">(</span><span class="nx">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nx">k</span><span class="p">))</span>
|
||||
<a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a><span class="w"> </span><span class="c1">// 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-4-14" name="__codelineno-4-14" href="#__codelineno-4-14"></a><span class="w"> </span><span class="nx">buckets</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">buckets</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">num</span><span class="p">)</span>
|
||||
@@ -3564,7 +3565,7 @@
|
||||
<a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a> <span class="kd">var</span> <span class="nv">buckets</span> <span class="p">=</span> <span class="p">(</span><span class="mi">0</span> <span class="p">..</span><span class="o"><</span> <span class="n">k</span><span class="p">).</span><span class="bp">map</span> <span class="p">{</span> <span class="kc">_</span> <span class="k">in</span> <span class="p">[</span><span class="nb">Double</span><span class="p">]()</span> <span class="p">}</span>
|
||||
<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a> <span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a> <span class="k">for</span> <span class="n">num</span> <span class="k">in</span> <span class="n">nums</span> <span class="p">{</span>
|
||||
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a> <span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a> <span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> <span class="kd">let</span> <span class="nv">i</span> <span class="p">=</span> <span class="nb">Int</span><span class="p">(</span><span class="n">num</span> <span class="o">*</span> <span class="nb">Double</span><span class="p">(</span><span class="n">k</span><span class="p">))</span>
|
||||
<a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a> <span class="c1">// 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a> <span class="n">buckets</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">append</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
|
||||
@@ -3596,7 +3597,7 @@
|
||||
<a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">const</span><span class="w"> </span><span class="nx">num</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nx">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-6-12" name="__codelineno-6-12" href="#__codelineno-6-12"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nx">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nx">k</span><span class="p">);</span>
|
||||
<a id="__codelineno-6-13" name="__codelineno-6-13" href="#__codelineno-6-13"></a><span class="w"> </span><span class="c1">// 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-6-14" name="__codelineno-6-14" href="#__codelineno-6-14"></a><span class="w"> </span><span class="nx">buckets</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">push</span><span class="p">(</span><span class="nx">num</span><span class="p">);</span>
|
||||
@@ -3627,7 +3628,7 @@
|
||||
<a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">const</span><span class="w"> </span><span class="nx">num</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="nx">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nx">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nx">k</span><span class="p">);</span>
|
||||
<a id="__codelineno-7-13" name="__codelineno-7-13" href="#__codelineno-7-13"></a><span class="w"> </span><span class="c1">// 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-7-14" name="__codelineno-7-14" href="#__codelineno-7-14"></a><span class="w"> </span><span class="nx">buckets</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">push</span><span class="p">(</span><span class="nx">num</span><span class="p">);</span>
|
||||
@@ -3656,7 +3657,7 @@
|
||||
<a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a>
|
||||
<a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">double</span><span class="w"> </span><span class="n">_num</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">nums</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 _num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 _num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">_num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">k</span><span class="p">).</span><span class="n">toInt</span><span class="p">();</span>
|
||||
<a id="__codelineno-8-11" name="__codelineno-8-11" href="#__codelineno-8-11"></a><span class="w"> </span><span class="c1">// 将 _num 添加进桶 bucket_idx</span>
|
||||
<a id="__codelineno-8-12" name="__codelineno-8-12" href="#__codelineno-8-12"></a><span class="w"> </span><span class="n">buckets</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">add</span><span class="p">(</span><span class="n">_num</span><span class="p">);</span>
|
||||
@@ -3683,7 +3684,7 @@
|
||||
<a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">buckets</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="fm">vec!</span><span class="p">[];</span><span class="w"> </span><span class="n">k</span><span class="p">];</span>
|
||||
<a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="n">num</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="o">*</span><span class="n">nums</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">num</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">f64</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">;</span>
|
||||
<a id="__codelineno-9-10" name="__codelineno-9-10" href="#__codelineno-9-10"></a><span class="w"> </span><span class="c1">// 将 num 添加进桶 i</span>
|
||||
<a id="__codelineno-9-11" name="__codelineno-9-11" href="#__codelineno-9-11"></a><span class="w"> </span><span class="n">buckets</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">push</span><span class="p">(</span><span class="n">num</span><span class="p">);</span>
|
||||
@@ -3717,7 +3718,7 @@
|
||||
<a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a>
|
||||
<a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a><span class="w"> </span><span class="c1">// 1. 将数组元素分配到各个桶中</span>
|
||||
<a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a><span class="w"> </span><span class="c1">// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a><span class="w"> </span><span class="c1">// 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1]</span>
|
||||
<a id="__codelineno-10-14" name="__codelineno-10-14" href="#__codelineno-10-14"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">bucket_idx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">k</span><span class="p">;</span>
|
||||
<a id="__codelineno-10-15" name="__codelineno-10-15" href="#__codelineno-10-15"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
|
||||
<a id="__codelineno-10-16" name="__codelineno-10-16" href="#__codelineno-10-16"></a><span class="w"> </span><span class="c1">// 如果桶中有数据且数据小于当前值 nums[i], 要将其放到当前桶的后面,相当于 cpp 中的 push_back</span>
|
||||
@@ -3764,14 +3765,14 @@
|
||||
<p>桶排序适用于处理体量很大的数据。例如,输入数据包含 100 万个元素,由于空间限制,系统内存无法一次性加载所有数据。此时,可以将数据分成 1000 个桶,然后分别对每个桶进行排序,最后将结果合并。</p>
|
||||
<ul>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n + k)\)</span></strong> :假设元素在各个桶内平均分布,那么每个桶内的元素数量为 <span class="arithmatex">\(\frac{n}{k}\)</span> 。假设排序单个桶使用 <span class="arithmatex">\(O(\frac{n}{k} \log\frac{n}{k})\)</span> 时间,则排序所有桶使用 <span class="arithmatex">\(O(n \log\frac{n}{k})\)</span> 时间。<strong>当桶数量 <span class="arithmatex">\(k\)</span> 比较大时,时间复杂度则趋向于 <span class="arithmatex">\(O(n)\)</span></strong> 。合并结果时需要遍历所有桶和元素,花费 <span class="arithmatex">\(O(n + k)\)</span> 时间。</li>
|
||||
<li><strong>自适应排序</strong>:在最坏情况下,所有数据被分配到一个桶中,且排序该桶使用 <span class="arithmatex">\(O(n^2)\)</span> 时间。</li>
|
||||
<li><strong>自适应排序</strong>:在最差情况下,所有数据被分配到一个桶中,且排序该桶使用 <span class="arithmatex">\(O(n^2)\)</span> 时间。</li>
|
||||
<li><strong>空间复杂度 <span class="arithmatex">\(O(n + k)\)</span>、非原地排序</strong>:需要借助 <span class="arithmatex">\(k\)</span> 个桶和总共 <span class="arithmatex">\(n\)</span> 个元素的额外空间。</li>
|
||||
<li>桶排序是否稳定取决于排序桶内元素的算法是否稳定。</li>
|
||||
</ul>
|
||||
<h2 id="1183">11.8.3 如何实现平均分配<a class="headerlink" href="#1183" title="Permanent link">¶</a></h2>
|
||||
<p>桶排序的时间复杂度理论上可以达到 <span class="arithmatex">\(O(n)\)</span> ,<strong>关键在于将元素均匀分配到各个桶中</strong>,因为实际数据往往不是均匀分布的。例如,我们想要将淘宝上的所有商品按价格范围平均分配到 10 个桶中,但商品价格分布不均,低于 100 元的非常多,高于 1000 元的非常少。若将价格区间平均划分为 10 份,各个桶中的商品数量差距会非常大。</p>
|
||||
<p>为实现平均分配,我们可以先设定一个大致的分界线,将数据粗略地分到 3 个桶中。<strong>分配完毕后,再将商品较多的桶继续划分为 3 个桶,直至所有桶中的元素数量大致相等</strong>。</p>
|
||||
<p>如图 11-14 所示,这种方法本质上是创建一个递归树,目标是让叶节点的值尽可能平均。当然,不一定要每轮将数据划分为 3 个桶,具体划分方式可根据数据特点灵活选择。</p>
|
||||
<p>桶排序的时间复杂度理论上可以达到 <span class="arithmatex">\(O(n)\)</span> ,<strong>关键在于将元素均匀分配到各个桶中</strong>,因为实际数据往往不是均匀分布的。例如,我们想要将淘宝上的所有商品按价格范围平均分配到 10 个桶中,但商品价格分布不均,低于 100 元的非常多,高于 1000 元的非常少。若将价格区间平均划分为 10 个,各个桶中的商品数量差距会非常大。</p>
|
||||
<p>为实现平均分配,我们可以先设定一条大致的分界线,将数据粗略地分到 3 个桶中。<strong>分配完毕后,再将商品较多的桶继续划分为 3 个桶,直至所有桶中的元素数量大致相等</strong>。</p>
|
||||
<p>如图 11-14 所示,这种方法本质上是创建一棵递归树,目标是让叶节点的值尽可能平均。当然,不一定要每轮将数据划分为 3 个桶,具体划分方式可根据数据特点灵活选择。</p>
|
||||
<p><a class="glightbox" href="../bucket_sort.assets/scatter_in_buckets_recursively.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="递归划分桶" class="animation-figure" src="../bucket_sort.assets/scatter_in_buckets_recursively.png" /></a></p>
|
||||
<p align="center"> 图 11-14 递归划分桶 </p>
|
||||
|
||||
|
||||
@@ -3414,13 +3414,14 @@
|
||||
<h2 id="1191">11.9.1 简单实现<a class="headerlink" href="#1191" title="Permanent link">¶</a></h2>
|
||||
<p>先来看一个简单的例子。给定一个长度为 <span class="arithmatex">\(n\)</span> 的数组 <code>nums</code> ,其中的元素都是“非负整数”,计数排序的整体流程如图 11-16 所示。</p>
|
||||
<ol>
|
||||
<li>遍历数组,找出数组中的最大数字,记为 <span class="arithmatex">\(m\)</span> ,然后创建一个长度为 <span class="arithmatex">\(m + 1\)</span> 的辅助数组 <code>counter</code> 。</li>
|
||||
<li>遍历数组,找出其中的最大数字,记为 <span class="arithmatex">\(m\)</span> ,然后创建一个长度为 <span class="arithmatex">\(m + 1\)</span> 的辅助数组 <code>counter</code> 。</li>
|
||||
<li><strong>借助 <code>counter</code> 统计 <code>nums</code> 中各数字的出现次数</strong>,其中 <code>counter[num]</code> 对应数字 <code>num</code> 的出现次数。统计方法很简单,只需遍历 <code>nums</code>(设当前数字为 <code>num</code>),每轮将 <code>counter[num]</code> 增加 <span class="arithmatex">\(1\)</span> 即可。</li>
|
||||
<li><strong>由于 <code>counter</code> 的各个索引天然有序,因此相当于所有数字已经被排序好了</strong>。接下来,我们遍历 <code>counter</code> ,根据各数字的出现次数,将它们按从小到大的顺序填入 <code>nums</code> 即可。</li>
|
||||
<li><strong>由于 <code>counter</code> 的各个索引天然有序,因此相当于所有数字已经排序好了</strong>。接下来,我们遍历 <code>counter</code> ,根据各数字出现次数从小到大的顺序填入 <code>nums</code> 即可。</li>
|
||||
</ol>
|
||||
<p><a class="glightbox" href="../counting_sort.assets/counting_sort_overview.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="计数排序流程" class="animation-figure" src="../counting_sort.assets/counting_sort_overview.png" /></a></p>
|
||||
<p align="center"> 图 11-16 计数排序流程 </p>
|
||||
|
||||
<p>代码如下所示:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:12"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3704,10 +3705,10 @@
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">计数排序与桶排序的联系</p>
|
||||
<p>从桶排序的角度看,我们可以将计数排序中的计数数组 <code>counter</code> 的每个索引视为一个桶,将统计数量的过程看作是将各个元素分配到对应的桶中。本质上,计数排序是桶排序在整型数据下的一个特例。</p>
|
||||
<p>从桶排序的角度看,我们可以将计数排序中的计数数组 <code>counter</code> 的每个索引视为一个桶,将统计数量的过程看作将各个元素分配到对应的桶中。本质上,计数排序是桶排序在整型数据下的一个特例。</p>
|
||||
</div>
|
||||
<h2 id="1192">11.9.2 完整实现<a class="headerlink" href="#1192" title="Permanent link">¶</a></h2>
|
||||
<p>细心的同学可能发现,<strong>如果输入数据是对象,上述步骤 <code>3.</code> 就失效了</strong>。假设输入数据是商品对象,我们想要按照商品价格(类的成员变量)对商品进行排序,而上述算法只能给出价格的排序结果。</p>
|
||||
<p>细心的读者可能发现了,<strong>如果输入数据是对象,上述步骤 <code>3.</code> 就失效了</strong>。假设输入数据是商品对象,我们想按照商品价格(类的成员变量)对商品进行排序,而上述算法只能给出价格的排序结果。</p>
|
||||
<p>那么如何才能得到原数据的排序结果呢?我们首先计算 <code>counter</code> 的“前缀和”。顾名思义,索引 <code>i</code> 处的前缀和 <code>prefix[i]</code> 等于数组前 <code>i</code> 个元素之和:</p>
|
||||
<div class="arithmatex">\[
|
||||
\text{prefix}[i] = \sum_{j=0}^i \text{counter[j]}
|
||||
@@ -3748,7 +3749,7 @@
|
||||
</div>
|
||||
<p align="center"> 图 11-17 计数排序步骤 </p>
|
||||
|
||||
<p>计数排序的实现代码如下所示。</p>
|
||||
<p>计数排序的实现代码如下所示:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="3:12"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><input id="__tabbed_3_3" name="__tabbed_3" type="radio" /><input id="__tabbed_3_4" name="__tabbed_3" type="radio" /><input id="__tabbed_3_5" name="__tabbed_3" type="radio" /><input id="__tabbed_3_6" name="__tabbed_3" type="radio" /><input id="__tabbed_3_7" name="__tabbed_3" type="radio" /><input id="__tabbed_3_8" name="__tabbed_3" type="radio" /><input id="__tabbed_3_9" name="__tabbed_3" type="radio" /><input id="__tabbed_3_10" name="__tabbed_3" type="radio" /><input id="__tabbed_3_11" name="__tabbed_3" type="radio" /><input id="__tabbed_3_12" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">Python</label><label for="__tabbed_3_2">C++</label><label for="__tabbed_3_3">Java</label><label for="__tabbed_3_4">C#</label><label for="__tabbed_3_5">Go</label><label for="__tabbed_3_6">Swift</label><label for="__tabbed_3_7">JS</label><label for="__tabbed_3_8">TS</label><label for="__tabbed_3_9">Dart</label><label for="__tabbed_3_10">Rust</label><label for="__tabbed_3_11">C</label><label for="__tabbed_3_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -4144,8 +4145,8 @@
|
||||
<li><strong>稳定排序</strong>:由于向 <code>res</code> 中填充元素的顺序是“从右向左”的,因此倒序遍历 <code>nums</code> 可以避免改变相等元素之间的相对位置,从而实现稳定排序。实际上,正序遍历 <code>nums</code> 也可以得到正确的排序结果,但结果是非稳定的。</li>
|
||||
</ul>
|
||||
<h2 id="1194">11.9.4 局限性<a class="headerlink" href="#1194" title="Permanent link">¶</a></h2>
|
||||
<p>看到这里,你也许会觉得计数排序非常巧妙,仅通过统计数量就可以实现高效的排序工作。然而,使用计数排序的前置条件相对较为严格。</p>
|
||||
<p><strong>计数排序只适用于非负整数</strong>。若想要将其用于其他类型的数据,需要确保这些数据可以被转换为非负整数,并且在转换过程中不能改变各个元素之间的相对大小关系。例如,对于包含负数的整数数组,可以先给所有数字加上一个常数,将全部数字转化为正数,排序完成后再转换回去即可。</p>
|
||||
<p>看到这里,你也许会觉得计数排序非常巧妙,仅通过统计数量就可以实现高效的排序。然而,使用计数排序的前置条件相对较为严格。</p>
|
||||
<p><strong>计数排序只适用于非负整数</strong>。若想将其用于其他类型的数据,需要确保这些数据可以转换为非负整数,并且在转换过程中不能改变各个元素之间的相对大小关系。例如,对于包含负数的整数数组,可以先给所有数字加上一个常数,将全部数字转化为正数,排序完成后再转换回去。</p>
|
||||
<p><strong>计数排序适用于数据量大但数据范围较小的情况</strong>。比如,在上述示例中 <span class="arithmatex">\(m\)</span> 不能太大,否则会占用过多空间。而当 <span class="arithmatex">\(n \ll m\)</span> 时,计数排序使用 <span class="arithmatex">\(O(m)\)</span> 时间,可能比 <span class="arithmatex">\(O(n \log n)\)</span> 的排序算法还要慢。</p>
|
||||
|
||||
<!-- Source file information -->
|
||||
|
||||
@@ -3398,11 +3398,11 @@
|
||||
<li>输入数组并建立大顶堆。完成后,最大元素位于堆顶。</li>
|
||||
<li>将堆顶元素(第一个元素)与堆底元素(最后一个元素)交换。完成交换后,堆的长度减 <span class="arithmatex">\(1\)</span> ,已排序元素数量加 <span class="arithmatex">\(1\)</span> 。</li>
|
||||
<li>从堆顶元素开始,从顶到底执行堆化操作(Sift Down)。完成堆化后,堆的性质得到修复。</li>
|
||||
<li>循环执行第 <code>2.</code> 和 <code>3.</code> 步。循环 <span class="arithmatex">\(n - 1\)</span> 轮后,即可完成数组排序。</li>
|
||||
<li>循环执行第 <code>2.</code> 步和第 <code>3.</code> 步。循环 <span class="arithmatex">\(n - 1\)</span> 轮后,即可完成数组排序。</li>
|
||||
</ol>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>实际上,元素出堆操作中也包含第 <code>2.</code> 和 <code>3.</code> 步,只是多了一个弹出元素的步骤。</p>
|
||||
<p>实际上,元素出堆操作中也包含第 <code>2.</code> 步和第 <code>3.</code> 步,只是多了一个弹出元素的步骤。</p>
|
||||
</div>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:12"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1"><1></label><label for="__tabbed_1_2"><2></label><label for="__tabbed_1_3"><3></label><label for="__tabbed_1_4"><4></label><label for="__tabbed_1_5"><5></label><label for="__tabbed_1_6"><6></label><label for="__tabbed_1_7"><7></label><label for="__tabbed_1_8"><8></label><label for="__tabbed_1_9"><9></label><label for="__tabbed_1_10"><10></label><label for="__tabbed_1_11"><11></label><label for="__tabbed_1_12"><12></label></div>
|
||||
<div class="tabbed-content">
|
||||
@@ -3446,7 +3446,7 @@
|
||||
</div>
|
||||
<p align="center"> 图 11-12 堆排序步骤 </p>
|
||||
|
||||
<p>在代码实现中,我们使用了与堆章节相同的从顶至底堆化 <code>sift_down()</code> 函数。值得注意的是,由于堆的长度会随着提取最大元素而减小,因此我们需要给 <code>sift_down()</code> 函数添加一个长度参数 <span class="arithmatex">\(n\)</span> ,用于指定堆的当前有效长度。</p>
|
||||
<p>在代码实现中,我们使用了与“堆”章节相同的从顶至底堆化 <code>sift_down()</code> 函数。值得注意的是,由于堆的长度会随着提取最大元素而减小,因此我们需要给 <code>sift_down()</code> 函数添加一个长度参数 <span class="arithmatex">\(n\)</span> ,用于指定堆的当前有效长度。代码如下所示:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:12"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><input id="__tabbed_2_7" name="__tabbed_2" type="radio" /><input id="__tabbed_2_8" name="__tabbed_2" type="radio" /><input id="__tabbed_2_9" name="__tabbed_2" type="radio" /><input id="__tabbed_2_10" name="__tabbed_2" type="radio" /><input id="__tabbed_2_11" name="__tabbed_2" type="radio" /><input id="__tabbed_2_12" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">Python</label><label for="__tabbed_2_2">C++</label><label for="__tabbed_2_3">Java</label><label for="__tabbed_2_4">C#</label><label for="__tabbed_2_5">Go</label><label for="__tabbed_2_6">Swift</label><label for="__tabbed_2_7">JS</label><label for="__tabbed_2_8">TS</label><label for="__tabbed_2_9">Dart</label><label for="__tabbed_2_10">Rust</label><label for="__tabbed_2_11">C</label><label for="__tabbed_2_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3476,7 +3476,7 @@
|
||||
<a id="__codelineno-0-24" name="__codelineno-0-24" href="#__codelineno-0-24"></a> <span class="n">sift_down</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">nums</span><span class="p">),</span> <span class="n">i</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-25" name="__codelineno-0-25" href="#__codelineno-0-25"></a> <span class="c1"># 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-0-26" name="__codelineno-0-26" href="#__codelineno-0-26"></a> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">nums</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></a> <span class="c1"># 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></a> <span class="c1"># 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-0-28" name="__codelineno-0-28" href="#__codelineno-0-28"></a> <span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<a id="__codelineno-0-29" name="__codelineno-0-29" href="#__codelineno-0-29"></a> <span class="c1"># 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-0-30" name="__codelineno-0-30" href="#__codelineno-0-30"></a> <span class="n">sift_down</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||||
@@ -3513,7 +3513,7 @@
|
||||
<a id="__codelineno-1-28" name="__codelineno-1-28" href="#__codelineno-1-28"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-1-29" name="__codelineno-1-29" href="#__codelineno-1-29"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-1-30" name="__codelineno-1-30" href="#__codelineno-1-30"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="o">--</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-31" name="__codelineno-1-31" href="#__codelineno-1-31"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-1-31" name="__codelineno-1-31" href="#__codelineno-1-31"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-1-32" name="__codelineno-1-32" href="#__codelineno-1-32"></a><span class="w"> </span><span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
|
||||
<a id="__codelineno-1-33" name="__codelineno-1-33" href="#__codelineno-1-33"></a><span class="w"> </span><span class="c1">// 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-1-34" name="__codelineno-1-34" href="#__codelineno-1-34"></a><span class="w"> </span><span class="n">siftDown</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
|
||||
@@ -3553,7 +3553,7 @@
|
||||
<a id="__codelineno-2-29" name="__codelineno-2-29" href="#__codelineno-2-29"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-2-30" name="__codelineno-2-30" href="#__codelineno-2-30"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-2-31" name="__codelineno-2-31" href="#__codelineno-2-31"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="na">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-2-32" name="__codelineno-2-32" href="#__codelineno-2-32"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-2-32" name="__codelineno-2-32" href="#__codelineno-2-32"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-2-33" name="__codelineno-2-33" href="#__codelineno-2-33"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">tmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span><span class="p">;</span>
|
||||
<a id="__codelineno-2-34" name="__codelineno-2-34" href="#__codelineno-2-34"></a><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="p">;</span>
|
||||
<a id="__codelineno-2-35" name="__codelineno-2-35" href="#__codelineno-2-35"></a><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span>
|
||||
@@ -3593,7 +3593,7 @@
|
||||
<a id="__codelineno-3-27" name="__codelineno-3-27" href="#__codelineno-3-27"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-3-28" name="__codelineno-3-28" href="#__codelineno-3-28"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-3-29" name="__codelineno-3-29" href="#__codelineno-3-29"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">Length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="m">1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="m">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-3-30" name="__codelineno-3-30" href="#__codelineno-3-30"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-3-30" name="__codelineno-3-30" href="#__codelineno-3-30"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-3-31" name="__codelineno-3-31" href="#__codelineno-3-31"></a><span class="w"> </span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="m">0</span><span class="p">])</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">nums</span><span class="p">[</span><span class="m">0</span><span class="p">],</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
|
||||
<a id="__codelineno-3-32" name="__codelineno-3-32" href="#__codelineno-3-32"></a><span class="w"> </span><span class="c1">// 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-3-33" name="__codelineno-3-33" href="#__codelineno-3-33"></a><span class="w"> </span><span class="n">SiftDown</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">);</span>
|
||||
@@ -3634,7 +3634,7 @@
|
||||
<a id="__codelineno-4-30" name="__codelineno-4-30" href="#__codelineno-4-30"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-4-31" name="__codelineno-4-31" href="#__codelineno-4-31"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-4-32" name="__codelineno-4-32" href="#__codelineno-4-32"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="o">*</span><span class="nx">nums</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">></span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">--</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-4-33" name="__codelineno-4-33" href="#__codelineno-4-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-4-33" name="__codelineno-4-33" href="#__codelineno-4-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-4-34" name="__codelineno-4-34" href="#__codelineno-4-34"></a><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">nums</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">nums</span><span class="p">)[</span><span class="nx">i</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">nums</span><span class="p">)[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">nums</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<a id="__codelineno-4-35" name="__codelineno-4-35" href="#__codelineno-4-35"></a><span class="w"> </span><span class="c1">// 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-4-36" name="__codelineno-4-36" href="#__codelineno-4-36"></a><span class="w"> </span><span class="nx">siftDown</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span>
|
||||
@@ -3676,7 +3676,7 @@
|
||||
<a id="__codelineno-5-31" name="__codelineno-5-31" href="#__codelineno-5-31"></a> <span class="p">}</span>
|
||||
<a id="__codelineno-5-32" name="__codelineno-5-32" href="#__codelineno-5-32"></a> <span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-5-33" name="__codelineno-5-33" href="#__codelineno-5-33"></a> <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="bp">stride</span><span class="p">(</span><span class="n">from</span><span class="p">:</span> <span class="n">nums</span><span class="p">.</span><span class="bp">count</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">to</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="n">by</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
|
||||
<a id="__codelineno-5-34" name="__codelineno-5-34" href="#__codelineno-5-34"></a> <span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-5-34" name="__codelineno-5-34" href="#__codelineno-5-34"></a> <span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-5-35" name="__codelineno-5-35" href="#__codelineno-5-35"></a> <span class="n">nums</span><span class="p">.</span><span class="n">swapAt</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
|
||||
<a id="__codelineno-5-36" name="__codelineno-5-36" href="#__codelineno-5-36"></a> <span class="c1">// 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-5-37" name="__codelineno-5-37" href="#__codelineno-5-37"></a> <span class="n">siftDown</span><span class="p">(</span><span class="n">nums</span><span class="p">:</span> <span class="p">&</span><span class="n">nums</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="n">i</span><span class="p">,</span> <span class="n">i</span><span class="p">:</span> <span class="mi">0</span><span class="p">)</span>
|
||||
@@ -3717,7 +3717,7 @@
|
||||
<a id="__codelineno-6-30" name="__codelineno-6-30" href="#__codelineno-6-30"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-6-31" name="__codelineno-6-31" href="#__codelineno-6-31"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-6-32" name="__codelineno-6-32" href="#__codelineno-6-32"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">nums</span><span class="p">.</span><span class="nx">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mf">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-6-33" name="__codelineno-6-33" href="#__codelineno-6-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-6-33" name="__codelineno-6-33" href="#__codelineno-6-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-6-34" name="__codelineno-6-34" href="#__codelineno-6-34"></a><span class="w"> </span><span class="p">[</span><span class="nx">nums</span><span class="p">[</span><span class="mf">0</span><span class="p">],</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">i</span><span class="p">]]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="nx">nums</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="mf">0</span><span class="p">]];</span>
|
||||
<a id="__codelineno-6-35" name="__codelineno-6-35" href="#__codelineno-6-35"></a><span class="w"> </span><span class="c1">// 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-6-36" name="__codelineno-6-36" href="#__codelineno-6-36"></a><span class="w"> </span><span class="nx">siftDown</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="mf">0</span><span class="p">);</span>
|
||||
@@ -3758,7 +3758,7 @@
|
||||
<a id="__codelineno-7-30" name="__codelineno-7-30" href="#__codelineno-7-30"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-7-31" name="__codelineno-7-31" href="#__codelineno-7-31"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-7-32" name="__codelineno-7-32" href="#__codelineno-7-32"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">nums</span><span class="p">.</span><span class="nx">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mf">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-7-33" name="__codelineno-7-33" href="#__codelineno-7-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-7-33" name="__codelineno-7-33" href="#__codelineno-7-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-7-34" name="__codelineno-7-34" href="#__codelineno-7-34"></a><span class="w"> </span><span class="p">[</span><span class="nx">nums</span><span class="p">[</span><span class="mf">0</span><span class="p">],</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">i</span><span class="p">]]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="nx">nums</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="mf">0</span><span class="p">]];</span>
|
||||
<a id="__codelineno-7-35" name="__codelineno-7-35" href="#__codelineno-7-35"></a><span class="w"> </span><span class="c1">// 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-7-36" name="__codelineno-7-36" href="#__codelineno-7-36"></a><span class="w"> </span><span class="nx">siftDown</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="mf">0</span><span class="p">);</span>
|
||||
@@ -3795,7 +3795,7 @@
|
||||
<a id="__codelineno-8-26" name="__codelineno-8-26" href="#__codelineno-8-26"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-8-27" name="__codelineno-8-27" href="#__codelineno-8-27"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-8-28" name="__codelineno-8-28" href="#__codelineno-8-28"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">length</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="m">1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="m">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">--</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-8-29" name="__codelineno-8-29" href="#__codelineno-8-29"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-8-29" name="__codelineno-8-29" href="#__codelineno-8-29"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-8-30" name="__codelineno-8-30" href="#__codelineno-8-30"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">tmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="m">0</span><span class="p">];</span>
|
||||
<a id="__codelineno-8-31" name="__codelineno-8-31" href="#__codelineno-8-31"></a><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="m">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
|
||||
<a id="__codelineno-8-32" name="__codelineno-8-32" href="#__codelineno-8-32"></a><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span>
|
||||
@@ -3840,7 +3840,7 @@
|
||||
<a id="__codelineno-9-32" name="__codelineno-9-32" href="#__codelineno-9-32"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-9-33" name="__codelineno-9-33" href="#__codelineno-9-33"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-9-34" name="__codelineno-9-34" href="#__codelineno-9-34"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="o">..=</span><span class="n">nums</span><span class="p">.</span><span class="n">len</span><span class="p">()</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">).</span><span class="n">rev</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-9-35" name="__codelineno-9-35" href="#__codelineno-9-35"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-9-35" name="__codelineno-9-35" href="#__codelineno-9-35"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-9-36" name="__codelineno-9-36" href="#__codelineno-9-36"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">tmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
|
||||
<a id="__codelineno-9-37" name="__codelineno-9-37" href="#__codelineno-9-37"></a><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
|
||||
<a id="__codelineno-9-38" name="__codelineno-9-38" href="#__codelineno-9-38"></a><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span>
|
||||
@@ -3883,7 +3883,7 @@
|
||||
<a id="__codelineno-10-30" name="__codelineno-10-30" href="#__codelineno-10-30"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-10-31" name="__codelineno-10-31" href="#__codelineno-10-31"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-10-32" name="__codelineno-10-32" href="#__codelineno-10-32"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="o">--</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-10-33" name="__codelineno-10-33" href="#__codelineno-10-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-10-33" name="__codelineno-10-33" href="#__codelineno-10-33"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-10-34" name="__codelineno-10-34" href="#__codelineno-10-34"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">tmp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
|
||||
<a id="__codelineno-10-35" name="__codelineno-10-35" href="#__codelineno-10-35"></a><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
|
||||
<a id="__codelineno-10-36" name="__codelineno-10-36" href="#__codelineno-10-36"></a><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span>
|
||||
|
||||
@@ -3398,7 +3398,7 @@
|
||||
<h1 id="114">11.4 插入排序<a class="headerlink" href="#114" title="Permanent link">¶</a></h1>
|
||||
<p>「插入排序 insertion sort」是一种简单的排序算法,它的工作原理与手动整理一副牌的过程非常相似。</p>
|
||||
<p>具体来说,我们在未排序区间选择一个基准元素,将该元素与其左侧已排序区间的元素逐一比较大小,并将该元素插入到正确的位置。</p>
|
||||
<p>图 11-6 展示了数组插入元素的操作流程。设基准元素为 <code>base</code> ,我们需要将从目标索引到 <code>base</code> 之间的所有元素向右移动一位,然后再将 <code>base</code> 赋值给目标索引。</p>
|
||||
<p>图 11-6 展示了数组插入元素的操作流程。设基准元素为 <code>base</code> ,我们需要将从目标索引到 <code>base</code> 之间的所有元素向右移动一位,然后将 <code>base</code> 赋值给目标索引。</p>
|
||||
<p><a class="glightbox" href="../insertion_sort.assets/insertion_operation.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="单次插入操作" class="animation-figure" src="../insertion_sort.assets/insertion_operation.png" /></a></p>
|
||||
<p align="center"> 图 11-6 单次插入操作 </p>
|
||||
|
||||
@@ -3413,6 +3413,7 @@
|
||||
<p><a class="glightbox" href="../insertion_sort.assets/insertion_sort_overview.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="插入排序流程" class="animation-figure" src="../insertion_sort.assets/insertion_sort_overview.png" /></a></p>
|
||||
<p align="center"> 图 11-7 插入排序流程 </p>
|
||||
|
||||
<p>示例代码如下:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:12"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3616,14 +3617,14 @@
|
||||
</div>
|
||||
<h2 id="1142">11.4.2 算法特性<a class="headerlink" href="#1142" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n^2)\)</span>、自适应排序</strong>:最差情况下,每次插入操作分别需要循环 <span class="arithmatex">\(n - 1\)</span>、<span class="arithmatex">\(n-2\)</span>、<span class="arithmatex">\(\dots\)</span>、<span class="arithmatex">\(2\)</span>、<span class="arithmatex">\(1\)</span> 次,求和得到 <span class="arithmatex">\((n - 1) n / 2\)</span> ,因此时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> 。在遇到有序数据时,插入操作会提前终止。当输入数组完全有序时,插入排序达到最佳时间复杂度 <span class="arithmatex">\(O(n)\)</span> 。</li>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n^2)\)</span>、自适应排序</strong>:在最差情况下,每次插入操作分别需要循环 <span class="arithmatex">\(n - 1\)</span>、<span class="arithmatex">\(n-2\)</span>、<span class="arithmatex">\(\dots\)</span>、<span class="arithmatex">\(2\)</span>、<span class="arithmatex">\(1\)</span> 次,求和得到 <span class="arithmatex">\((n - 1) n / 2\)</span> ,因此时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> 。在遇到有序数据时,插入操作会提前终止。当输入数组完全有序时,插入排序达到最佳时间复杂度 <span class="arithmatex">\(O(n)\)</span> 。</li>
|
||||
<li><strong>空间复杂度 <span class="arithmatex">\(O(1)\)</span>、原地排序</strong>:指针 <span class="arithmatex">\(i\)</span> 和 <span class="arithmatex">\(j\)</span> 使用常数大小的额外空间。</li>
|
||||
<li><strong>稳定排序</strong>:在插入操作过程中,我们会将元素插入到相等元素的右侧,不会改变它们的顺序。</li>
|
||||
</ul>
|
||||
<h2 id="1143">11.4.3 插入排序优势<a class="headerlink" href="#1143" title="Permanent link">¶</a></h2>
|
||||
<p>插入排序的时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> ,而我们即将学习的快速排序的时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span> 。尽管插入排序的时间复杂度相比快速排序更高,<strong>但在数据量较小的情况下,插入排序通常更快</strong>。</p>
|
||||
<p>这个结论与线性查找和二分查找的适用情况的结论类似。快速排序这类 <span class="arithmatex">\(O(n \log n)\)</span> 的算法属于基于分治的排序算法,往往包含更多单元计算操作。而在数据量较小时,<span class="arithmatex">\(n^2\)</span> 和 <span class="arithmatex">\(n \log n\)</span> 的数值比较接近,复杂度不占主导作用;每轮中的单元操作数量起到决定性因素。</p>
|
||||
<p>实际上,许多编程语言(例如 Java)的内置排序函数都采用了插入排序,大致思路为:对于长数组,采用基于分治的排序算法,例如快速排序;对于短数组,直接使用插入排序。</p>
|
||||
<p>插入排序的时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> ,而我们即将学习的快速排序的时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span> 。尽管插入排序的时间复杂度更高,<strong>但在数据量较小的情况下,插入排序通常更快</strong>。</p>
|
||||
<p>这个结论与线性查找和二分查找的适用情况的结论类似。快速排序这类 <span class="arithmatex">\(O(n \log n)\)</span> 的算法属于基于分治策略的排序算法,往往包含更多单元计算操作。而在数据量较小时,<span class="arithmatex">\(n^2\)</span> 和 <span class="arithmatex">\(n \log n\)</span> 的数值比较接近,复杂度不占主导地位;每轮中的单元操作数量起到决定性作用。</p>
|
||||
<p>实际上,许多编程语言(例如 Java)的内置排序函数采用了插入排序,大致思路为:对于长数组,采用基于分治策略的排序算法,例如快速排序;对于短数组,直接使用插入排序。</p>
|
||||
<p>虽然冒泡排序、选择排序和插入排序的时间复杂度都为 <span class="arithmatex">\(O(n^2)\)</span> ,但在实际情况中,<strong>插入排序的使用频率显著高于冒泡排序和选择排序</strong>,主要有以下原因。</p>
|
||||
<ul>
|
||||
<li>冒泡排序基于元素交换实现,需要借助一个临时变量,共涉及 3 个单元操作;插入排序基于元素赋值实现,仅需 1 个单元操作。因此,<strong>冒泡排序的计算开销通常比插入排序更高</strong>。</li>
|
||||
|
||||
@@ -2266,7 +2266,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1163" class="md-nav__link">
|
||||
11.6.3 链表排序 *
|
||||
11.6.3 链表排序
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -3335,7 +3335,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1163" class="md-nav__link">
|
||||
11.6.3 链表排序 *
|
||||
11.6.3 链表排序
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -3408,7 +3408,7 @@
|
||||
<p>如图 11-11 所示,“划分阶段”从顶至底递归地将数组从中点切分为两个子数组。</p>
|
||||
<ol>
|
||||
<li>计算数组中点 <code>mid</code> ,递归划分左子数组(区间 <code>[left, mid]</code> )和右子数组(区间 <code>[mid + 1, right]</code> )。</li>
|
||||
<li>递归执行步骤 <code>1.</code> ,直至子数组区间长度为 1 时,终止递归划分。</li>
|
||||
<li>递归执行步骤 <code>1.</code> ,直至子数组区间长度为 1 时终止。</li>
|
||||
</ol>
|
||||
<p>“合并阶段”从底至顶地将左子数组和右子数组合并为一个有序数组。需要注意的是,从长度为 1 的子数组开始合并,合并阶段中的每个子数组都是有序的。</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:10"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1"><1></label><label for="__tabbed_1_2"><2></label><label for="__tabbed_1_3"><3></label><label for="__tabbed_1_4"><4></label><label for="__tabbed_1_5"><5></label><label for="__tabbed_1_6"><6></label><label for="__tabbed_1_7"><7></label><label for="__tabbed_1_8"><8></label><label for="__tabbed_1_9"><9></label><label for="__tabbed_1_10"><10></label></div>
|
||||
@@ -3452,6 +3452,7 @@
|
||||
<li><strong>后序遍历</strong>:先递归左子树,再递归右子树,最后处理根节点。</li>
|
||||
<li><strong>归并排序</strong>:先递归左子数组,再递归右子数组,最后处理合并。</li>
|
||||
</ul>
|
||||
<p>归并排序的实现如以下代码所示。请注意,<code>nums</code> 的待合并区间为 <code>[left, right]</code> ,而 <code>tmp</code> 的对应区间为 <code>[0, right - left]</code> 。</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:12"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><input id="__tabbed_2_7" name="__tabbed_2" type="radio" /><input id="__tabbed_2_8" name="__tabbed_2" type="radio" /><input id="__tabbed_2_9" name="__tabbed_2" type="radio" /><input id="__tabbed_2_10" name="__tabbed_2" type="radio" /><input id="__tabbed_2_11" name="__tabbed_2" type="radio" /><input id="__tabbed_2_12" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">Python</label><label for="__tabbed_2_2">C++</label><label for="__tabbed_2_3">Java</label><label for="__tabbed_2_4">C#</label><label for="__tabbed_2_5">Go</label><label for="__tabbed_2_6">Swift</label><label for="__tabbed_2_7">JS</label><label for="__tabbed_2_8">TS</label><label for="__tabbed_2_9">Dart</label><label for="__tabbed_2_10">Rust</label><label for="__tabbed_2_11">C</label><label for="__tabbed_2_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -4004,20 +4005,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>值得注意的是,<code>nums</code> 的待合并区间为 <code>[left, right]</code> ,而 <code>tmp</code> 的对应区间为 <code>[0, right - left]</code> 。</p>
|
||||
<h2 id="1162">11.6.2 算法特性<a class="headerlink" href="#1162" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n \log n)\)</span>、非自适应排序</strong>:划分产生高度为 <span class="arithmatex">\(\log n\)</span> 的递归树,每层合并的总操作数量为 <span class="arithmatex">\(n\)</span> ,因此总体时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span> 。</li>
|
||||
<li><strong>空间复杂度 <span class="arithmatex">\(O(n)\)</span>、非原地排序</strong>:递归深度为 <span class="arithmatex">\(\log n\)</span> ,使用 <span class="arithmatex">\(O(\log n)\)</span> 大小的栈帧空间。合并操作需要借助辅助数组实现,使用 <span class="arithmatex">\(O(n)\)</span> 大小的额外空间。</li>
|
||||
<li><strong>稳定排序</strong>:在合并过程中,相等元素的次序保持不变。</li>
|
||||
</ul>
|
||||
<h2 id="1163">11.6.3 链表排序 *<a class="headerlink" href="#1163" title="Permanent link">¶</a></h2>
|
||||
<h2 id="1163">11.6.3 链表排序<a class="headerlink" href="#1163" title="Permanent link">¶</a></h2>
|
||||
<p>对于链表,归并排序相较于其他排序算法具有显著优势,<strong>可以将链表排序任务的空间复杂度优化至 <span class="arithmatex">\(O(1)\)</span></strong> 。</p>
|
||||
<ul>
|
||||
<li><strong>划分阶段</strong>:可以通过使用“迭代”替代“递归”来实现链表划分工作,从而省去递归使用的栈帧空间。</li>
|
||||
<li><strong>划分阶段</strong>:可以使用“迭代”替代“递归”来实现链表划分工作,从而省去递归使用的栈帧空间。</li>
|
||||
<li><strong>合并阶段</strong>:在链表中,节点增删操作仅需改变引用(指针)即可实现,因此合并阶段(将两个短有序链表合并为一个长有序链表)无须创建额外链表。</li>
|
||||
</ul>
|
||||
<p>具体实现细节比较复杂,有兴趣的同学可以查阅相关资料进行学习。</p>
|
||||
<p>具体实现细节比较复杂,有兴趣的读者可以查阅相关资料进行学习。</p>
|
||||
|
||||
<!-- Source file information -->
|
||||
|
||||
|
||||
@@ -2246,7 +2246,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1153" class="md-nav__link">
|
||||
11.5.3 快排为什么快?
|
||||
11.5.3 快速排序为什么快
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -3349,7 +3349,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1153" class="md-nav__link">
|
||||
11.5.3 快排为什么快?
|
||||
11.5.3 快速排序为什么快
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -3474,7 +3474,7 @@
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">quick_sort.py</span><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="k">def</span> <span class="nf">partition</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">nums</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">left</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">right</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="sd">"""哨兵划分"""</span>
|
||||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a> <span class="c1"># 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a> <span class="c1"># 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">left</span><span class="p">,</span> <span class="n">right</span>
|
||||
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a> <span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="n">j</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a> <span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="n">j</span> <span class="ow">and</span> <span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">>=</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]:</span>
|
||||
@@ -3498,7 +3498,7 @@
|
||||
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a>
|
||||
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a><span class="kt">int</span><span class="w"> </span><span class="nf">partition</span><span class="p">(</span><span class="n">vector</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="o">&</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span>
|
||||
@@ -3522,7 +3522,7 @@
|
||||
<a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a>
|
||||
<a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a><span class="kt">int</span><span class="w"> </span><span class="nf">partition</span><span class="p">(</span><span class="kt">int</span><span class="o">[]</span><span class="w"> </span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-2-12" name="__codelineno-2-12" href="#__codelineno-2-12"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-2-13" name="__codelineno-2-13" href="#__codelineno-2-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="n">j</span><span class="o">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="n">left</span><span class="o">]</span><span class="p">)</span>
|
||||
@@ -3544,7 +3544,7 @@
|
||||
<a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a>
|
||||
<a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="kt">int</span><span class="w"> </span><span class="nf">Partition</span><span class="p">(</span><span class="kt">int</span><span class="p">[]</span><span class="w"> </span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span>
|
||||
@@ -3561,7 +3561,7 @@
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">quick_sort.go</span><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">q</span><span class="w"> </span><span class="o">*</span><span class="nx">quickSort</span><span class="p">)</span><span class="w"> </span><span class="nx">partition</span><span class="p">(</span><span class="nx">nums</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span>
|
||||
<a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">left</span><span class="p">]</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3589,7 +3589,7 @@
|
||||
<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a>
|
||||
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a><span class="kd">func</span> <span class="nf">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">:</span> <span class="kr">inout</span> <span class="p">[</span><span class="nb">Int</span><span class="p">],</span> <span class="kr">left</span><span class="p">:</span> <span class="nb">Int</span><span class="p">,</span> <span class="kr">right</span><span class="p">:</span> <span class="nb">Int</span><span class="p">)</span> <span class="p">-></span> <span class="nb">Int</span> <span class="p">{</span>
|
||||
<a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a> <span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a> <span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a> <span class="kd">var</span> <span class="nv">i</span> <span class="p">=</span> <span class="kr">left</span>
|
||||
<a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a> <span class="kd">var</span> <span class="nv">j</span> <span class="p">=</span> <span class="kr">right</span>
|
||||
<a id="__codelineno-5-13" name="__codelineno-5-13" href="#__codelineno-5-13"></a> <span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="n">j</span> <span class="p">{</span>
|
||||
@@ -3616,7 +3616,7 @@
|
||||
<a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a>
|
||||
<a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="nx">partition</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span>
|
||||
<a id="__codelineno-6-12" name="__codelineno-6-12" href="#__codelineno-6-12"></a><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-6-13" name="__codelineno-6-13" href="#__codelineno-6-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3644,7 +3644,7 @@
|
||||
<a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a>
|
||||
<a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="nx">partition</span><span class="p">(</span><span class="nx">nums</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">[],</span><span class="w"> </span><span class="nx">left</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">)</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span>
|
||||
<a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-7-13" name="__codelineno-7-13" href="#__codelineno-7-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3672,7 +3672,7 @@
|
||||
<a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a>
|
||||
<a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="kt">int</span><span class="w"> </span><span class="n">_partition</span><span class="p">(</span><span class="n">List</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-8-11" name="__codelineno-8-11" href="#__codelineno-8-11"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-8-12" name="__codelineno-8-12" href="#__codelineno-8-12"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-8-13" name="__codelineno-8-13" href="#__codelineno-8-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span><span class="w"> </span><span class="n">j</span><span class="o">--</span><span class="p">;</span><span class="w"> </span><span class="c1">// 从右向左找首个小于基准数的元素</span>
|
||||
@@ -3687,7 +3687,7 @@
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">quick_sort.rs</span><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="cm">/* 哨兵划分 */</span>
|
||||
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="k">fn</span> <span class="nf">partition</span><span class="p">(</span><span class="n">nums</span>: <span class="kp">&</span><span class="nc">mut</span><span class="w"> </span><span class="p">[</span><span class="kt">i32</span><span class="p">],</span><span class="w"> </span><span class="n">left</span>: <span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">right</span>: <span class="kt">usize</span><span class="p">)</span><span class="w"> </span>-> <span class="kt">usize</span> <span class="p">{</span>
|
||||
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3714,7 +3714,7 @@
|
||||
<a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="cm">/* 快速排序类 */</span>
|
||||
<a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="c1">// 快速排序类-哨兵划分</span>
|
||||
<a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a><span class="kt">int</span><span class="w"> </span><span class="nf">partition</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">nums</span><span class="p">[],</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-10-14" name="__codelineno-10-14" href="#__codelineno-10-14"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3745,7 +3745,7 @@
|
||||
<a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a>
|
||||
<a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a><span class="c1">// 哨兵划分</span>
|
||||
<a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a><span class="k">fn</span><span class="w"> </span><span class="n">partition</span><span class="p">(</span><span class="n">nums</span><span class="o">:</span><span class="w"> </span><span class="p">[]</span><span class="kt">i32</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="o">:</span><span class="w"> </span><span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="o">:</span><span class="w"> </span><span class="kt">usize</span><span class="p">)</span><span class="w"> </span><span class="kt">usize</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-11-10" name="__codelineno-11-10" href="#__codelineno-11-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-11-10" name="__codelineno-11-10" href="#__codelineno-11-10"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-11-11" name="__codelineno-11-11" href="#__codelineno-11-11"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">;</span>
|
||||
<a id="__codelineno-11-12" name="__codelineno-11-12" href="#__codelineno-11-12"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-11-13" name="__codelineno-11-13" href="#__codelineno-11-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3917,7 +3917,7 @@
|
||||
<div class="highlight"><span class="filename">quick_sort.c</span><pre><span></span><code><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="cm">/* 快速排序类 */</span>
|
||||
<a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="c1">// 快速排序类-哨兵划分</span>
|
||||
<a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="kt">int</span><span class="w"> </span><span class="nf">partition</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">nums</span><span class="p">[],</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-22-7" name="__codelineno-22-7" href="#__codelineno-22-7"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3968,22 +3968,23 @@
|
||||
</div>
|
||||
<h2 id="1152">11.5.2 算法特性<a class="headerlink" href="#1152" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n \log n)\)</span>、自适应排序</strong>:在平均情况下,哨兵划分的递归层数为 <span class="arithmatex">\(\log n\)</span> ,每层中的总循环数为 <span class="arithmatex">\(n\)</span> ,总体使用 <span class="arithmatex">\(O(n \log n)\)</span> 时间。在最差情况下,每轮哨兵划分操作都将长度为 <span class="arithmatex">\(n\)</span> 的数组划分为长度为 <span class="arithmatex">\(0\)</span> 和 <span class="arithmatex">\(n - 1\)</span> 的两个子数组,此时递归层数达到 <span class="arithmatex">\(n\)</span> 层,每层中的循环数为 <span class="arithmatex">\(n\)</span> ,总体使用 <span class="arithmatex">\(O(n^2)\)</span> 时间。</li>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n \log n)\)</span>、自适应排序</strong>:在平均情况下,哨兵划分的递归层数为 <span class="arithmatex">\(\log n\)</span> ,每层中的总循环数为 <span class="arithmatex">\(n\)</span> ,总体使用 <span class="arithmatex">\(O(n \log n)\)</span> 时间。在最差情况下,每轮哨兵划分操作都将长度为 <span class="arithmatex">\(n\)</span> 的数组划分为长度为 <span class="arithmatex">\(0\)</span> 和 <span class="arithmatex">\(n - 1\)</span> 的两个子数组,此时递归层数达到 <span class="arithmatex">\(n\)</span> ,每层中的循环数为 <span class="arithmatex">\(n\)</span> ,总体使用 <span class="arithmatex">\(O(n^2)\)</span> 时间。</li>
|
||||
<li><strong>空间复杂度 <span class="arithmatex">\(O(n)\)</span>、原地排序</strong>:在输入数组完全倒序的情况下,达到最差递归深度 <span class="arithmatex">\(n\)</span> ,使用 <span class="arithmatex">\(O(n)\)</span> 栈帧空间。排序操作是在原数组上进行的,未借助额外数组。</li>
|
||||
<li><strong>非稳定排序</strong>:在哨兵划分的最后一步,基准数可能会被交换至相等元素的右侧。</li>
|
||||
</ul>
|
||||
<h2 id="1153">11.5.3 快排为什么快?<a class="headerlink" href="#1153" title="Permanent link">¶</a></h2>
|
||||
<h2 id="1153">11.5.3 快速排序为什么快<a class="headerlink" href="#1153" title="Permanent link">¶</a></h2>
|
||||
<p>从名称上就能看出,快速排序在效率方面应该具有一定的优势。尽管快速排序的平均时间复杂度与“归并排序”和“堆排序”相同,但通常快速排序的效率更高,主要有以下原因。</p>
|
||||
<ul>
|
||||
<li><strong>出现最差情况的概率很低</strong>:虽然快速排序的最差时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> ,没有归并排序稳定,但在绝大多数情况下,快速排序能在 <span class="arithmatex">\(O(n \log n)\)</span> 的时间复杂度下运行。</li>
|
||||
<li><strong>缓存使用效率高</strong>:在执行哨兵划分操作时,系统可将整个子数组加载到缓存,因此访问元素的效率较高。而像“堆排序”这类算法需要跳跃式访问元素,从而缺乏这一特性。</li>
|
||||
<li><strong>复杂度的常数系数低</strong>:在上述三种算法中,快速排序的比较、赋值、交换等操作的总数量最少。这与“插入排序”比“冒泡排序”更快的原因类似。</li>
|
||||
<li><strong>复杂度的常数系数小</strong>:在上述三种算法中,快速排序的比较、赋值、交换等操作的总数量最少。这与“插入排序”比“冒泡排序”更快的原因类似。</li>
|
||||
</ul>
|
||||
<h2 id="1154">11.5.4 基准数优化<a class="headerlink" href="#1154" title="Permanent link">¶</a></h2>
|
||||
<p><strong>快速排序在某些输入下的时间效率可能降低</strong>。举一个极端例子,假设输入数组是完全倒序的,由于我们选择最左端元素作为基准数,那么在哨兵划分完成后,基准数被交换至数组最右端,导致左子数组长度为 <span class="arithmatex">\(n - 1\)</span>、右子数组长度为 <span class="arithmatex">\(0\)</span> 。如此递归下去,每轮哨兵划分后的右子数组长度都为 <span class="arithmatex">\(0\)</span> ,分治策略失效,快速排序退化为“冒泡排序”。</p>
|
||||
<p>为了尽量避免这种情况发生,<strong>我们可以优化哨兵划分中的基准数的选取策略</strong>。例如,我们可以随机选取一个元素作为基准数。然而,如果运气不佳,每次都选到不理想的基准数,效率仍然不尽如人意。</p>
|
||||
<p>需要注意的是,编程语言通常生成的是“伪随机数”。如果我们针对伪随机数序列构建一个特定的测试样例,那么快速排序的效率仍然可能劣化。</p>
|
||||
<p>为了进一步改进,我们可以在数组中选取三个候选元素(通常为数组的首、尾、中点元素),<strong>并将这三个候选元素的中位数作为基准数</strong>。这样一来,基准数“既不太小也不太大”的概率将大幅提升。当然,我们还可以选取更多候选元素,以进一步提高算法的稳健性。采用这种方法后,时间复杂度劣化至 <span class="arithmatex">\(O(n^2)\)</span> 的概率大大降低。</p>
|
||||
<p>示例代码如下:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="4:12"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><input id="__tabbed_4_6" name="__tabbed_4" type="radio" /><input id="__tabbed_4_7" name="__tabbed_4" type="radio" /><input id="__tabbed_4_8" name="__tabbed_4" type="radio" /><input id="__tabbed_4_9" name="__tabbed_4" type="radio" /><input id="__tabbed_4_10" name="__tabbed_4" type="radio" /><input id="__tabbed_4_11" name="__tabbed_4" type="radio" /><input id="__tabbed_4_12" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">Python</label><label for="__tabbed_4_2">C++</label><label for="__tabbed_4_3">Java</label><label for="__tabbed_4_4">C#</label><label for="__tabbed_4_5">Go</label><label for="__tabbed_4_6">Swift</label><label for="__tabbed_4_7">JS</label><label for="__tabbed_4_8">TS</label><label for="__tabbed_4_9">Dart</label><label for="__tabbed_4_10">Rust</label><label for="__tabbed_4_11">C</label><label for="__tabbed_4_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3999,11 +4000,11 @@
|
||||
<a id="__codelineno-24-10" name="__codelineno-24-10" href="#__codelineno-24-10"></a>
|
||||
<a id="__codelineno-24-11" name="__codelineno-24-11" href="#__codelineno-24-11"></a><span class="k">def</span> <span class="nf">partition</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">nums</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">left</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">right</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
||||
<a id="__codelineno-24-12" name="__codelineno-24-12" href="#__codelineno-24-12"></a><span class="w"> </span><span class="sd">"""哨兵划分(三数取中值)"""</span>
|
||||
<a id="__codelineno-24-13" name="__codelineno-24-13" href="#__codelineno-24-13"></a> <span class="c1"># 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-24-13" name="__codelineno-24-13" href="#__codelineno-24-13"></a> <span class="c1"># 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-24-14" name="__codelineno-24-14" href="#__codelineno-24-14"></a> <span class="n">med</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">median_three</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">left</span><span class="p">,</span> <span class="p">(</span><span class="n">left</span> <span class="o">+</span> <span class="n">right</span><span class="p">)</span> <span class="o">//</span> <span class="mi">2</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span>
|
||||
<a id="__codelineno-24-15" name="__codelineno-24-15" href="#__codelineno-24-15"></a> <span class="c1"># 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-24-16" name="__codelineno-24-16" href="#__codelineno-24-16"></a> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">med</span><span class="p">]</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">med</span><span class="p">],</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]</span>
|
||||
<a id="__codelineno-24-17" name="__codelineno-24-17" href="#__codelineno-24-17"></a> <span class="c1"># 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-24-17" name="__codelineno-24-17" href="#__codelineno-24-17"></a> <span class="c1"># 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-24-18" name="__codelineno-24-18" href="#__codelineno-24-18"></a> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="n">left</span><span class="p">,</span> <span class="n">right</span>
|
||||
<a id="__codelineno-24-19" name="__codelineno-24-19" href="#__codelineno-24-19"></a> <span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="n">j</span><span class="p">:</span>
|
||||
<a id="__codelineno-24-20" name="__codelineno-24-20" href="#__codelineno-24-20"></a> <span class="k">while</span> <span class="n">i</span> <span class="o"><</span> <span class="n">j</span> <span class="ow">and</span> <span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">>=</span> <span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]:</span>
|
||||
@@ -4036,7 +4037,7 @@
|
||||
<a id="__codelineno-25-16" name="__codelineno-25-16" href="#__codelineno-25-16"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">med</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">medianThree</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-25-17" name="__codelineno-25-17" href="#__codelineno-25-17"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-25-18" name="__codelineno-25-18" href="#__codelineno-25-18"></a><span class="w"> </span><span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-25-19" name="__codelineno-25-19" href="#__codelineno-25-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-25-19" name="__codelineno-25-19" href="#__codelineno-25-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-25-20" name="__codelineno-25-20" href="#__codelineno-25-20"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-25-21" name="__codelineno-25-21" href="#__codelineno-25-21"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-25-22" name="__codelineno-25-22" href="#__codelineno-25-22"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span>
|
||||
@@ -4069,7 +4070,7 @@
|
||||
<a id="__codelineno-26-16" name="__codelineno-26-16" href="#__codelineno-26-16"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">med</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">medianThree</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-26-17" name="__codelineno-26-17" href="#__codelineno-26-17"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-26-18" name="__codelineno-26-18" href="#__codelineno-26-18"></a><span class="w"> </span><span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-26-19" name="__codelineno-26-19" href="#__codelineno-26-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-26-19" name="__codelineno-26-19" href="#__codelineno-26-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-26-20" name="__codelineno-26-20" href="#__codelineno-26-20"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-26-21" name="__codelineno-26-21" href="#__codelineno-26-21"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-26-22" name="__codelineno-26-22" href="#__codelineno-26-22"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="n">j</span><span class="o">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="n">left</span><span class="o">]</span><span class="p">)</span>
|
||||
@@ -4102,7 +4103,7 @@
|
||||
<a id="__codelineno-27-16" name="__codelineno-27-16" href="#__codelineno-27-16"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">med</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MedianThree</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-27-17" name="__codelineno-27-17" href="#__codelineno-27-17"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-27-18" name="__codelineno-27-18" href="#__codelineno-27-18"></a><span class="w"> </span><span class="n">Swap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-27-19" name="__codelineno-27-19" href="#__codelineno-27-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-27-19" name="__codelineno-27-19" href="#__codelineno-27-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-27-20" name="__codelineno-27-20" href="#__codelineno-27-20"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-27-21" name="__codelineno-27-21" href="#__codelineno-27-21"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-27-22" name="__codelineno-27-22" href="#__codelineno-27-22"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span>
|
||||
@@ -4131,11 +4132,11 @@
|
||||
<a id="__codelineno-28-12" name="__codelineno-28-12" href="#__codelineno-28-12"></a>
|
||||
<a id="__codelineno-28-13" name="__codelineno-28-13" href="#__codelineno-28-13"></a><span class="cm">/* 哨兵划分(三数取中值)*/</span>
|
||||
<a id="__codelineno-28-14" name="__codelineno-28-14" href="#__codelineno-28-14"></a><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">q</span><span class="w"> </span><span class="o">*</span><span class="nx">quickSortMedian</span><span class="p">)</span><span class="w"> </span><span class="nx">partition</span><span class="p">(</span><span class="nx">nums</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-28-15" name="__codelineno-28-15" href="#__codelineno-28-15"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-28-15" name="__codelineno-28-15" href="#__codelineno-28-15"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-28-16" name="__codelineno-28-16" href="#__codelineno-28-16"></a><span class="w"> </span><span class="nx">med</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">q</span><span class="p">.</span><span class="nx">medianThree</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="nx">left</span><span class="o">+</span><span class="nx">right</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="p">)</span>
|
||||
<a id="__codelineno-28-17" name="__codelineno-28-17" href="#__codelineno-28-17"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-28-18" name="__codelineno-28-18" href="#__codelineno-28-18"></a><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">left</span><span class="p">],</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">med</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">med</span><span class="p">],</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">left</span><span class="p">]</span>
|
||||
<a id="__codelineno-28-19" name="__codelineno-28-19" href="#__codelineno-28-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-28-19" name="__codelineno-28-19" href="#__codelineno-28-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-28-20" name="__codelineno-28-20" href="#__codelineno-28-20"></a><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span>
|
||||
<a id="__codelineno-28-21" name="__codelineno-28-21" href="#__codelineno-28-21"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-28-22" name="__codelineno-28-22" href="#__codelineno-28-22"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="nx">nums</span><span class="p">[</span><span class="nx">left</span><span class="p">]</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -4197,7 +4198,7 @@
|
||||
<a id="__codelineno-30-19" name="__codelineno-30-19" href="#__codelineno-30-19"></a><span class="w"> </span><span class="p">);</span>
|
||||
<a id="__codelineno-30-20" name="__codelineno-30-20" href="#__codelineno-30-20"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-30-21" name="__codelineno-30-21" href="#__codelineno-30-21"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">swap</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-30-22" name="__codelineno-30-22" href="#__codelineno-30-22"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-30-22" name="__codelineno-30-22" href="#__codelineno-30-22"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-30-23" name="__codelineno-30-23" href="#__codelineno-30-23"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span>
|
||||
<a id="__codelineno-30-24" name="__codelineno-30-24" href="#__codelineno-30-24"></a><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-30-25" name="__codelineno-30-25" href="#__codelineno-30-25"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -4242,7 +4243,7 @@
|
||||
<a id="__codelineno-31-29" name="__codelineno-31-29" href="#__codelineno-31-29"></a><span class="w"> </span><span class="p">);</span>
|
||||
<a id="__codelineno-31-30" name="__codelineno-31-30" href="#__codelineno-31-30"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-31-31" name="__codelineno-31-31" href="#__codelineno-31-31"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">swap</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-31-32" name="__codelineno-31-32" href="#__codelineno-31-32"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-31-32" name="__codelineno-31-32" href="#__codelineno-31-32"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-31-33" name="__codelineno-31-33" href="#__codelineno-31-33"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span>
|
||||
<a id="__codelineno-31-34" name="__codelineno-31-34" href="#__codelineno-31-34"></a><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-31-35" name="__codelineno-31-35" href="#__codelineno-31-35"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nx">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -4278,7 +4279,7 @@
|
||||
<a id="__codelineno-32-16" name="__codelineno-32-16" href="#__codelineno-32-16"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">med</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_medianThree</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="o">~/</span><span class="w"> </span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-32-17" name="__codelineno-32-17" href="#__codelineno-32-17"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-32-18" name="__codelineno-32-18" href="#__codelineno-32-18"></a><span class="w"> </span><span class="n">_swap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-32-19" name="__codelineno-32-19" href="#__codelineno-32-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-32-19" name="__codelineno-32-19" href="#__codelineno-32-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-32-20" name="__codelineno-32-20" href="#__codelineno-32-20"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-32-21" name="__codelineno-32-21" href="#__codelineno-32-21"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-32-22" name="__codelineno-32-22" href="#__codelineno-32-22"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span><span class="w"> </span><span class="n">j</span><span class="o">--</span><span class="p">;</span><span class="w"> </span><span class="c1">// 从右向左找首个小于基准数的元素</span>
|
||||
@@ -4309,7 +4310,7 @@
|
||||
<a id="__codelineno-33-16" name="__codelineno-33-16" href="#__codelineno-33-16"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">med</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">Self</span>::<span class="n">median_three</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-33-17" name="__codelineno-33-17" href="#__codelineno-33-17"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-33-18" name="__codelineno-33-18" href="#__codelineno-33-18"></a><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">swap</span><span class="p">(</span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-33-19" name="__codelineno-33-19" href="#__codelineno-33-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-33-19" name="__codelineno-33-19" href="#__codelineno-33-19"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-33-20" name="__codelineno-33-20" href="#__codelineno-33-20"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-33-21" name="__codelineno-33-21" href="#__codelineno-33-21"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-33-22" name="__codelineno-33-22" href="#__codelineno-33-22"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">]</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -4345,7 +4346,7 @@
|
||||
<a id="__codelineno-34-17" name="__codelineno-34-17" href="#__codelineno-34-17"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">med</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">medianThree</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-34-18" name="__codelineno-34-18" href="#__codelineno-34-18"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-34-19" name="__codelineno-34-19" href="#__codelineno-34-19"></a><span class="w"> </span><span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-34-20" name="__codelineno-34-20" href="#__codelineno-34-20"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-34-20" name="__codelineno-34-20" href="#__codelineno-34-20"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-34-21" name="__codelineno-34-21" href="#__codelineno-34-21"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-34-22" name="__codelineno-34-22" href="#__codelineno-34-22"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-34-23" name="__codelineno-34-23" href="#__codelineno-34-23"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">left</span><span class="p">])</span>
|
||||
@@ -4379,7 +4380,7 @@
|
||||
<a id="__codelineno-35-17" name="__codelineno-35-17" href="#__codelineno-35-17"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">med</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">medianThree</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-35-18" name="__codelineno-35-18" href="#__codelineno-35-18"></a><span class="w"> </span><span class="c1">// 将中位数交换至数组最左端</span>
|
||||
<a id="__codelineno-35-19" name="__codelineno-35-19" href="#__codelineno-35-19"></a><span class="w"> </span><span class="n">swap</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">med</span><span class="p">);</span>
|
||||
<a id="__codelineno-35-20" name="__codelineno-35-20" href="#__codelineno-35-20"></a><span class="w"> </span><span class="c1">// 以 nums[left] 作为基准数</span>
|
||||
<a id="__codelineno-35-20" name="__codelineno-35-20" href="#__codelineno-35-20"></a><span class="w"> </span><span class="c1">// 以 nums[left] 为基准数</span>
|
||||
<a id="__codelineno-35-21" name="__codelineno-35-21" href="#__codelineno-35-21"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">left</span><span class="p">;</span>
|
||||
<a id="__codelineno-35-22" name="__codelineno-35-22" href="#__codelineno-35-22"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">right</span><span class="p">;</span>
|
||||
<a id="__codelineno-35-23" name="__codelineno-35-23" href="#__codelineno-35-23"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">j</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -4396,7 +4397,7 @@
|
||||
</div>
|
||||
<h2 id="1155">11.5.5 尾递归优化<a class="headerlink" href="#1155" title="Permanent link">¶</a></h2>
|
||||
<p><strong>在某些输入下,快速排序可能占用空间较多</strong>。以完全倒序的输入数组为例,设递归中的子数组长度为 <span class="arithmatex">\(m\)</span> ,每轮哨兵划分操作都将产生长度为 <span class="arithmatex">\(0\)</span> 的左子数组和长度为 <span class="arithmatex">\(m - 1\)</span> 的右子数组,这意味着每一层递归调用减少的问题规模非常小(只减少一个元素),递归树的高度会达到 <span class="arithmatex">\(n - 1\)</span> ,此时需要占用 <span class="arithmatex">\(O(n)\)</span> 大小的栈帧空间。</p>
|
||||
<p>为了防止栈帧空间的累积,我们可以在每轮哨兵排序完成后,比较两个子数组的长度,<strong>仅对较短的子数组进行递归</strong>。由于较短子数组的长度不会超过 <span class="arithmatex">\(n / 2\)</span> ,因此这种方法能确保递归深度不超过 <span class="arithmatex">\(\log n\)</span> ,从而将最差空间复杂度优化至 <span class="arithmatex">\(O(\log n)\)</span> 。</p>
|
||||
<p>为了防止栈帧空间的累积,我们可以在每轮哨兵排序完成后,比较两个子数组的长度,<strong>仅对较短的子数组进行递归</strong>。由于较短子数组的长度不会超过 <span class="arithmatex">\(n / 2\)</span> ,因此这种方法能确保递归深度不超过 <span class="arithmatex">\(\log n\)</span> ,从而将最差空间复杂度优化至 <span class="arithmatex">\(O(\log n)\)</span> 。代码如下所示:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="5:12"><input checked="checked" id="__tabbed_5_1" name="__tabbed_5" type="radio" /><input id="__tabbed_5_2" name="__tabbed_5" type="radio" /><input id="__tabbed_5_3" name="__tabbed_5" type="radio" /><input id="__tabbed_5_4" name="__tabbed_5" type="radio" /><input id="__tabbed_5_5" name="__tabbed_5" type="radio" /><input id="__tabbed_5_6" name="__tabbed_5" type="radio" /><input id="__tabbed_5_7" name="__tabbed_5" type="radio" /><input id="__tabbed_5_8" name="__tabbed_5" type="radio" /><input id="__tabbed_5_9" name="__tabbed_5" type="radio" /><input id="__tabbed_5_10" name="__tabbed_5" type="radio" /><input id="__tabbed_5_11" name="__tabbed_5" type="radio" /><input id="__tabbed_5_12" name="__tabbed_5" type="radio" /><div class="tabbed-labels"><label for="__tabbed_5_1">Python</label><label for="__tabbed_5_2">C++</label><label for="__tabbed_5_3">Java</label><label for="__tabbed_5_4">C#</label><label for="__tabbed_5_5">Go</label><label for="__tabbed_5_6">Swift</label><label for="__tabbed_5_7">JS</label><label for="__tabbed_5_8">TS</label><label for="__tabbed_5_9">Dart</label><label for="__tabbed_5_10">Rust</label><label for="__tabbed_5_11">C</label><label for="__tabbed_5_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -4406,7 +4407,7 @@
|
||||
<a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a> <span class="k">while</span> <span class="n">left</span> <span class="o"><</span> <span class="n">right</span><span class="p">:</span>
|
||||
<a id="__codelineno-36-5" name="__codelineno-36-5" href="#__codelineno-36-5"></a> <span class="c1"># 哨兵划分操作</span>
|
||||
<a id="__codelineno-36-6" name="__codelineno-36-6" href="#__codelineno-36-6"></a> <span class="n">pivot</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">)</span>
|
||||
<a id="__codelineno-36-7" name="__codelineno-36-7" href="#__codelineno-36-7"></a> <span class="c1"># 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-36-7" name="__codelineno-36-7" href="#__codelineno-36-7"></a> <span class="c1"># 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-36-8" name="__codelineno-36-8" href="#__codelineno-36-8"></a> <span class="k">if</span> <span class="n">pivot</span> <span class="o">-</span> <span class="n">left</span> <span class="o"><</span> <span class="n">right</span> <span class="o">-</span> <span class="n">pivot</span><span class="p">:</span>
|
||||
<a id="__codelineno-36-9" name="__codelineno-36-9" href="#__codelineno-36-9"></a> <span class="bp">self</span><span class="o">.</span><span class="n">quick_sort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span> <span class="n">left</span><span class="p">,</span> <span class="n">pivot</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="c1"># 递归排序左子数组</span>
|
||||
<a id="__codelineno-36-10" name="__codelineno-36-10" href="#__codelineno-36-10"></a> <span class="n">left</span> <span class="o">=</span> <span class="n">pivot</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1"># 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4422,7 +4423,7 @@
|
||||
<a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-37-6" name="__codelineno-37-6" href="#__codelineno-37-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-37-8" name="__codelineno-37-8" href="#__codelineno-37-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-37-9" name="__codelineno-37-9" href="#__codelineno-37-9"></a><span class="w"> </span><span class="n">quickSort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-37-10" name="__codelineno-37-10" href="#__codelineno-37-10"></a><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4441,7 +4442,7 @@
|
||||
<a id="__codelineno-38-4" name="__codelineno-38-4" href="#__codelineno-38-4"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-38-5" name="__codelineno-38-5" href="#__codelineno-38-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-38-6" name="__codelineno-38-6" href="#__codelineno-38-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-38-7" name="__codelineno-38-7" href="#__codelineno-38-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-38-7" name="__codelineno-38-7" href="#__codelineno-38-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-38-8" name="__codelineno-38-8" href="#__codelineno-38-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-38-9" name="__codelineno-38-9" href="#__codelineno-38-9"></a><span class="w"> </span><span class="n">quickSort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-38-10" name="__codelineno-38-10" href="#__codelineno-38-10"></a><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4460,7 +4461,7 @@
|
||||
<a id="__codelineno-39-4" name="__codelineno-39-4" href="#__codelineno-39-4"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-39-5" name="__codelineno-39-5" href="#__codelineno-39-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-39-6" name="__codelineno-39-6" href="#__codelineno-39-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-39-7" name="__codelineno-39-7" href="#__codelineno-39-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-39-7" name="__codelineno-39-7" href="#__codelineno-39-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-39-8" name="__codelineno-39-8" href="#__codelineno-39-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-39-9" name="__codelineno-39-9" href="#__codelineno-39-9"></a><span class="w"> </span><span class="n">QuickSort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="m">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-39-10" name="__codelineno-39-10" href="#__codelineno-39-10"></a><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="m">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4479,7 +4480,7 @@
|
||||
<a id="__codelineno-40-4" name="__codelineno-40-4" href="#__codelineno-40-4"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">left</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nx">right</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-40-5" name="__codelineno-40-5" href="#__codelineno-40-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-40-6" name="__codelineno-40-6" href="#__codelineno-40-6"></a><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">q</span><span class="p">.</span><span class="nx">partition</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="p">)</span>
|
||||
<a id="__codelineno-40-7" name="__codelineno-40-7" href="#__codelineno-40-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-40-7" name="__codelineno-40-7" href="#__codelineno-40-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-40-8" name="__codelineno-40-8" href="#__codelineno-40-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">pivot</span><span class="o">-</span><span class="nx">left</span><span class="w"> </span><span class="p"><</span><span class="w"> </span><span class="nx">right</span><span class="o">-</span><span class="nx">pivot</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-40-9" name="__codelineno-40-9" href="#__codelineno-40-9"></a><span class="w"> </span><span class="nx">q</span><span class="p">.</span><span class="nx">quickSort</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">pivot</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-40-10" name="__codelineno-40-10" href="#__codelineno-40-10"></a><span class="w"> </span><span class="nx">left</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4500,7 +4501,7 @@
|
||||
<a id="__codelineno-41-6" name="__codelineno-41-6" href="#__codelineno-41-6"></a> <span class="k">while</span> <span class="kr">left</span> <span class="o"><</span> <span class="kr">right</span> <span class="p">{</span>
|
||||
<a id="__codelineno-41-7" name="__codelineno-41-7" href="#__codelineno-41-7"></a> <span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-41-8" name="__codelineno-41-8" href="#__codelineno-41-8"></a> <span class="kd">let</span> <span class="nv">pivot</span> <span class="p">=</span> <span class="bp">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">:</span> <span class="p">&</span><span class="n">nums</span><span class="p">,</span> <span class="kr">left</span><span class="p">:</span> <span class="kr">left</span><span class="p">,</span> <span class="kr">right</span><span class="p">:</span> <span class="kr">right</span><span class="p">)</span>
|
||||
<a id="__codelineno-41-9" name="__codelineno-41-9" href="#__codelineno-41-9"></a> <span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-41-9" name="__codelineno-41-9" href="#__codelineno-41-9"></a> <span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-41-10" name="__codelineno-41-10" href="#__codelineno-41-10"></a> <span class="k">if</span> <span class="p">(</span><span class="n">pivot</span> <span class="o">-</span> <span class="kr">left</span><span class="p">)</span> <span class="o"><</span> <span class="p">(</span><span class="kr">right</span> <span class="o">-</span> <span class="n">pivot</span><span class="p">)</span> <span class="p">{</span>
|
||||
<a id="__codelineno-41-11" name="__codelineno-41-11" href="#__codelineno-41-11"></a> <span class="n">quickSortTailCall</span><span class="p">(</span><span class="n">nums</span><span class="p">:</span> <span class="p">&</span><span class="n">nums</span><span class="p">,</span> <span class="kr">left</span><span class="p">:</span> <span class="kr">left</span><span class="p">,</span> <span class="kr">right</span><span class="p">:</span> <span class="n">pivot</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-41-12" name="__codelineno-41-12" href="#__codelineno-41-12"></a> <span class="kr">left</span> <span class="p">=</span> <span class="n">pivot</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4519,7 +4520,7 @@
|
||||
<a id="__codelineno-42-4" name="__codelineno-42-4" href="#__codelineno-42-4"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nx">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-42-5" name="__codelineno-42-5" href="#__codelineno-42-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-42-6" name="__codelineno-42-6" href="#__codelineno-42-6"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">partition</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-42-7" name="__codelineno-42-7" href="#__codelineno-42-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-42-7" name="__codelineno-42-7" href="#__codelineno-42-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-42-8" name="__codelineno-42-8" href="#__codelineno-42-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-42-9" name="__codelineno-42-9" href="#__codelineno-42-9"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">quickSort</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-42-10" name="__codelineno-42-10" href="#__codelineno-42-10"></a><span class="w"> </span><span class="nx">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4538,7 +4539,7 @@
|
||||
<a id="__codelineno-43-4" name="__codelineno-43-4" href="#__codelineno-43-4"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nx">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-43-5" name="__codelineno-43-5" href="#__codelineno-43-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-43-6" name="__codelineno-43-6" href="#__codelineno-43-6"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">partition</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-43-7" name="__codelineno-43-7" href="#__codelineno-43-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-43-7" name="__codelineno-43-7" href="#__codelineno-43-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-43-8" name="__codelineno-43-8" href="#__codelineno-43-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-43-9" name="__codelineno-43-9" href="#__codelineno-43-9"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">quickSort</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">left</span><span class="p">,</span><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-43-10" name="__codelineno-43-10" href="#__codelineno-43-10"></a><span class="w"> </span><span class="nx">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4557,7 +4558,7 @@
|
||||
<a id="__codelineno-44-4" name="__codelineno-44-4" href="#__codelineno-44-4"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-44-5" name="__codelineno-44-5" href="#__codelineno-44-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-44-6" name="__codelineno-44-6" href="#__codelineno-44-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">_partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-44-7" name="__codelineno-44-7" href="#__codelineno-44-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-44-7" name="__codelineno-44-7" href="#__codelineno-44-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-44-8" name="__codelineno-44-8" href="#__codelineno-44-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-44-9" name="__codelineno-44-9" href="#__codelineno-44-9"></a><span class="w"> </span><span class="n">quickSort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="m">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-44-10" name="__codelineno-44-10" href="#__codelineno-44-10"></a><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="m">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4576,7 +4577,7 @@
|
||||
<a id="__codelineno-45-4" name="__codelineno-45-4" href="#__codelineno-45-4"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-45-5" name="__codelineno-45-5" href="#__codelineno-45-5"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-45-6" name="__codelineno-45-6" href="#__codelineno-45-6"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">Self</span>::<span class="n">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">usize</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="kt">i32</span><span class="p">;</span>
|
||||
<a id="__codelineno-45-7" name="__codelineno-45-7" href="#__codelineno-45-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-45-7" name="__codelineno-45-7" href="#__codelineno-45-7"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-45-8" name="__codelineno-45-8" href="#__codelineno-45-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-45-9" name="__codelineno-45-9" href="#__codelineno-45-9"></a><span class="w"> </span><span class="bp">Self</span>::<span class="n">quick_sort</span><span class="p">(</span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">nums</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-45-10" name="__codelineno-45-10" href="#__codelineno-45-10"></a><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4596,7 +4597,7 @@
|
||||
<a id="__codelineno-46-5" name="__codelineno-46-5" href="#__codelineno-46-5"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-46-6" name="__codelineno-46-6" href="#__codelineno-46-6"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-46-7" name="__codelineno-46-7" href="#__codelineno-46-7"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-46-8" name="__codelineno-46-8" href="#__codelineno-46-8"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-46-8" name="__codelineno-46-8" href="#__codelineno-46-8"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-46-9" name="__codelineno-46-9" href="#__codelineno-46-9"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-46-10" name="__codelineno-46-10" href="#__codelineno-46-10"></a><span class="w"> </span><span class="n">quickSortTailCall</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-46-11" name="__codelineno-46-11" href="#__codelineno-46-11"></a><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
@@ -4617,7 +4618,7 @@
|
||||
<a id="__codelineno-47-6" name="__codelineno-47-6" href="#__codelineno-47-6"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-47-7" name="__codelineno-47-7" href="#__codelineno-47-7"></a><span class="w"> </span><span class="c1">// 哨兵划分操作</span>
|
||||
<a id="__codelineno-47-8" name="__codelineno-47-8" href="#__codelineno-47-8"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">partition</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">right</span><span class="p">);</span>
|
||||
<a id="__codelineno-47-9" name="__codelineno-47-9" href="#__codelineno-47-9"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快排</span>
|
||||
<a id="__codelineno-47-9" name="__codelineno-47-9" href="#__codelineno-47-9"></a><span class="w"> </span><span class="c1">// 对两个子数组中较短的那个执行快速排序</span>
|
||||
<a id="__codelineno-47-10" name="__codelineno-47-10" href="#__codelineno-47-10"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">pivot</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-47-11" name="__codelineno-47-11" href="#__codelineno-47-11"></a><span class="w"> </span><span class="n">quickSort</span><span class="p">(</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="n">left</span><span class="p">,</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"> </span><span class="c1">// 递归排序左子数组</span>
|
||||
<a id="__codelineno-47-12" name="__codelineno-47-12" href="#__codelineno-47-12"></a><span class="w"> </span><span class="n">left</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// 剩余未排序区间为 [pivot + 1, right]</span>
|
||||
|
||||
@@ -3382,7 +3382,7 @@
|
||||
|
||||
<!-- Page content -->
|
||||
<h1 id="1110">11.10 基数排序<a class="headerlink" href="#1110" title="Permanent link">¶</a></h1>
|
||||
<p>上一节我们介绍了计数排序,它适用于数据量 <span class="arithmatex">\(n\)</span> 较大但数据范围 <span class="arithmatex">\(m\)</span> 较小的情况。假设我们需要对 <span class="arithmatex">\(n = 10^6\)</span> 个学号进行排序,而学号是一个 <span class="arithmatex">\(8\)</span> 位数字,这意味着数据范围 <span class="arithmatex">\(m = 10^8\)</span> 非常大,使用计数排序需要分配大量内存空间,而基数排序可以避免这种情况。</p>
|
||||
<p>上一节介绍了计数排序,它适用于数据量 <span class="arithmatex">\(n\)</span> 较大但数据范围 <span class="arithmatex">\(m\)</span> 较小的情况。假设我们需要对 <span class="arithmatex">\(n = 10^6\)</span> 个学号进行排序,而学号是一个 <span class="arithmatex">\(8\)</span> 位数字,这意味着数据范围 <span class="arithmatex">\(m = 10^8\)</span> 非常大,使用计数排序需要分配大量内存空间,而基数排序可以避免这种情况。</p>
|
||||
<p>「基数排序 radix sort」的核心思想与计数排序一致,也通过统计个数来实现排序。在此基础上,基数排序利用数字各位之间的递进关系,依次对每一位进行排序,从而得到最终的排序结果。</p>
|
||||
<h2 id="11101">11.10.1 算法流程<a class="headerlink" href="#11101" title="Permanent link">¶</a></h2>
|
||||
<p>以学号数据为例,假设数字的最低位是第 <span class="arithmatex">\(1\)</span> 位,最高位是第 <span class="arithmatex">\(8\)</span> 位,基数排序的流程如图 11-18 所示。</p>
|
||||
@@ -3394,12 +3394,12 @@
|
||||
<p><a class="glightbox" href="../radix_sort.assets/radix_sort_overview.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="基数排序算法流程" class="animation-figure" src="../radix_sort.assets/radix_sort_overview.png" /></a></p>
|
||||
<p align="center"> 图 11-18 基数排序算法流程 </p>
|
||||
|
||||
<p>下面来剖析代码实现。对于一个 <span class="arithmatex">\(d\)</span> 进制的数字 <span class="arithmatex">\(x\)</span> ,要获取其第 <span class="arithmatex">\(k\)</span> 位 <span class="arithmatex">\(x_k\)</span> ,可以使用以下计算公式:</p>
|
||||
<p>下面剖析代码实现。对于一个 <span class="arithmatex">\(d\)</span> 进制的数字 <span class="arithmatex">\(x\)</span> ,要获取其第 <span class="arithmatex">\(k\)</span> 位 <span class="arithmatex">\(x_k\)</span> ,可以使用以下计算公式:</p>
|
||||
<div class="arithmatex">\[
|
||||
x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
\]</div>
|
||||
<p>其中 <span class="arithmatex">\(\lfloor a \rfloor\)</span> 表示对浮点数 <span class="arithmatex">\(a\)</span> 向下取整,而 <span class="arithmatex">\(\bmod \: d\)</span> 表示对 <span class="arithmatex">\(d\)</span> 取余。对于学号数据,<span class="arithmatex">\(d = 10\)</span> 且 <span class="arithmatex">\(k \in [1, 8]\)</span> 。</p>
|
||||
<p>此外,我们需要小幅改动计数排序代码,使之可以根据数字的第 <span class="arithmatex">\(k\)</span> 位进行排序。</p>
|
||||
<p>此外,我们需要小幅改动计数排序代码,使之可以根据数字的第 <span class="arithmatex">\(k\)</span> 位进行排序:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="1:12"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3410,7 +3410,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a>
|
||||
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="k">def</span> <span class="nf">counting_sort_digit</span><span class="p">(</span><span class="n">nums</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">exp</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="w"> </span><span class="sd">"""计数排序(根据 nums 第 k 位排序)"""</span>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a> <span class="c1"># 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a> <span class="c1"># 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a> <span class="n">counter</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="mi">10</span>
|
||||
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a> <span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">nums</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a> <span class="c1"># 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3455,7 +3455,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a>
|
||||
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="kt">void</span><span class="w"> </span><span class="nf">countingSortDigit</span><span class="p">(</span><span class="n">vector</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="o">&</span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">exp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a><span class="w"> </span><span class="n">vector</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">counter</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
|
||||
<a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
|
||||
<a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3503,7 +3503,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a>
|
||||
<a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a><span class="kt">void</span><span class="w"> </span><span class="nf">countingSortDigit</span><span class="p">(</span><span class="kt">int</span><span class="o">[]</span><span class="w"> </span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">exp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="w"> </span><span class="kt">int</span><span class="o">[]</span><span class="w"> </span><span class="n">counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="kt">int</span><span class="o">[</span><span class="mi">10</span><span class="o">]</span><span class="p">;</span>
|
||||
<a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="na">length</span><span class="p">;</span>
|
||||
<a id="__codelineno-2-12" name="__codelineno-2-12" href="#__codelineno-2-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3554,7 +3554,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a>
|
||||
<a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="k">void</span><span class="w"> </span><span class="nf">CountingSortDigit</span><span class="p">(</span><span class="kt">int</span><span class="p">[]</span><span class="w"> </span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">exp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="w"> </span><span class="kt">int</span><span class="p">[]</span><span class="w"> </span><span class="n">counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="kt">int</span><span class="p">[</span><span class="m">10</span><span class="p">];</span>
|
||||
<a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span>
|
||||
<a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3607,7 +3607,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a>
|
||||
<a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="kd">func</span><span class="w"> </span><span class="nx">countingSortDigit</span><span class="p">(</span><span class="nx">nums</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="nx">exp</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a><span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span>
|
||||
<a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">nums</span><span class="p">)</span>
|
||||
<a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3662,7 +3662,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a>
|
||||
<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="kd">func</span> <span class="nf">countingSortDigit</span><span class="p">(</span><span class="n">nums</span><span class="p">:</span> <span class="kr">inout</span> <span class="p">[</span><span class="nb">Int</span><span class="p">],</span> <span class="n">exp</span><span class="p">:</span> <span class="nb">Int</span><span class="p">)</span> <span class="p">{</span>
|
||||
<a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> <span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> <span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a> <span class="kd">var</span> <span class="nv">counter</span> <span class="p">=</span> <span class="nb">Array</span><span class="p">(</span><span class="n">repeating</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="bp">count</span><span class="p">:</span> <span class="mi">10</span><span class="p">)</span>
|
||||
<a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a> <span class="kd">let</span> <span class="nv">n</span> <span class="p">=</span> <span class="n">nums</span><span class="p">.</span><span class="bp">count</span>
|
||||
<a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a> <span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3717,7 +3717,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a>
|
||||
<a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a><span class="kd">function</span><span class="w"> </span><span class="nx">countingSortDigit</span><span class="p">(</span><span class="nx">nums</span><span class="p">,</span><span class="w"> </span><span class="nx">exp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="mf">10</span><span class="p">).</span><span class="nx">fill</span><span class="p">(</span><span class="mf">0</span><span class="p">);</span>
|
||||
<a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">nums</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
|
||||
<a id="__codelineno-6-12" name="__codelineno-6-12" href="#__codelineno-6-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3772,7 +3772,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a>
|
||||
<a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a><span class="kd">function</span><span class="w"> </span><span class="nx">countingSortDigit</span><span class="p">(</span><span class="nx">nums</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">[],</span><span class="w"> </span><span class="nx">exp</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">)</span><span class="o">:</span><span class="w"> </span><span class="ow">void</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Array</span><span class="p">(</span><span class="mf">10</span><span class="p">).</span><span class="nx">fill</span><span class="p">(</span><span class="mf">0</span><span class="p">);</span>
|
||||
<a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">nums</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
|
||||
<a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3827,7 +3827,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a>
|
||||
<a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a><span class="kt">void</span><span class="w"> </span><span class="n">countingSortDigit</span><span class="p">(</span><span class="n">List</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">nums</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">exp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a><span class="w"> </span><span class="n">List</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">List</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="p">.</span><span class="n">filled</span><span class="p">(</span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">);</span>
|
||||
<a id="__codelineno-8-11" name="__codelineno-8-11" href="#__codelineno-8-11"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">length</span><span class="p">;</span>
|
||||
<a id="__codelineno-8-12" name="__codelineno-8-12" href="#__codelineno-8-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3876,7 +3876,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a>
|
||||
<a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a><span class="k">fn</span> <span class="nf">counting_sort_digit</span><span class="p">(</span><span class="n">nums</span>: <span class="kp">&</span><span class="nc">mut</span><span class="w"> </span><span class="p">[</span><span class="kt">i32</span><span class="p">],</span><span class="w"> </span><span class="n">exp</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-9-10" name="__codelineno-9-10" href="#__codelineno-9-10"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="mi">10</span><span class="p">];</span>
|
||||
<a id="__codelineno-9-11" name="__codelineno-9-11" href="#__codelineno-9-11"></a><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nums</span><span class="p">.</span><span class="n">len</span><span class="p">();</span>
|
||||
<a id="__codelineno-9-12" name="__codelineno-9-12" href="#__codelineno-9-12"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
@@ -3924,7 +3924,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a>
|
||||
<a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="cm">/* 计数排序(根据 nums 第 k 位排序) */</span>
|
||||
<a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="kt">void</span><span class="w"> </span><span class="nf">countingSortDigit</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">nums</span><span class="p">[],</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">size</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">exp</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="n">counter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">((</span><span class="k">sizeof</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">10</span><span class="p">));</span>
|
||||
<a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a><span class="w"> </span><span class="c1">// 统计 0~9 各数字的出现次数</span>
|
||||
<a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">size</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
@@ -3979,7 +3979,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a>
|
||||
<a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a><span class="c1">// 计数排序(根据 nums 第 k 位排序)</span>
|
||||
<a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a><span class="k">fn</span><span class="w"> </span><span class="n">countingSortDigit</span><span class="p">(</span><span class="n">nums</span><span class="o">:</span><span class="w"> </span><span class="p">[]</span><span class="kt">i32</span><span class="p">,</span><span class="w"> </span><span class="n">exp</span><span class="o">:</span><span class="w"> </span><span class="kt">i32</span><span class="p">)</span><span class="w"> </span><span class="o">!</span><span class="kt">void</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶</span>
|
||||
<a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a><span class="w"> </span><span class="c1">// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组</span>
|
||||
<a id="__codelineno-11-10" name="__codelineno-11-10" href="#__codelineno-11-10"></a><span class="w"> </span><span class="kr">var</span><span class="w"> </span><span class="n">mem_arena</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span><span class="p">.</span><span class="n">heap</span><span class="p">.</span><span class="n">ArenaAllocator</span><span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="n">std</span><span class="p">.</span><span class="n">heap</span><span class="p">.</span><span class="n">page_allocator</span><span class="p">);</span>
|
||||
<a id="__codelineno-11-11" name="__codelineno-11-11" href="#__codelineno-11-11"></a><span class="w"> </span><span class="c1">// defer mem_arena.deinit();</span>
|
||||
<a id="__codelineno-11-12" name="__codelineno-11-12" href="#__codelineno-11-12"></a><span class="w"> </span><span class="kr">const</span><span class="w"> </span><span class="n">mem_allocator</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mem_arena</span><span class="p">.</span><span class="n">allocator</span><span class="p">();</span>
|
||||
@@ -4036,7 +4036,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">为什么从最低位开始排序?</p>
|
||||
<p>在连续的排序轮次中,后一轮排序会覆盖前一轮排序的结果。举例来说,如果第一轮排序结果 <span class="arithmatex">\(a < b\)</span> ,而第二轮排序结果 <span class="arithmatex">\(a > b\)</span> ,那么第二轮的结果将取代第一轮的结果。由于数字的高位优先级高于低位,我们应该先排序低位再排序高位。</p>
|
||||
<p>在连续的排序轮次中,后一轮排序会覆盖前一轮排序的结果。举例来说,如果第一轮排序结果 <span class="arithmatex">\(a < b\)</span> ,而第二轮排序结果 <span class="arithmatex">\(a > b\)</span> ,那么第二轮的结果将取代第一轮的结果。由于数字的高位优先级高于低位,因此应该先排序低位再排序高位。</p>
|
||||
</div>
|
||||
<h2 id="11102">11.10.2 算法特性<a class="headerlink" href="#11102" title="Permanent link">¶</a></h2>
|
||||
<p>相较于计数排序,基数排序适用于数值范围较大的情况,<strong>但前提是数据必须可以表示为固定位数的格式,且位数不能过大</strong>。例如,浮点数不适合使用基数排序,因为其位数 <span class="arithmatex">\(k\)</span> 过大,可能导致时间复杂度 <span class="arithmatex">\(O(nk) \gg O(n^2)\)</span> 。</p>
|
||||
|
||||
@@ -3368,12 +3368,12 @@
|
||||
|
||||
<!-- Page content -->
|
||||
<h1 id="112">11.2 选择排序<a class="headerlink" href="#112" title="Permanent link">¶</a></h1>
|
||||
<p>「选择排序 selection sort」的工作原理非常直接:开启一个循环,每轮从未排序区间选择最小的元素,将其放到已排序区间的末尾。</p>
|
||||
<p>「选择排序 selection sort」的工作原理非常简单:开启一个循环,每轮从未排序区间选择最小的元素,将其放到已排序区间的末尾。</p>
|
||||
<p>设数组的长度为 <span class="arithmatex">\(n\)</span> ,选择排序的算法流程如图 11-2 所示。</p>
|
||||
<ol>
|
||||
<li>初始状态下,所有元素未排序,即未排序(索引)区间为 <span class="arithmatex">\([0, n-1]\)</span> 。</li>
|
||||
<li>选取区间 <span class="arithmatex">\([0, n-1]\)</span> 中的最小元素,将其与索引 <span class="arithmatex">\(0\)</span> 处元素交换。完成后,数组前 1 个元素已排序。</li>
|
||||
<li>选取区间 <span class="arithmatex">\([1, n-1]\)</span> 中的最小元素,将其与索引 <span class="arithmatex">\(1\)</span> 处元素交换。完成后,数组前 2 个元素已排序。</li>
|
||||
<li>选取区间 <span class="arithmatex">\([0, n-1]\)</span> 中的最小元素,将其与索引 <span class="arithmatex">\(0\)</span> 处的元素交换。完成后,数组前 1 个元素已排序。</li>
|
||||
<li>选取区间 <span class="arithmatex">\([1, n-1]\)</span> 中的最小元素,将其与索引 <span class="arithmatex">\(1\)</span> 处的元素交换。完成后,数组前 2 个元素已排序。</li>
|
||||
<li>以此类推。经过 <span class="arithmatex">\(n - 1\)</span> 轮选择与交换后,数组前 <span class="arithmatex">\(n - 1\)</span> 个元素已排序。</li>
|
||||
<li>仅剩的一个元素必定是最大元素,无须排序,因此数组排序完成。</li>
|
||||
</ol>
|
||||
@@ -3416,7 +3416,7 @@
|
||||
</div>
|
||||
<p align="center"> 图 11-2 选择排序步骤 </p>
|
||||
|
||||
<p>在代码中,我们用 <span class="arithmatex">\(k\)</span> 来记录未排序区间内的最小元素。</p>
|
||||
<p>在代码中,我们用 <span class="arithmatex">\(k\)</span> 来记录未排序区间内的最小元素:</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:12"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><input id="__tabbed_2_3" name="__tabbed_2" type="radio" /><input id="__tabbed_2_4" name="__tabbed_2" type="radio" /><input id="__tabbed_2_5" name="__tabbed_2" type="radio" /><input id="__tabbed_2_6" name="__tabbed_2" type="radio" /><input id="__tabbed_2_7" name="__tabbed_2" type="radio" /><input id="__tabbed_2_8" name="__tabbed_2" type="radio" /><input id="__tabbed_2_9" name="__tabbed_2" type="radio" /><input id="__tabbed_2_10" name="__tabbed_2" type="radio" /><input id="__tabbed_2_11" name="__tabbed_2" type="radio" /><input id="__tabbed_2_12" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">Python</label><label for="__tabbed_2_2">C++</label><label for="__tabbed_2_3">Java</label><label for="__tabbed_2_4">C#</label><label for="__tabbed_2_5">Go</label><label for="__tabbed_2_6">Swift</label><label for="__tabbed_2_7">JS</label><label for="__tabbed_2_8">TS</label><label for="__tabbed_2_9">Dart</label><label for="__tabbed_2_10">Rust</label><label for="__tabbed_2_11">C</label><label for="__tabbed_2_12">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
@@ -3634,7 +3634,7 @@
|
||||
<ul>
|
||||
<li><strong>时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span>、非自适应排序</strong>:外循环共 <span class="arithmatex">\(n - 1\)</span> 轮,第一轮的未排序区间长度为 <span class="arithmatex">\(n\)</span> ,最后一轮的未排序区间长度为 <span class="arithmatex">\(2\)</span> ,即各轮外循环分别包含 <span class="arithmatex">\(n\)</span>、<span class="arithmatex">\(n - 1\)</span>、<span class="arithmatex">\(\dots\)</span>、<span class="arithmatex">\(3\)</span>、<span class="arithmatex">\(2\)</span> 轮内循环,求和为 <span class="arithmatex">\(\frac{(n - 1)(n + 2)}{2}\)</span> 。</li>
|
||||
<li><strong>空间复杂度 <span class="arithmatex">\(O(1)\)</span>、原地排序</strong>:指针 <span class="arithmatex">\(i\)</span> 和 <span class="arithmatex">\(j\)</span> 使用常数大小的额外空间。</li>
|
||||
<li><strong>非稳定排序</strong>:如图 11-3 所示,元素 <code>nums[i]</code> 有可能被交换至与其相等的元素的右边,导致两者相对顺序发生改变。</li>
|
||||
<li><strong>非稳定排序</strong>:如图 11-3 所示,元素 <code>nums[i]</code> 有可能被交换至与其相等的元素的右边,导致两者的相对顺序发生改变。</li>
|
||||
</ul>
|
||||
<p><a class="glightbox" href="../selection_sort.assets/selection_sort_instability.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="选择排序非稳定示例" class="animation-figure" src="../selection_sort.assets/selection_sort_instability.png" /></a></p>
|
||||
<p align="center"> 图 11-3 选择排序非稳定示例 </p>
|
||||
|
||||
@@ -3382,16 +3382,16 @@
|
||||
|
||||
<!-- Page content -->
|
||||
<h1 id="111">11.1 排序算法<a class="headerlink" href="#111" title="Permanent link">¶</a></h1>
|
||||
<p>「排序算法 sorting algorithm」用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用,因为有序数据通常能够被更有效地查找、分析和处理。</p>
|
||||
<p>「排序算法 sorting algorithm」用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用,因为有序数据通常能够被更高效地查找、分析和处理。</p>
|
||||
<p>如图 11-1 所示,排序算法中的数据类型可以是整数、浮点数、字符或字符串等。排序的判断规则可根据需求设定,如数字大小、字符 ASCII 码顺序或自定义规则。</p>
|
||||
<p><a class="glightbox" href="../sorting_algorithm.assets/sorting_examples.png" data-type="image" data-width="100%" data-height="auto" data-desc-position="bottom"><img alt="数据类型和判断规则示例" class="animation-figure" src="../sorting_algorithm.assets/sorting_examples.png" /></a></p>
|
||||
<p align="center"> 图 11-1 数据类型和判断规则示例 </p>
|
||||
|
||||
<h2 id="1111">11.1.1 评价维度<a class="headerlink" href="#1111" title="Permanent link">¶</a></h2>
|
||||
<p><strong>运行效率</strong>:我们期望排序算法的时间复杂度尽量低,且总体操作数量较少(即时间复杂度中的常数项降低)。对于大数据量情况,运行效率显得尤为重要。</p>
|
||||
<p><strong>运行效率</strong>:我们期望排序算法的时间复杂度尽量低,且总体操作数量较少(时间复杂度中的常数项变小)。对于大数据量的情况,运行效率显得尤为重要。</p>
|
||||
<p><strong>就地性</strong>:顾名思义,「原地排序」通过在原数组上直接操作实现排序,无须借助额外的辅助数组,从而节省内存。通常情况下,原地排序的数据搬运操作较少,运行速度也更快。</p>
|
||||
<p><strong>稳定性</strong>:「稳定排序」在完成排序后,相等元素在数组中的相对顺序不发生改变。</p>
|
||||
<p>稳定排序是多级排序场景的必要条件。假设我们有一个存储学生信息的表格,第 1 列和第 2 列分别是姓名和年龄。在这种情况下,「非稳定排序」可能导致输入数据的有序性丧失。</p>
|
||||
<p>稳定排序是多级排序场景的必要条件。假设我们有一个存储学生信息的表格,第 1 列和第 2 列分别是姓名和年龄。在这种情况下,「非稳定排序」可能导致输入数据的有序性丧失:</p>
|
||||
<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># 输入数据是按照姓名排序好的</span>
|
||||
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="c1"># (name, age)</span>
|
||||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="o">(</span><span class="s1">'A'</span>,<span class="w"> </span><span class="m">19</span><span class="o">)</span>
|
||||
@@ -3409,9 +3409,9 @@
|
||||
<a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a><span class="w"> </span><span class="o">(</span><span class="s1">'C'</span>,<span class="w"> </span><span class="m">21</span><span class="o">)</span>
|
||||
<a id="__codelineno-0-16" name="__codelineno-0-16" href="#__codelineno-0-16"></a><span class="w"> </span><span class="o">(</span><span class="s1">'E'</span>,<span class="w"> </span><span class="m">23</span><span class="o">)</span>
|
||||
</code></pre></div>
|
||||
<p><strong>自适应性</strong>:「自适应排序」的时间复杂度会受输入数据的影响,即最佳、最差、平均时间复杂度并不完全相等。</p>
|
||||
<p><strong>自适应性</strong>:「自适应排序」的时间复杂度会受输入数据的影响,即最佳时间复杂度、最差时间复杂度、平均时间复杂度并不完全相等。</p>
|
||||
<p>自适应性需要根据具体情况来评估。如果最差时间复杂度差于平均时间复杂度,说明排序算法在某些数据下性能可能劣化,因此被视为负面属性;而如果最佳时间复杂度优于平均时间复杂度,则被视为正面属性。</p>
|
||||
<p><strong>是否基于比较</strong>:「基于比较的排序」依赖于比较运算符(<span class="arithmatex">\(<\)</span>、<span class="arithmatex">\(=\)</span>、<span class="arithmatex">\(>\)</span>)来判断元素的相对顺序,从而排序整个数组,理论最优时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span> 。而「非比较排序」不使用比较运算符,时间复杂度可达 <span class="arithmatex">\(O(n)\)</span> ,但其通用性相对较差。</p>
|
||||
<p><strong>是否基于比较</strong>:「基于比较的排序」依赖比较运算符(<span class="arithmatex">\(<\)</span>、<span class="arithmatex">\(=\)</span>、<span class="arithmatex">\(>\)</span>)来判断元素的相对顺序,从而排序整个数组,理论最优时间复杂度为 <span class="arithmatex">\(O(n \log n)\)</span> 。而「非比较排序」不使用比较运算符,时间复杂度可达 <span class="arithmatex">\(O(n)\)</span> ,但其通用性相对较差。</p>
|
||||
<h2 id="1112">11.1.2 理想排序算法<a class="headerlink" href="#1112" title="Permanent link">¶</a></h2>
|
||||
<p><strong>运行快、原地、稳定、正向自适应、通用性好</strong>。显然,迄今为止尚未发现兼具以上所有特性的排序算法。因此,在选择排序算法时,需要根据具体的数据特点和问题需求来决定。</p>
|
||||
<p>接下来,我们将共同学习各种排序算法,并基于上述评价维度对各个排序算法的优缺点进行分析。</p>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 59 KiB |
@@ -3385,7 +3385,7 @@
|
||||
<h3 id="1">1. 重点回顾<a class="headerlink" href="#1" title="Permanent link">¶</a></h3>
|
||||
<ul>
|
||||
<li>冒泡排序通过交换相邻元素来实现排序。通过添加一个标志位来实现提前返回,我们可以将冒泡排序的最佳时间复杂度优化到 <span class="arithmatex">\(O(n)\)</span> 。</li>
|
||||
<li>插入排序每轮将未排序区间内的元素插入到已排序区间的正确位置,从而完成排序。虽然插入排序的时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> ,但由于单元操作相对较少,它在小数据量的排序任务中非常受欢迎。</li>
|
||||
<li>插入排序每轮将未排序区间内的元素插入到已排序区间的正确位置,从而完成排序。虽然插入排序的时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> ,但由于单元操作相对较少,因此在小数据量的排序任务中非常受欢迎。</li>
|
||||
<li>快速排序基于哨兵划分操作实现排序。在哨兵划分中,有可能每次都选取到最差的基准数,导致时间复杂度劣化至 <span class="arithmatex">\(O(n^2)\)</span> 。引入中位数基准数或随机基准数可以降低这种劣化的概率。尾递归方法可以有效地减少递归深度,将空间复杂度优化到 <span class="arithmatex">\(O(\log n)\)</span> 。</li>
|
||||
<li>归并排序包括划分和合并两个阶段,典型地体现了分治策略。在归并排序中,排序数组需要创建辅助数组,空间复杂度为 <span class="arithmatex">\(O(n)\)</span> ;然而排序链表的空间复杂度可以优化至 <span class="arithmatex">\(O(1)\)</span> 。</li>
|
||||
<li>桶排序包含三个步骤:数据分桶、桶内排序和合并结果。它同样体现了分治策略,适用于数据体量很大的情况。桶排序的关键在于对数据进行平均分配。</li>
|
||||
@@ -3399,9 +3399,9 @@
|
||||
|
||||
<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">排序算法稳定性在什么情况下是必须的?</p>
|
||||
<p>在现实中,我们有可能是在对象的某个属性上进行排序。例如,学生有姓名和身高两个属性,我们希望实现一个多级排序/</p>
|
||||
<p>先按照姓名进行排序,得到 <code>(A, 180) (B, 185) (C, 170) (D, 170)</code> ;接下来对身高进行排序。由于排序算法不稳定,我们可能得到 <code>(D, 170) (C, 170) (A, 180) (B, 185)</code> 。</p>
|
||||
<p class="admonition-title">排序算法稳定性在什么情况下是必需的?</p>
|
||||
<p>在现实中,我们有可能是基于对象的某个属性进行排序。例如,学生有姓名和身高两个属性,我们希望实现一个多级排序:</p>
|
||||
<p>先按照姓名进行排序,得到 <code>(A, 180) (B, 185) (C, 170) (D, 170)</code> ;再对身高进行排序。由于排序算法不稳定,因此可能得到 <code>(D, 170) (C, 170) (A, 180) (B, 185)</code> 。</p>
|
||||
<p>可以发现,学生 D 和 C 的位置发生了交换,姓名的有序性被破坏了,而这是我们不希望看到的。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
@@ -3413,12 +3413,12 @@
|
||||
</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>回顾原始的快速排序,我们有可能会连续地递归长度较大的数组,最差情况下为 <span class="arithmatex">\(n\)</span>、<span class="arithmatex">\(n - 1\)</span>、<span class="arithmatex">\(\dots\)</span>、<span class="arithmatex">\(2\)</span>、<span class="arithmatex">\(1\)</span> ,递归深度为 <span class="arithmatex">\(n\)</span> 。尾递归优化可以避免这种情况的出现。</p>
|
||||
<p>递归深度就是当前未返回的递归方法的数量。每轮哨兵划分我们将原数组划分为两个子数组。在尾递归优化后,向下递归的子数组长度最大为原数组长度的一半。假设最差情况,一直为一半长度,那么最终的递归深度就是 <span class="arithmatex">\(\log n\)</span> 。</p>
|
||||
<p>回顾原始的快速排序,我们有可能会连续地递归长度较大的数组,最差情况下为 <span class="arithmatex">\(n\)</span>、<span class="arithmatex">\(n - 1\)</span>、<span class="arithmatex">\(\dots\)</span>、<span class="arithmatex">\(2\)</span>、<span class="arithmatex">\(1\)</span> ,递归深度为 <span class="arithmatex">\(n\)</span> 。尾递归优化可以避免这种情况出现。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">当数组中所有元素都相等时,快速排序的时间复杂度是 <span class="arithmatex">\(O(n^2)\)</span> 吗?该如何处理这种退化情况?</p>
|
||||
<p>是的。这种情况可以考虑通过哨兵划分将数组划分为三个部分:小于、等于、大于基准数。仅向下递归小于和大于的两部分。在该方法下,输入元素全部相等的数组,仅一轮哨兵划分即可完成排序。</p>
|
||||
<p>是的。对于这种情况,可以考虑通过哨兵划分将数组划分为三个部分:小于、等于、大于基准数。仅向下递归小于和大于的两部分。在该方法下,输入元素全部相等的数组,仅一轮哨兵划分即可完成排序。</p>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">桶排序的最差时间复杂度为什么是 <span class="arithmatex">\(O(n^2)\)</span> ?</p>
|
||||
|
||||
Reference in New Issue
Block a user