deploy
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 46 KiB |
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1572,9 +1574,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1588,7 +1604,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1602,7 +1618,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1616,7 +1632,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -2420,7 +2436,7 @@
|
||||
<nav class="md-footer__inner md-grid" aria-label="页脚" >
|
||||
|
||||
|
||||
<a href="../selection_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.2. &nbsp; 选择排序(New)" rel="prev">
|
||||
<a href="../selection_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.2. &nbsp; 选择排序(New)" rel="prev">
|
||||
<div class="md-footer__button md-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</div>
|
||||
@@ -2429,7 +2445,7 @@
|
||||
上一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<link rel="canonical" href="https://www.hello-algo.com/chapter_sorting/bucket_sort/">
|
||||
|
||||
|
||||
<link rel="prev" href="../merge_sort/">
|
||||
<link rel="prev" href="../heap_sort/">
|
||||
|
||||
|
||||
<link rel="next" href="../counting_sort/">
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
|
||||
<title>11.7. 桶排序 - Hello 算法</title>
|
||||
<title>11.8. 桶排序 - Hello 算法</title>
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#117" class="md-skip">
|
||||
<a href="#118" class="md-skip">
|
||||
跳转至
|
||||
</a>
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
|
||||
</span>
|
||||
</div>
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1516,6 +1518,20 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1528,12 +1544,12 @@
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1552,22 +1568,22 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1171" class="md-nav__link">
|
||||
11.7.1. 算法流程
|
||||
<a href="#1181" class="md-nav__link">
|
||||
11.8.1. 算法流程
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1172" class="md-nav__link">
|
||||
11.7.2. 算法特性
|
||||
<a href="#1182" class="md-nav__link">
|
||||
11.8.2. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1173" class="md-nav__link">
|
||||
11.7.3. 如何实现平均分配
|
||||
<a href="#1183" class="md-nav__link">
|
||||
11.8.3. 如何实现平均分配
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -1588,7 +1604,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1602,7 +1618,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1616,7 +1632,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1861,22 +1877,22 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1171" class="md-nav__link">
|
||||
11.7.1. 算法流程
|
||||
<a href="#1181" class="md-nav__link">
|
||||
11.8.1. 算法流程
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1172" class="md-nav__link">
|
||||
11.7.2. 算法特性
|
||||
<a href="#1182" class="md-nav__link">
|
||||
11.8.2. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1173" class="md-nav__link">
|
||||
11.7.3. 如何实现平均分配
|
||||
<a href="#1183" class="md-nav__link">
|
||||
11.8.3. 如何实现平均分配
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -1904,10 +1920,10 @@
|
||||
|
||||
|
||||
|
||||
<h1 id="117">11.7. 桶排序<a class="headerlink" href="#117" title="Permanent link">¶</a></h1>
|
||||
<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>「桶排序 Bucket Sort」是分治思想的一个典型应用。它通过设置一些具有大小顺序的桶,每个桶对应一个数据范围,将数据平均分配到各个桶中;然后,在每个桶内部分别执行排序;最终按照桶的顺序将所有数据合并。</p>
|
||||
<h2 id="1171">11.7.1. 算法流程<a class="headerlink" href="#1171" title="Permanent link">¶</a></h2>
|
||||
<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> 的浮点数。桶排序的流程如下:</p>
|
||||
<ol>
|
||||
<li>初始化 <span class="arithmatex">\(k\)</span> 个桶,将 <span class="arithmatex">\(n\)</span> 个元素分配到 <span class="arithmatex">\(k\)</span> 个桶中;</li>
|
||||
@@ -2170,14 +2186,14 @@
|
||||
<p class="admonition-title">桶排序的适用场景是什么?</p>
|
||||
<p>桶排序适用于处理体量很大的数据。例如,输入数据包含 100 万个元素,由于空间限制,系统内存无法一次性加载所有数据。此时,可以将数据分成 1000 个桶,然后分别对每个桶进行排序,最后将结果合并。</p>
|
||||
</div>
|
||||
<h2 id="1172">11.7.2. 算法特性<a class="headerlink" href="#1172" title="Permanent link">¶</a></h2>
|
||||
<h2 id="1182">11.8.2. 算法特性<a class="headerlink" href="#1182" title="Permanent link">¶</a></h2>
|
||||
<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">\(n\)</span> 个桶,花费 <span class="arithmatex">\(O(k)\)</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="1173">11.7.3. 如何实现平均分配<a class="headerlink" href="#1173" title="Permanent link">¶</a></h2>
|
||||
<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>。这种方法本质上是创建一个递归树,使叶节点的值尽可能平均。当然,不一定要每轮将数据划分为 3 个桶,具体划分方式可根据数据特点灵活选择。</p>
|
||||
<p><img alt="递归划分桶" src="../bucket_sort.assets/scatter_in_buckets_recursively.png" /></p>
|
||||
@@ -2263,7 +2279,7 @@
|
||||
<nav class="md-footer__inner md-grid" aria-label="页脚" >
|
||||
|
||||
|
||||
<a href="../merge_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.6. &nbsp; 归并排序" rel="prev">
|
||||
<a href="../heap_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.7. &nbsp; 堆排序(New)" rel="prev">
|
||||
<div class="md-footer__button md-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</div>
|
||||
@@ -2272,20 +2288,20 @@
|
||||
上一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.6. 归并排序
|
||||
11.7. 堆排序(New)
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a href="../counting_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.8. &nbsp; 计数排序" rel="next">
|
||||
<a href="../counting_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.9. &nbsp; 计数排序" rel="next">
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
下一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
|
||||
<title>11.8. 计数排序 - Hello 算法</title>
|
||||
<title>11.9. 计数排序 - Hello 算法</title>
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#118" class="md-skip">
|
||||
<a href="#119" class="md-skip">
|
||||
跳转至
|
||||
</a>
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
|
||||
</span>
|
||||
</div>
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1517,9 +1519,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1542,12 +1558,12 @@
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1566,29 +1582,29 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1181" class="md-nav__link">
|
||||
11.8.1. 简单实现
|
||||
<a href="#1191" class="md-nav__link">
|
||||
11.9.1. 简单实现
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1182" class="md-nav__link">
|
||||
11.8.2. 完整实现
|
||||
<a href="#1192" class="md-nav__link">
|
||||
11.9.2. 完整实现
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1183" class="md-nav__link">
|
||||
11.8.3. 算法特性
|
||||
<a href="#1193" class="md-nav__link">
|
||||
11.9.3. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1184" class="md-nav__link">
|
||||
11.8.4. 局限性
|
||||
<a href="#1194" class="md-nav__link">
|
||||
11.9.4. 局限性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -1609,7 +1625,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1623,7 +1639,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1868,29 +1884,29 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1181" class="md-nav__link">
|
||||
11.8.1. 简单实现
|
||||
<a href="#1191" class="md-nav__link">
|
||||
11.9.1. 简单实现
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1182" class="md-nav__link">
|
||||
11.8.2. 完整实现
|
||||
<a href="#1192" class="md-nav__link">
|
||||
11.9.2. 完整实现
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1183" class="md-nav__link">
|
||||
11.8.3. 算法特性
|
||||
<a href="#1193" class="md-nav__link">
|
||||
11.9.3. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1184" class="md-nav__link">
|
||||
11.8.4. 局限性
|
||||
<a href="#1194" class="md-nav__link">
|
||||
11.9.4. 局限性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -1918,9 +1934,9 @@
|
||||
|
||||
|
||||
|
||||
<h1 id="118">11.8. 计数排序<a class="headerlink" href="#118" title="Permanent link">¶</a></h1>
|
||||
<h1 id="119">11.9. 计数排序<a class="headerlink" href="#119" title="Permanent link">¶</a></h1>
|
||||
<p>「计数排序 Counting Sort」通过统计元素数量来实现排序,通常应用于整数数组。</p>
|
||||
<h2 id="1181">11.8.1. 简单实现<a class="headerlink" href="#1181" title="Permanent link">¶</a></h2>
|
||||
<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> ,其中的元素都是“非负整数”。计数排序的整体流程如下:</p>
|
||||
<ol>
|
||||
<li>遍历数组,找出数组中的最大数字,记为 <span class="arithmatex">\(m\)</span> ,然后创建一个长度为 <span class="arithmatex">\(m + 1\)</span> 的辅助数组 <code>counter</code> ;</li>
|
||||
@@ -2165,7 +2181,7 @@
|
||||
<p class="admonition-title">计数排序与桶排序的联系</p>
|
||||
<p>从桶排序的角度看,我们可以将计数排序中的计数数组 <code>counter</code> 的每个索引视为一个桶,将统计数量的过程看作是将各个元素分配到对应的桶中。本质上,计数排序是桶排序在整型数据下的一个特例。</p>
|
||||
</div>
|
||||
<h2 id="1182">11.8.2. 完整实现<a class="headerlink" href="#1182" title="Permanent link">¶</a></h2>
|
||||
<h2 id="1192">11.9.2. 完整实现<a class="headerlink" href="#1192" title="Permanent link">¶</a></h2>
|
||||
<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">\[
|
||||
@@ -2525,13 +2541,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="1183">11.8.3. 算法特性<a class="headerlink" href="#1183" title="Permanent link">¶</a></h2>
|
||||
<h2 id="1193">11.9.3. 算法特性<a class="headerlink" href="#1193" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n + m)\)</span></strong> :涉及遍历 <code>nums</code> 和遍历 <code>counter</code> ,都使用线性时间。一般情况下 <span class="arithmatex">\(n \gg m\)</span> ,时间复杂度趋于 <span class="arithmatex">\(O(n)\)</span> 。</li>
|
||||
<li><strong>空间复杂度 <span class="arithmatex">\(O(n + m)\)</span> 、非原地排序</strong> :借助了长度分别为 <span class="arithmatex">\(n\)</span> 和 <span class="arithmatex">\(m\)</span> 的数组 <code>res</code> 和 <code>counter</code> 。</li>
|
||||
<li><strong>稳定排序</strong>:由于向 <code>res</code> 中填充元素的顺序是“从右向左”的,因此倒序遍历 <code>nums</code> 可以避免改变相等元素之间的相对位置,从而实现稳定排序。实际上,正序遍历 <code>nums</code> 也可以得到正确的排序结果,但结果是非稳定的。</li>
|
||||
</ul>
|
||||
<h2 id="1184">11.8.4. 局限性<a class="headerlink" href="#1184" title="Permanent link">¶</a></h2>
|
||||
<h2 id="1194">11.9.4. 局限性<a class="headerlink" href="#1194" title="Permanent link">¶</a></h2>
|
||||
<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>
|
||||
@@ -2612,7 +2628,7 @@
|
||||
<nav class="md-footer__inner md-grid" aria-label="页脚" >
|
||||
|
||||
|
||||
<a href="../bucket_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.7. &nbsp; 桶排序" rel="prev">
|
||||
<a href="../bucket_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.8. &nbsp; 桶排序" rel="prev">
|
||||
<div class="md-footer__button md-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</div>
|
||||
@@ -2621,20 +2637,20 @@
|
||||
上一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a href="../radix_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.9. &nbsp; 基数排序" rel="next">
|
||||
<a href="../radix_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.10. &nbsp; 基数排序" rel="next">
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
下一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
|
||||
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 68 KiB |
@@ -15,13 +15,17 @@
|
||||
<link rel="canonical" href="https://www.hello-algo.com/chapter_sorting/heap_sort/">
|
||||
|
||||
|
||||
<link rel="prev" href="../merge_sort/">
|
||||
|
||||
|
||||
<link rel="next" href="../bucket_sort/">
|
||||
|
||||
<link rel="icon" href="../../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.4.2, mkdocs-material-9.1.6">
|
||||
|
||||
|
||||
|
||||
<title>堆排序 - Hello 算法</title>
|
||||
<title>11.7. 堆排序(New) - Hello 算法</title>
|
||||
|
||||
|
||||
|
||||
@@ -75,7 +79,7 @@
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#_1" class="md-skip">
|
||||
<a href="#117" class="md-skip">
|
||||
跳转至
|
||||
</a>
|
||||
|
||||
@@ -109,7 +113,7 @@
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
堆排序
|
||||
11.7. 堆排序(New)
|
||||
|
||||
</span>
|
||||
</div>
|
||||
@@ -1375,16 +1379,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
|
||||
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
|
||||
|
||||
|
||||
|
||||
|
||||
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_12" >
|
||||
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_12" checked>
|
||||
|
||||
|
||||
|
||||
@@ -1405,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1415,7 +1423,7 @@
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_12_label" aria-expanded="false">
|
||||
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_12_label" aria-expanded="true">
|
||||
<label class="md-nav__title" for="__nav_12">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
11. 排序算法
|
||||
@@ -1443,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1510,10 +1518,65 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item md-nav__item--active">
|
||||
|
||||
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
11.7. 堆排序(New)
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary" aria-label="目录">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
目录
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1171" class="md-nav__link">
|
||||
11.7.1. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1527,7 +1590,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1541,7 +1604,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1555,7 +1618,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1793,6 +1856,21 @@
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
目录
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1171" class="md-nav__link">
|
||||
11.7.1. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1814,12 +1892,286 @@
|
||||
|
||||
|
||||
|
||||
<h1 id="_1">堆排序<a class="headerlink" href="#_1" title="Permanent link">¶</a></h1>
|
||||
<h1 id="117">11.7. 堆排序<a class="headerlink" href="#117" title="Permanent link">¶</a></h1>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>阅读本节前,请确保已完成堆章节的学习。</p>
|
||||
</div>
|
||||
<p>「堆排序 Heap Sort」是一种基于堆数据结构实现的高效排序算法。我们可以利用已经学过的“建堆操作”和“元素出堆操作”实现堆排序:</p>
|
||||
<ol>
|
||||
<li>输入数组并建立小顶堆,此时最小元素位于堆顶。</li>
|
||||
<li>初始化一个数组 <code>res</code> ,用于存储排序结果。</li>
|
||||
<li>循环执行 <span class="arithmatex">\(n\)</span> 轮出堆操作,并依次将出堆元素记录至 <code>res</code> ,即可得到从小到大排序的序列。</li>
|
||||
</ol>
|
||||
<p>该方法虽然可行,但需要借助一个额外数组,比较浪费空间。在实际中,我们通常使用一种更加优雅的实现方式。设数组的长度为 <span class="arithmatex">\(n\)</span> ,堆排序的流程如下:</p>
|
||||
<ol>
|
||||
<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>
|
||||
</ol>
|
||||
<p>实际上,元素出堆操作中也包含第 <code>2.</code> 和 <code>3.</code> 步,只是多了一个弹出元素的步骤。</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"><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">
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="堆排序步骤" src="../heap_sort.assets/heap_sort_step1.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step2" src="../heap_sort.assets/heap_sort_step2.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step3" src="../heap_sort.assets/heap_sort_step3.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step4" src="../heap_sort.assets/heap_sort_step4.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step5" src="../heap_sort.assets/heap_sort_step5.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step6" src="../heap_sort.assets/heap_sort_step6.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step7" src="../heap_sort.assets/heap_sort_step7.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step8" src="../heap_sort.assets/heap_sort_step8.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step9" src="../heap_sort.assets/heap_sort_step9.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step10" src="../heap_sort.assets/heap_sort_step10.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step11" src="../heap_sort.assets/heap_sort_step11.png" /></p>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<p><img alt="heap_sort_step12" src="../heap_sort.assets/heap_sort_step12.png" /></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>在代码实现中,我们使用了与堆章节相同的从顶至底堆化(Sift Down)的函数。值得注意的是,由于堆的长度会随着提取最大元素而减小,因此我们需要给 Sift Down 函数添加一个长度参数 <span class="arithmatex">\(n\)</span> ,用于指定堆的当前有效长度。</p>
|
||||
<div class="tabbed-set tabbed-alternate" data-tabs="2:10"><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" /><div class="tabbed-labels"><label for="__tabbed_2_1">Java</label><label for="__tabbed_2_2">C++</label><label for="__tabbed_2_3">Python</label><label for="__tabbed_2_4">Go</label><label for="__tabbed_2_5">JavaScript</label><label for="__tabbed_2_6">TypeScript</label><label for="__tabbed_2_7">C</label><label for="__tabbed_2_8">C#</label><label for="__tabbed_2_9">Swift</label><label for="__tabbed_2_10">Zig</label></div>
|
||||
<div class="tabbed-content">
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.java</span><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="cm">/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */</span>
|
||||
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="kt">void</span><span class="w"> </span><span class="nf">siftDown</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">n</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="kc">true</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="w"> </span><span class="c1">// 判断节点 i, l, r 中值最大的节点,记为 ma</span>
|
||||
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">*</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">1</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">*</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">2</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="kt">int</span><span class="w"> </span><span class="n">ma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">l</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="n">nums</span><span class="o">[</span><span class="n">l</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">ma</span><span class="o">]</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a><span class="w"> </span><span class="n">ma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">l</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">r</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="n">nums</span><span class="o">[</span><span class="n">r</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">ma</span><span class="o">]</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a><span class="w"> </span><span class="n">ma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a><span class="w"> </span><span class="c1">// 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出</span>
|
||||
<a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ma</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">i</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-14" name="__codelineno-0-14" href="#__codelineno-0-14"></a><span class="w"> </span><span class="k">break</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a><span class="w"> </span><span class="c1">// 交换两节点</span>
|
||||
<a id="__codelineno-0-16" name="__codelineno-0-16" href="#__codelineno-0-16"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">temp</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-0-17" name="__codelineno-0-17" href="#__codelineno-0-17"></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">nums</span><span class="o">[</span><span class="n">ma</span><span class="o">]</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-18" name="__codelineno-0-18" href="#__codelineno-0-18"></a><span class="w"> </span><span class="n">nums</span><span class="o">[</span><span class="n">ma</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">temp</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-19" name="__codelineno-0-19" href="#__codelineno-0-19"></a><span class="w"> </span><span class="c1">// 循环向下堆化</span>
|
||||
<a id="__codelineno-0-20" name="__codelineno-0-20" href="#__codelineno-0-20"></a><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ma</span><span class="p">;</span>
|
||||
<a id="__codelineno-0-21" name="__codelineno-0-21" href="#__codelineno-0-21"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-0-22" name="__codelineno-0-22" href="#__codelineno-0-22"></a><span class="p">}</span>
|
||||
<a id="__codelineno-0-23" name="__codelineno-0-23" href="#__codelineno-0-23"></a>
|
||||
<a id="__codelineno-0-24" name="__codelineno-0-24" href="#__codelineno-0-24"></a><span class="cm">/* 堆排序 */</span>
|
||||
<a id="__codelineno-0-25" name="__codelineno-0-25" href="#__codelineno-0-25"></a><span class="kt">void</span><span class="w"> </span><span class="nf">heapSort</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="p">{</span>
|
||||
<a id="__codelineno-0-26" name="__codelineno-0-26" href="#__codelineno-0-26"></a><span class="w"> </span><span class="c1">// 建堆操作:堆化除叶节点以外的其他所有节点</span>
|
||||
<a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></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">2</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-0-28" name="__codelineno-0-28" href="#__codelineno-0-28"></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">nums</span><span class="p">.</span><span class="na">length</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">);</span>
|
||||
<a id="__codelineno-0-29" name="__codelineno-0-29" href="#__codelineno-0-29"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-0-30" name="__codelineno-0-30" href="#__codelineno-0-30"></a><span class="w"> </span><span class="c1">// 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-0-31" name="__codelineno-0-31" href="#__codelineno-0-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-0-32" name="__codelineno-0-32" href="#__codelineno-0-32"></a><span class="w"> </span><span class="c1">// 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-0-33" name="__codelineno-0-33" href="#__codelineno-0-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-0-34" name="__codelineno-0-34" href="#__codelineno-0-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-0-35" name="__codelineno-0-35" href="#__codelineno-0-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>
|
||||
<a id="__codelineno-0-36" name="__codelineno-0-36" href="#__codelineno-0-36"></a><span class="w"> </span><span class="c1">// 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-0-37" name="__codelineno-0-37" href="#__codelineno-0-37"></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>
|
||||
<a id="__codelineno-0-38" name="__codelineno-0-38" href="#__codelineno-0-38"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-0-39" name="__codelineno-0-39" href="#__codelineno-0-39"></a><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.cpp</span><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="cm">/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */</span>
|
||||
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="kt">void</span><span class="w"> </span><span class="nf">siftDown</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">n</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="nb">true</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="w"> </span><span class="c1">// 判断节点 i, l, r 中值最大的节点,记为 ma</span>
|
||||
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">*</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">1</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="kt">int</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">*</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">2</span><span class="p">;</span>
|
||||
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">ma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">i</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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">l</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="n">nums</span><span class="p">[</span><span class="n">l</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">ma</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="n">ma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">l</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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">r</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="n">nums</span><span class="p">[</span><span class="n">r</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">ma</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="n">ma</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">r</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">// 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出</span>
|
||||
<a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ma</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
|
||||
<a id="__codelineno-1-14" name="__codelineno-1-14" href="#__codelineno-1-14"></a><span class="w"> </span><span class="k">break</span><span class="p">;</span>
|
||||
<a id="__codelineno-1-15" name="__codelineno-1-15" href="#__codelineno-1-15"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-1-16" name="__codelineno-1-16" href="#__codelineno-1-16"></a><span class="w"> </span><span class="c1">// 交换两节点</span>
|
||||
<a id="__codelineno-1-17" name="__codelineno-1-17" href="#__codelineno-1-17"></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="n">i</span><span class="p">],</span><span class="w"> </span><span class="n">nums</span><span class="p">[</span><span class="n">ma</span><span class="p">]);</span>
|
||||
<a id="__codelineno-1-18" name="__codelineno-1-18" href="#__codelineno-1-18"></a><span class="w"> </span><span class="c1">// 循环向下堆化</span>
|
||||
<a id="__codelineno-1-19" name="__codelineno-1-19" href="#__codelineno-1-19"></a><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ma</span><span class="p">;</span>
|
||||
<a id="__codelineno-1-20" name="__codelineno-1-20" href="#__codelineno-1-20"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-1-21" name="__codelineno-1-21" href="#__codelineno-1-21"></a><span class="p">}</span>
|
||||
<a id="__codelineno-1-22" name="__codelineno-1-22" href="#__codelineno-1-22"></a>
|
||||
<a id="__codelineno-1-23" name="__codelineno-1-23" href="#__codelineno-1-23"></a><span class="cm">/* 堆排序 */</span>
|
||||
<a id="__codelineno-1-24" name="__codelineno-1-24" href="#__codelineno-1-24"></a><span class="kt">void</span><span class="w"> </span><span class="nf">heapSort</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="p">{</span>
|
||||
<a id="__codelineno-1-25" name="__codelineno-1-25" href="#__codelineno-1-25"></a><span class="w"> </span><span class="c1">// 建堆操作:堆化除叶节点以外的其他所有节点</span>
|
||||
<a id="__codelineno-1-26" name="__codelineno-1-26" href="#__codelineno-1-26"></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">2</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-27" name="__codelineno-1-27" href="#__codelineno-1-27"></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">nums</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span><span class="w"> </span><span class="n">i</span><span class="p">);</span>
|
||||
<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-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>
|
||||
<a id="__codelineno-1-35" name="__codelineno-1-35" href="#__codelineno-1-35"></a><span class="w"> </span><span class="p">}</span>
|
||||
<a id="__codelineno-1-36" name="__codelineno-1-36" href="#__codelineno-1-36"></a><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.py</span><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="k">def</span> <span class="nf">sift_down</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">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">i</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
|
||||
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="w"> </span><span class="sd">"""堆的长度为 n ,从节点 i 开始,从顶至底堆化"""</span>
|
||||
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||||
<a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a> <span class="c1"># 判断节点 i, l, r 中值最大的节点,记为 ma</span>
|
||||
<a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a> <span class="n">l</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span>
|
||||
<a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a> <span class="n">r</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">*</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">2</span>
|
||||
<a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a> <span class="n">ma</span> <span class="o">=</span> <span class="n">i</span>
|
||||
<a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a> <span class="k">if</span> <span class="n">l</span> <span class="o"><</span> <span class="n">n</span> <span class="ow">and</span> <span class="n">nums</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="o">></span> <span class="n">nums</span><span class="p">[</span><span class="n">ma</span><span class="p">]:</span>
|
||||
<a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a> <span class="n">ma</span> <span class="o">=</span> <span class="n">l</span>
|
||||
<a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a> <span class="k">if</span> <span class="n">r</span> <span class="o"><</span> <span class="n">n</span> <span class="ow">and</span> <span class="n">nums</span><span class="p">[</span><span class="n">r</span><span class="p">]</span> <span class="o">></span> <span class="n">nums</span><span class="p">[</span><span class="n">ma</span><span class="p">]:</span>
|
||||
<a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a> <span class="n">ma</span> <span class="o">=</span> <span class="n">r</span>
|
||||
<a id="__codelineno-2-12" name="__codelineno-2-12" href="#__codelineno-2-12"></a> <span class="c1"># 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出</span>
|
||||
<a id="__codelineno-2-13" name="__codelineno-2-13" href="#__codelineno-2-13"></a> <span class="k">if</span> <span class="n">ma</span> <span class="o">==</span> <span class="n">i</span><span class="p">:</span>
|
||||
<a id="__codelineno-2-14" name="__codelineno-2-14" href="#__codelineno-2-14"></a> <span class="k">break</span>
|
||||
<a id="__codelineno-2-15" name="__codelineno-2-15" href="#__codelineno-2-15"></a> <span class="c1"># 交换两节点</span>
|
||||
<a id="__codelineno-2-16" name="__codelineno-2-16" href="#__codelineno-2-16"></a> <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="n">ma</span><span class="p">]</span> <span class="o">=</span> <span class="n">nums</span><span class="p">[</span><span class="n">ma</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-2-17" name="__codelineno-2-17" href="#__codelineno-2-17"></a> <span class="c1"># 循环向下堆化</span>
|
||||
<a id="__codelineno-2-18" name="__codelineno-2-18" href="#__codelineno-2-18"></a> <span class="n">i</span> <span class="o">=</span> <span class="n">ma</span>
|
||||
<a id="__codelineno-2-19" name="__codelineno-2-19" href="#__codelineno-2-19"></a>
|
||||
<a id="__codelineno-2-20" name="__codelineno-2-20" href="#__codelineno-2-20"></a><span class="k">def</span> <span class="nf">heap_sort</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>
|
||||
<a id="__codelineno-2-21" name="__codelineno-2-21" href="#__codelineno-2-21"></a><span class="w"> </span><span class="sd">"""堆排序"""</span>
|
||||
<a id="__codelineno-2-22" name="__codelineno-2-22" href="#__codelineno-2-22"></a> <span class="c1"># 建堆操作:堆化除叶节点以外的其他所有节点</span>
|
||||
<a id="__codelineno-2-23" name="__codelineno-2-23" href="#__codelineno-2-23"></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">2</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
|
||||
<a id="__codelineno-2-24" name="__codelineno-2-24" href="#__codelineno-2-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-2-25" name="__codelineno-2-25" href="#__codelineno-2-25"></a> <span class="c1"># 从堆中提取最大元素,循环 n-1 轮</span>
|
||||
<a id="__codelineno-2-26" name="__codelineno-2-26" href="#__codelineno-2-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-2-27" name="__codelineno-2-27" href="#__codelineno-2-27"></a> <span class="c1"># 交换根节点与最右叶节点(即交换首元素与尾元素)</span>
|
||||
<a id="__codelineno-2-28" name="__codelineno-2-28" href="#__codelineno-2-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-2-29" name="__codelineno-2-29" href="#__codelineno-2-29"></a> <span class="c1"># 以根节点为起点,从顶至底进行堆化</span>
|
||||
<a id="__codelineno-2-30" name="__codelineno-2-30" href="#__codelineno-2-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>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.go</span><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="p">[</span><span class="nx">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="kd">func</span><span class="p">]{</span><span class="nx">siftDown</span><span class="p">}</span>
|
||||
<a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>
|
||||
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="p">[</span><span class="nx">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="kd">func</span><span class="p">]{</span><span class="nx">heapSort</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.js</span><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="p">[</span><span class="kd">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="nx">func</span><span class="p">]{</span><span class="nx">siftDown</span><span class="p">}</span>
|
||||
<a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>
|
||||
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="p">[</span><span class="kd">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="nx">func</span><span class="p">]{</span><span class="nx">heapSort</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.ts</span><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="p">[</span><span class="kd">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="nx">func</span><span class="p">]{</span><span class="nx">siftDown</span><span class="p">}</span>
|
||||
<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a>
|
||||
<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="p">[</span><span class="kd">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="nx">func</span><span class="p">]{</span><span class="nx">heapSort</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.c</span><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="p">[</span><span class="n">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="n">func</span><span class="p">]{</span><span class="n">siftDown</span><span class="p">}</span>
|
||||
<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a>
|
||||
<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="p">[</span><span class="n">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="n">func</span><span class="p">]{</span><span class="n">heapSort</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.cs</span><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="na">[class]</span><span class="p">{</span><span class="n">heap_sort</span><span class="p">}</span><span class="o">-</span><span class="p">[</span><span class="n">func</span><span class="p">]{</span><span class="n">siftDown</span><span class="p">}</span>
|
||||
<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a>
|
||||
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="na">[class]</span><span class="p">{</span><span class="n">heap_sort</span><span class="p">}</span><span class="o">-</span><span class="p">[</span><span class="n">func</span><span class="p">]{</span><span class="n">heapSort</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.swift</span><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="p">[</span><span class="kd">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="kd">func</span><span class="p">]{</span><span class="n">siftDown</span><span class="p">}</span>
|
||||
<a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a>
|
||||
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="p">[</span><span class="kd">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="kd">func</span><span class="p">]{</span><span class="n">heapSort</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
<div class="tabbed-block">
|
||||
<div class="highlight"><span class="filename">heap_sort.zig</span><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="p">[</span><span class="n">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="n">func</span><span class="p">]{</span><span class="n">siftDown</span><span class="p">}</span>
|
||||
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a>
|
||||
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="p">[</span><span class="n">class</span><span class="p">]{}</span><span class="o">-</span><span class="p">[</span><span class="n">func</span><span class="p">]{</span><span class="n">heapSort</span><span class="p">}</span>
|
||||
</code></pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 id="1171">11.7.1. 算法特性<a class="headerlink" href="#1171" title="Permanent link">¶</a></h2>
|
||||
<ul>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(n \log n)\)</span> 、非自适应排序</strong> :从堆中提取最大元素的时间复杂度为 <span class="arithmatex">\(O(\log n)\)</span> ,共循环 <span class="arithmatex">\(n - 1\)</span> 轮。</li>
|
||||
<li><strong>空间复杂度 <span class="arithmatex">\(O(1)\)</span> 、原地排序</strong> :几个指针变量使用 <span class="arithmatex">\(O(1)\)</span> 空间。元素交换和堆化操作都是在原数组上进行的。</li>
|
||||
<li><strong>非稳定排序</strong>:在交换堆顶元素和堆底元素时,相等元素的相对位置可能发生变化。</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h2 id="__comments">评论</h2>
|
||||
<!-- Insert generated snippet here -->
|
||||
<script
|
||||
src="https://giscus.app/client.js"
|
||||
data-repo="krahets/hello-algo"
|
||||
data-repo-id="R_kgDOIXtSqw"
|
||||
data-category="Announcements"
|
||||
data-category-id="DIC_kwDOIXtSq84CSZk_"
|
||||
data-mapping="pathname"
|
||||
data-strict="1"
|
||||
data-reactions-enabled="1"
|
||||
data-emit-metadata="0"
|
||||
data-input-position="bottom"
|
||||
data-theme="preferred_color_scheme"
|
||||
data-lang="zh-CN"
|
||||
crossorigin="anonymous"
|
||||
async
|
||||
>
|
||||
</script>
|
||||
<!-- Synchronize Giscus theme with palette -->
|
||||
<script>
|
||||
var giscus = document.querySelector("script[src*=giscus]")
|
||||
|
||||
/* Set palette on initial load */
|
||||
var palette = __md_get("__palette")
|
||||
if (palette && typeof palette.color === "object") {
|
||||
var theme = palette.color.scheme === "slate" ? "dark" : "light"
|
||||
giscus.setAttribute("data-theme", theme)
|
||||
}
|
||||
|
||||
/* Register event handlers after documented loaded */
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var ref = document.querySelector("[data-md-component=palette]")
|
||||
ref.addEventListener("change", function() {
|
||||
var palette = __md_get("__palette")
|
||||
if (palette && typeof palette.color === "object") {
|
||||
var theme = palette.color.scheme === "slate" ? "dark" : "light"
|
||||
|
||||
/* Instruct Giscus to change theme */
|
||||
var frame = document.querySelector(".giscus-frame")
|
||||
frame.contentWindow.postMessage(
|
||||
{ giscus: { setConfig: { theme } } },
|
||||
"https://giscus.app"
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
</article>
|
||||
</div>
|
||||
@@ -1839,6 +2191,42 @@
|
||||
<footer class="md-footer">
|
||||
|
||||
|
||||
|
||||
<nav class="md-footer__inner md-grid" aria-label="页脚" >
|
||||
|
||||
|
||||
<a href="../merge_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.6. &nbsp; 归并排序" rel="prev">
|
||||
<div class="md-footer__button md-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</div>
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
上一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.6. 归并排序
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a href="../bucket_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.8. &nbsp; 桶排序" rel="next">
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
下一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.8. 桶排序
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4Z"/></svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
|
||||
|
||||
<div class="md-footer-meta md-typeset">
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1572,9 +1574,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1588,7 +1604,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1602,7 +1618,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1616,7 +1632,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<link rel="prev" href="../quick_sort/">
|
||||
|
||||
|
||||
<link rel="next" href="../bucket_sort/">
|
||||
<link rel="next" href="../heap_sort/">
|
||||
|
||||
<link rel="icon" href="../../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.4.2, mkdocs-material-9.1.6">
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1572,9 +1574,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1588,7 +1604,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1602,7 +1618,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1616,7 +1632,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -2525,13 +2541,13 @@
|
||||
|
||||
|
||||
|
||||
<a href="../bucket_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.7. &nbsp; 桶排序" rel="next">
|
||||
<a href="../heap_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.7. &nbsp; 堆排序(New)" rel="next">
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
下一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.7. 桶排序
|
||||
11.7. 堆排序(New)
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1586,9 +1588,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1602,7 +1618,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1616,7 +1632,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1630,7 +1646,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -2979,13 +2995,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">哨兵划分中“从右往左查找”与“从左往右查找”的顺序可以交换吗?</p>
|
||||
<p>不行,当我们以最左端元素为基准数时,必须先“从右往左查找”再“从左往右查找”。这个结论有些反直觉,我们来剖析一下原因。</p>
|
||||
<p>哨兵划分 <code>partition()</code> 的最后一步是交换 <code>nums[left]</code> 和 <code>nums[i]</code> 。完成交换后,基准数左边的元素都 <code><=</code> 基准数,<strong>这就要求最后一步交换前 <code>nums[left] >= nums[i]</code> 必须成立</strong>。假设我们先“从左往右查找”,那么如果找不到比基准数更小的元素,<strong>则会在 <code>i == j</code> 时跳出循环,此时可能 <code>nums[j] == nums[i] > nums[left]</code></strong>。也就是说,此时最后一步交换操作会把一个比基准数更大的元素交换至数组最左端,导致哨兵划分失败。</p>
|
||||
<p>举个例子,给定数组 <code>[0, 0, 0, 0, 1]</code> ,如果先“从左向右查找”,哨兵划分后数组为 <code>[1, 0, 0, 0, 0]</code> ,这个结果是不正确的。</p>
|
||||
<p>再深入思考一下,如果我们选择 <code>nums[right]</code> 为基准数,那么正好反过来,必须先“从左往右查找”。</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
|
||||
<title>11.9. 基数排序 - Hello 算法</title>
|
||||
<title>11.10. 基数排序 - Hello 算法</title>
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#119" class="md-skip">
|
||||
<a href="#1110" class="md-skip">
|
||||
跳转至
|
||||
</a>
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
|
||||
</span>
|
||||
</div>
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1517,9 +1519,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1533,7 +1549,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1556,12 +1572,12 @@
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1580,15 +1596,15 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1191" class="md-nav__link">
|
||||
11.9.1. 算法流程
|
||||
<a href="#11101" class="md-nav__link">
|
||||
11.10.1. 算法流程
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1192" class="md-nav__link">
|
||||
11.9.2. 算法特性
|
||||
<a href="#11102" class="md-nav__link">
|
||||
11.10.2. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -1609,7 +1625,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1854,15 +1870,15 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1191" class="md-nav__link">
|
||||
11.9.1. 算法流程
|
||||
<a href="#11101" class="md-nav__link">
|
||||
11.10.1. 算法流程
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1192" class="md-nav__link">
|
||||
11.9.2. 算法特性
|
||||
<a href="#11102" class="md-nav__link">
|
||||
11.10.2. 算法特性
|
||||
</a>
|
||||
|
||||
</li>
|
||||
@@ -1890,10 +1906,10 @@
|
||||
|
||||
|
||||
|
||||
<h1 id="119">11.9. 基数排序<a class="headerlink" href="#119" title="Permanent link">¶</a></h1>
|
||||
<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>「基数排序 Radix Sort」的核心思想与计数排序一致,也通过统计个数来实现排序。在此基础上,基数排序利用数字各位之间的递进关系,依次对每一位进行排序,从而得到最终的排序结果。</p>
|
||||
<h2 id="1191">11.9.1. 算法流程<a class="headerlink" href="#1191" title="Permanent link">¶</a></h2>
|
||||
<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> 位,基数排序的步骤如下:</p>
|
||||
<ol>
|
||||
<li>初始化位数 <span class="arithmatex">\(k = 1\)</span> ;</li>
|
||||
@@ -2450,7 +2466,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<p class="admonition-title">为什么从最低位开始排序?</p>
|
||||
<p>在连续的排序轮次中,后一轮排序会覆盖前一轮排序的结果。举例来说,如果第一轮排序结果 <span class="arithmatex">\(a < b\)</span> ,而第二轮排序结果 <span class="arithmatex">\(a > b\)</span> ,那么第二轮的结果将取代第一轮的结果。由于数字的高位优先级高于低位,我们应该先排序低位再排序高位。</p>
|
||||
</div>
|
||||
<h2 id="1192">11.9.2. 算法特性<a class="headerlink" href="#1192" title="Permanent link">¶</a></h2>
|
||||
<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>
|
||||
<ul>
|
||||
<li><strong>时间复杂度 <span class="arithmatex">\(O(nk)\)</span></strong> :设数据量为 <span class="arithmatex">\(n\)</span> 、数据为 <span class="arithmatex">\(d\)</span> 进制、最大位数为 <span class="arithmatex">\(k\)</span> ,则对某一位执行计数排序使用 <span class="arithmatex">\(O(n + d)\)</span> 时间,排序所有 <span class="arithmatex">\(k\)</span> 位使用 <span class="arithmatex">\(O((n + d)k)\)</span> 时间。通常情况下,<span class="arithmatex">\(d\)</span> 和 <span class="arithmatex">\(k\)</span> 都相对较小,时间复杂度趋向 <span class="arithmatex">\(O(n)\)</span> 。</li>
|
||||
@@ -2534,7 +2550,7 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
<nav class="md-footer__inner md-grid" aria-label="页脚" >
|
||||
|
||||
|
||||
<a href="../counting_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.8. &nbsp; 计数排序" rel="prev">
|
||||
<a href="../counting_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.9. &nbsp; 计数排序" rel="prev">
|
||||
<div class="md-footer__button md-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</div>
|
||||
@@ -2543,20 +2559,20 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
|
||||
上一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<a href="../summary/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.10. &nbsp; 小结" rel="next">
|
||||
<a href="../summary/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.11. &nbsp; 小结" rel="next">
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
下一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
|
||||
<title>11.2. 选择排序(New) - Hello 算法</title>
|
||||
<title>11.2. 选择排序(New) - Hello 算法</title>
|
||||
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
|
||||
</span>
|
||||
</div>
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1458,12 +1460,12 @@
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1558,9 +1560,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1574,7 +1590,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1588,7 +1604,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1602,7 +1618,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1497,7 +1499,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1565,9 +1567,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1581,7 +1597,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1595,7 +1611,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1609,7 +1625,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../summary/" class="md-nav__link">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -2017,13 +2033,13 @@
|
||||
|
||||
|
||||
|
||||
<a href="../selection_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.2. &nbsp; 选择排序(New)" rel="next">
|
||||
<a href="../selection_sort/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.2. &nbsp; 选择排序(New)" rel="next">
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
下一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
|
||||
<title>11.10. 小结 - Hello 算法</title>
|
||||
<title>11.11. 小结 - Hello 算法</title>
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#1110" class="md-skip">
|
||||
<a href="#1111" class="md-skip">
|
||||
跳转至
|
||||
</a>
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
<div class="md-header__topic" data-md-component="header-topic">
|
||||
<span class="md-ellipsis">
|
||||
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
|
||||
</span>
|
||||
</div>
|
||||
@@ -1411,6 +1411,8 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1449,7 +1451,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../selection_sort/" class="md-nav__link">
|
||||
11.2. 选择排序(New)
|
||||
11.2. 选择排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1517,9 +1519,23 @@
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../heap_sort/" class="md-nav__link">
|
||||
11.7. 堆排序(New)
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../bucket_sort/" class="md-nav__link">
|
||||
11.7. 桶排序
|
||||
11.8. 桶排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1533,7 +1549,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../counting_sort/" class="md-nav__link">
|
||||
11.8. 计数排序
|
||||
11.9. 计数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1547,7 +1563,7 @@
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="../radix_sort/" class="md-nav__link">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1569,10 +1585,41 @@
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__link md-nav__link--active" for="__toc">
|
||||
11.11. 小结
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
</label>
|
||||
|
||||
<a href="./" class="md-nav__link md-nav__link--active">
|
||||
11.10. 小结
|
||||
11.11. 小结
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<nav class="md-nav md-nav--secondary" aria-label="目录">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
目录
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#11111-q-a" class="md-nav__link">
|
||||
11.11.1. Q & A
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -1809,6 +1856,21 @@
|
||||
|
||||
|
||||
|
||||
<label class="md-nav__title" for="__toc">
|
||||
<span class="md-nav__icon md-icon"></span>
|
||||
目录
|
||||
</label>
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#11111-q-a" class="md-nav__link">
|
||||
11.11.1. Q & A
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1830,7 +1892,7 @@
|
||||
|
||||
|
||||
|
||||
<h1 id="1110">11.10. 小结<a class="headerlink" href="#1110" title="Permanent link">¶</a></h1>
|
||||
<h1 id="1111">11.11. 小结<a class="headerlink" href="#1111" title="Permanent link">¶</a></h1>
|
||||
<ul>
|
||||
<li>冒泡排序通过交换相邻元素来实现排序。通过添加一个标志位来实现提前返回,我们可以将冒泡排序的最佳时间复杂度优化到 <span class="arithmatex">\(O(n)\)</span> 。</li>
|
||||
<li>插入排序每轮将未排序区间内的元素插入到已排序区间的正确位置,从而完成排序。虽然插入排序的时间复杂度为 <span class="arithmatex">\(O(n^2)\)</span> ,但由于单元操作相对较少,它在小数据量的排序任务中非常受欢迎。</li>
|
||||
@@ -1844,9 +1906,16 @@
|
||||
<p align="center"> Fig. 排序算法对比 </p>
|
||||
|
||||
<ul>
|
||||
<li>总体来看,我们追求运行快、稳定、原地、正向自适应性的排序。显然,如同其他数据结构与算法一样,同时满足这些条件的排序算法并不存在,我们需要根据问题特点来选择排序算法。</li>
|
||||
<li>总的来说,我们希望找到一种排序算法,具有高效率、稳定、原地以及正向自适应性等优点。然而,正如其他数据结构和算法一样,没有一种排序算法能够同时满足所有这些条件。在实际应用中,我们需要根据数据的特性来选择合适的排序算法。</li>
|
||||
</ul>
|
||||
<h2 id="11111-q-a">11.11.1. Q & A<a class="headerlink" href="#11111-q-a" title="Permanent link">¶</a></h2>
|
||||
<div class="admonition question">
|
||||
<p class="admonition-title">哨兵划分中“从右往左查找”与“从左往右查找”的顺序可以交换吗?</p>
|
||||
<p>不行,当我们以最左端元素为基准数时,必须先“从右往左查找”再“从左往右查找”。这个结论有些反直觉,我们来剖析一下原因。</p>
|
||||
<p>哨兵划分 <code>partition()</code> 的最后一步是交换 <code>nums[left]</code> 和 <code>nums[i]</code> 。完成交换后,基准数左边的元素都 <code><=</code> 基准数,<strong>这就要求最后一步交换前 <code>nums[left] >= nums[i]</code> 必须成立</strong>。假设我们先“从左往右查找”,那么如果找不到比基准数更小的元素,<strong>则会在 <code>i == j</code> 时跳出循环,此时可能 <code>nums[j] == nums[i] > nums[left]</code></strong>。也就是说,此时最后一步交换操作会把一个比基准数更大的元素交换至数组最左端,导致哨兵划分失败。</p>
|
||||
<p>举个例子,给定数组 <code>[0, 0, 0, 0, 1]</code> ,如果先“从左向右查找”,哨兵划分后数组为 <code>[1, 0, 0, 0, 0]</code> ,这个结果是不正确的。</p>
|
||||
<p>再深入思考一下,如果我们选择 <code>nums[right]</code> 为基准数,那么正好反过来,必须先“从左往右查找”。</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1924,7 +1993,7 @@
|
||||
<nav class="md-footer__inner md-grid" aria-label="页脚" >
|
||||
|
||||
|
||||
<a href="../radix_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.9. &nbsp; 基数排序" rel="prev">
|
||||
<a href="../radix_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.10. &nbsp; 基数排序" rel="prev">
|
||||
<div class="md-footer__button md-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
|
||||
</div>
|
||||
@@ -1933,7 +2002,7 @@
|
||||
上一页
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
11.9. 基数排序
|
||||
11.10. 基数排序
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||