This commit is contained in:
krahets
2023-05-24 00:32:47 +08:00
parent 9a0252f484
commit c6937e63b7
80 changed files with 4101 additions and 905 deletions

View File

@ -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. &nbsp; 基数排序
11.9. &nbsp; 基数排序
</span>
</div>
@ -1409,6 +1409,8 @@
@ -1445,9 +1447,23 @@
<li class="md-nav__item">
<a href="../selection_sort/" class="md-nav__link">
11.2. &nbsp; 选择排序
</a>
</li>
<li class="md-nav__item">
<a href="../bubble_sort/" class="md-nav__link">
11.2. &nbsp; 冒泡排序
11.3. &nbsp; 冒泡排序
</a>
</li>
@ -1461,7 +1477,7 @@
<li class="md-nav__item">
<a href="../insertion_sort/" class="md-nav__link">
11.3. &nbsp; 插入排序
11.4. &nbsp; 插入排序
</a>
</li>
@ -1475,7 +1491,7 @@
<li class="md-nav__item">
<a href="../quick_sort/" class="md-nav__link">
11.4. &nbsp; 快速排序
11.5. &nbsp; 快速排序
</a>
</li>
@ -1489,7 +1505,7 @@
<li class="md-nav__item">
<a href="../merge_sort/" class="md-nav__link">
11.5. &nbsp; 归并排序
11.6. &nbsp; 归并排序
</a>
</li>
@ -1503,7 +1519,7 @@
<li class="md-nav__item">
<a href="../bucket_sort/" class="md-nav__link">
11.6. &nbsp; 桶排序
11.7. &nbsp; 桶排序
</a>
</li>
@ -1517,7 +1533,7 @@
<li class="md-nav__item">
<a href="../counting_sort/" class="md-nav__link">
11.7. &nbsp; 计数排序
11.8. &nbsp; 计数排序
</a>
</li>
@ -1540,12 +1556,12 @@
<label class="md-nav__link md-nav__link--active" for="__toc">
11.8. &nbsp; 基数排序
11.9. &nbsp; 基数排序
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
11.8. &nbsp; 基数排序
11.9. &nbsp; 基数排序
</a>
@ -1564,15 +1580,15 @@
<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. &nbsp; 算法流程
<a href="#1191" class="md-nav__link">
11.9.1. &nbsp; 算法流程
</a>
</li>
<li class="md-nav__item">
<a href="#1182" class="md-nav__link">
11.8.2. &nbsp; 算法特性
<a href="#1192" class="md-nav__link">
11.9.2. &nbsp; 算法特性
</a>
</li>
@ -1593,7 +1609,7 @@
<li class="md-nav__item">
<a href="../summary/" class="md-nav__link">
11.9. &nbsp; 小结
11.10. &nbsp; 小结
</a>
</li>
@ -1838,15 +1854,15 @@
<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. &nbsp; 算法流程
<a href="#1191" class="md-nav__link">
11.9.1. &nbsp; 算法流程
</a>
</li>
<li class="md-nav__item">
<a href="#1182" class="md-nav__link">
11.8.2. &nbsp; 算法特性
<a href="#1192" class="md-nav__link">
11.9.2. &nbsp; 算法特性
</a>
</li>
@ -1874,10 +1890,10 @@
<h1 id="118">11.8. &nbsp; 基数排序<a class="headerlink" href="#118" title="Permanent link">&para;</a></h1>
<h1 id="119">11.9. &nbsp; 基数排序<a class="headerlink" href="#119" title="Permanent link">&para;</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="1181">11.8.1. &nbsp; 算法流程<a class="headerlink" href="#1181" title="Permanent link">&para;</a></h2>
<h2 id="1191">11.9.1. &nbsp; 算法流程<a class="headerlink" href="#1191" title="Permanent link">&para;</a></h2>
<p>以学号数据为例,假设数字的最低位是第 <span class="arithmatex">\(1\)</span> 位,最高位是第 <span class="arithmatex">\(8\)</span> 位,基数排序的步骤如下:</p>
<ol>
<li>初始化位数 <span class="arithmatex">\(k = 1\)</span> </li>
@ -2434,10 +2450,13 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
<p class="admonition-title">为什么从最低位开始排序?</p>
<p>在连续的排序轮次中,后一轮排序会覆盖前一轮排序的结果。举例来说,如果第一轮排序结果 <span class="arithmatex">\(a &lt; b\)</span> ,而第二轮排序结果 <span class="arithmatex">\(a &gt; b\)</span> ,那么第二轮的结果将取代第一轮的结果。由于数字的高位优先级高于低位,我们应该先排序低位再排序高位。</p>
</div>
<h2 id="1182">11.8.2. &nbsp; 算法特性<a class="headerlink" href="#1182" title="Permanent link">&para;</a></h2>
<p><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></p>
<p><strong>空间复杂度 <span class="arithmatex">\(O(n + d)\)</span></strong> :与计数排序相同,基数排序需要借助长度为 <span class="arithmatex">\(n\)</span><span class="arithmatex">\(d\)</span> 的数组 <code>res</code><code>counter</code> ,因此它是一种“非原地排序”。</p>
<p>基数排序与计数排序一样,都属于稳定排序。相较于计数排序,基数排序适用于数值范围较大的情况,<strong>但前提是数据必须可以表示为固定位数的格式,且位数不能过大</strong>。例如,浮点数不适合使用基数排序,因为其位数 <span class="arithmatex">\(k\)</span> 过大,可能导致时间复杂度 <span class="arithmatex">\(O(nk) \gg O(n^2)\)</span></p>
<h2 id="1192">11.9.2. &nbsp; 算法特性<a class="headerlink" href="#1192" title="Permanent link">&para;</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>
<li><strong>空间复杂度 <span class="arithmatex">\(O(n + d)\)</span> 、非原地排序</strong> :与计数排序相同,基数排序需要借助长度为 <span class="arithmatex">\(n\)</span><span class="arithmatex">\(d\)</span> 的数组 <code>res</code><code>counter</code></li>
<li><strong>稳定排序</strong>:与计数排序相同。</li>
</ul>
@ -2515,7 +2534,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.7. &amp;nbsp; 计数排序" rel="prev">
<a href="../counting_sort/" class="md-footer__link md-footer__link--prev" aria-label="上一页: 11.8. &amp;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>
@ -2524,20 +2543,20 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \bmod d
上一页
</span>
<div class="md-ellipsis">
11.7. &nbsp; 计数排序
11.8. &nbsp; 计数排序
</div>
</div>
</a>
<a href="../summary/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.9. &amp;nbsp; 小结" rel="next">
<a href="../summary/" class="md-footer__link md-footer__link--next" aria-label="下一页: 11.10. &amp;nbsp; 小结" rel="next">
<div class="md-footer__title">
<span class="md-footer__direction">
下一页
</span>
<div class="md-ellipsis">
11.9. &nbsp; 小结
11.10. &nbsp; 小结
</div>
</div>
<div class="md-footer__button md-icon">