mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-04 19:54:20 +00:00
feat: Revised the book (#978)
* Sync recent changes to the revised Word. * Revised the preface chapter * Revised the introduction chapter * Revised the computation complexity chapter * Revised the chapter data structure * Revised the chapter array and linked list * Revised the chapter stack and queue * Revised the chapter hashing * Revised the chapter tree * Revised the chapter heap * Revised the chapter graph * Revised the chapter searching * Reivised the sorting chapter * Revised the divide and conquer chapter * Revised the chapter backtacking * Revised the DP chapter * Revised the greedy chapter * Revised the appendix chapter * Revised the preface chapter doubly * Revised the figures
This commit is contained in:
@@ -6,23 +6,25 @@
|
||||
|
||||
先来看一个简单的例子。给定一个长度为 $n$ 的数组 `nums` ,其中的元素都是“非负整数”,计数排序的整体流程如下图所示。
|
||||
|
||||
1. 遍历数组,找出数组中的最大数字,记为 $m$ ,然后创建一个长度为 $m + 1$ 的辅助数组 `counter` 。
|
||||
1. 遍历数组,找出其中的最大数字,记为 $m$ ,然后创建一个长度为 $m + 1$ 的辅助数组 `counter` 。
|
||||
2. **借助 `counter` 统计 `nums` 中各数字的出现次数**,其中 `counter[num]` 对应数字 `num` 的出现次数。统计方法很简单,只需遍历 `nums`(设当前数字为 `num`),每轮将 `counter[num]` 增加 $1$ 即可。
|
||||
3. **由于 `counter` 的各个索引天然有序,因此相当于所有数字已经被排序好了**。接下来,我们遍历 `counter` ,根据各数字的出现次数,将它们按从小到大的顺序填入 `nums` 即可。
|
||||
3. **由于 `counter` 的各个索引天然有序,因此相当于所有数字已经排序好了**。接下来,我们遍历 `counter` ,根据各数字出现次数从小到大的顺序填入 `nums` 即可。
|
||||
|
||||

|
||||
|
||||
代码如下所示:
|
||||
|
||||
```src
|
||||
[file]{counting_sort}-[class]{}-[func]{counting_sort_naive}
|
||||
```
|
||||
|
||||
!!! note "计数排序与桶排序的联系"
|
||||
|
||||
从桶排序的角度看,我们可以将计数排序中的计数数组 `counter` 的每个索引视为一个桶,将统计数量的过程看作是将各个元素分配到对应的桶中。本质上,计数排序是桶排序在整型数据下的一个特例。
|
||||
从桶排序的角度看,我们可以将计数排序中的计数数组 `counter` 的每个索引视为一个桶,将统计数量的过程看作将各个元素分配到对应的桶中。本质上,计数排序是桶排序在整型数据下的一个特例。
|
||||
|
||||
## 完整实现
|
||||
|
||||
细心的同学可能发现,**如果输入数据是对象,上述步骤 `3.` 就失效了**。假设输入数据是商品对象,我们想要按照商品价格(类的成员变量)对商品进行排序,而上述算法只能给出价格的排序结果。
|
||||
细心的读者可能发现了,**如果输入数据是对象,上述步骤 `3.` 就失效了**。假设输入数据是商品对象,我们想按照商品价格(类的成员变量)对商品进行排序,而上述算法只能给出价格的排序结果。
|
||||
|
||||
那么如何才能得到原数据的排序结果呢?我们首先计算 `counter` 的“前缀和”。顾名思义,索引 `i` 处的前缀和 `prefix[i]` 等于数组前 `i` 个元素之和:
|
||||
|
||||
@@ -61,7 +63,7 @@ $$
|
||||
=== "<8>"
|
||||

|
||||
|
||||
计数排序的实现代码如下所示。
|
||||
计数排序的实现代码如下所示:
|
||||
|
||||
```src
|
||||
[file]{counting_sort}-[class]{}-[func]{counting_sort}
|
||||
@@ -75,8 +77,8 @@ $$
|
||||
|
||||
## 局限性
|
||||
|
||||
看到这里,你也许会觉得计数排序非常巧妙,仅通过统计数量就可以实现高效的排序工作。然而,使用计数排序的前置条件相对较为严格。
|
||||
看到这里,你也许会觉得计数排序非常巧妙,仅通过统计数量就可以实现高效的排序。然而,使用计数排序的前置条件相对较为严格。
|
||||
|
||||
**计数排序只适用于非负整数**。若想要将其用于其他类型的数据,需要确保这些数据可以被转换为非负整数,并且在转换过程中不能改变各个元素之间的相对大小关系。例如,对于包含负数的整数数组,可以先给所有数字加上一个常数,将全部数字转化为正数,排序完成后再转换回去即可。
|
||||
**计数排序只适用于非负整数**。若想将其用于其他类型的数据,需要确保这些数据可以转换为非负整数,并且在转换过程中不能改变各个元素之间的相对大小关系。例如,对于包含负数的整数数组,可以先给所有数字加上一个常数,将全部数字转化为正数,排序完成后再转换回去。
|
||||
|
||||
**计数排序适用于数据量大但数据范围较小的情况**。比如,在上述示例中 $m$ 不能太大,否则会占用过多空间。而当 $n \ll m$ 时,计数排序使用 $O(m)$ 时间,可能比 $O(n \log n)$ 的排序算法还要慢。
|
||||
|
||||
Reference in New Issue
Block a user