-å\9fºæ\95°æ\8e\92åº\8fæ\98¯å°\86å¾\85æ\8e\92åº\8fç \81æ\8b\86å\88\86æ\88\90å¤\9a个é\83¨å\88\86å\88\86å\88«æ\9d¥æ¯\94è¾\83。
+å\9fºæ\95°æ\8e\92åº\8fæ\98¯å°\86å¾\85æ\8e\92åº\8fç\9a\84å\85\83ç´ æ\8b\86å\88\86为 $k$ 个å\85³é\94®å\97ï¼\88æ¯\94è¾\83两个å\85\83ç´ æ\97¶ï¼\8cå\85\88æ¯\94è¾\83第ä¸\80å\85³é\94®å\97ï¼\8cå¦\82æ\9e\9cç\9b¸å\90\8cå\86\8dæ¯\94è¾\83第äº\8cå\85³é\94®å\97â\80¦â\80¦ï¼\89ï¼\8cç\84¶å\90\8eå\85\88对第 $k$ å\85³é\94®å\97è¿\9bè¡\8c稳å®\9aæ\8e\92åº\8fï¼\8cå\86\8d对第 $k-1$ å\85³é\94®å\97è¿\9bè¡\8c稳å®\9aæ\8e\92åº\8fï¼\8cå\86\8d对第 $k-2$ å\85³é\94®å\97è¿\9bè¡\8c稳å®\9aæ\8e\92åº\8fâ\80¦â\80¦æ\9c\80å\90\8e对第ä¸\80å\85³é\94®å\97è¿\9bè¡\8c稳å®\9aæ\8e\92åº\8fï¼\8cè¿\99æ ·å°±å®\8cæ\88\90äº\86对æ\95´ä¸ªå¾\85æ\8e\92åº\8fåº\8få\88\97ç\9a\84稳å®\9aæ\8e\92åº\8f。
-按照排序码的先后顺序,分为两种:
+基数排序的正确性可以自己感性理解一下,也可以参考 https://walkccc.github.io/CLRS/Chap08/8.3/#83-3 。
-1. 高位优先(MSD)
- 先对高位排序,分成若干子序列,对每个子序列根据较低位排序,是一个分、分、……、分、收的过程。
-2. 低位优先(LSD)
- 从低位开始,对于排好的序列用次低位排序,(每次排序的都是全体元素)是一个分、收、分、收、……、分、收的过程。
+一般来说,每个关键字的值域都不大,就可以使用 [计数排序](./counting-sort.md) 作为内层排序,复杂度为 $O(nk+\sum\limits_{i=1}^k w_i)$,其中 $w_i$ 为第 $i$ 关键字的值域大小。
-低位优先速度较快,便于处理,更常用。
+(如果关键字值域很大,就可以直接使用基于比较的 $O(nk\log n)$ 排序而无需使用基数排序了。)
-基数排序对关键码值进行 $O(\log_r n)$ 次运算,因此处理 n 个不同的关键码时,基数排序的时间代价为 $O(n \log n)$ 。
+伪代码:
-### 参考
+$$
+\begin{array}{ll}
+1 & \textbf{Input. } \text{An array } A \text{ consisting of }n\text{ elements, where each element has }k\text{ keys.}\\
+2 & \textbf{Output. } \text{Array }A\text{ will be sorted in nondecreasing order stably.} \\
+3 & \textbf{Method. } \\
+4 & \textbf{for }i\gets k\textbf{ down to }1\\
+5 & \qquad\text{sort }A\text{ into nondecreasing order by the }i\text{-th key stably}
+\end{array}
+$$
+C++ 代码:
+
+```cpp
+const int N = 100010;
+const int W = 100010;
+const int K = 100;
+
+int n, w[K], k, cnt[W];
+
+struct Element
+{
+ int key[K];
+ bool operator<(const Element& y) const // shows how two elements are compared
+ {
+ for (int i = 1; i <= k; ++i)
+ {
+ if (key[i] == y.key[i]) continue;
+ return key[i] < y.key[i];
+ }
+ return false;
+ }
+} a[N], b[N];
+
+void counting_sort(int p)
+{
+ memset(cnt, 0, sizeof(cnt));
+ for (int i = 1; i <= n; ++i) ++cnt[a[i].key[p]];
+ for (int i = 1; i <= w[p]; ++i) cnt[i] += cnt[i - 1];
+ for (int i = 1; i <= n; ++i) b[cnt[a[i].key[p]]--] = a[i];
+ memcpy(a, b, sizeof(a));
+}
+
+void radix_sort()
+{
+ for (int i = k; i >= 1; --i)
+ {
+ counting_sort(i);
+ }
+}
+```
- <http://atool.org/sort.php> ATool 的排序演示动画
- <https://www.geeksforgeeks.org/counting-sort/>
Introsort 的这个限制使得它的最坏时间复杂度是 $O(n\log n)$ 的。
-快速用法:
+用法:
```cpp
// a[0] .. a[n - 1] 为需要排序的数列
-std::sort(a, a + n);
-// 这句代码直接修改 a 数组里的元素顺序,使得现在它是从小到大排列的
+std::sort(a, a + n); // 这句代码直接修改 a 数组里的元素顺序,使得现在它是从小到大排列的
+std::sort(a, a + n, cmp); // cmp 为自定义的比较函数
```
## nth_element
作用是找到选定区间内第 $k$ 大的数,并将所有比它小的数与比它大的数分别置于两侧,返回它的地址。
-原理是未完成的快速排序
+原理是未完成的快速排序。
-用法
+用法:
```cpp
std::nth_element(begin, mid, end);
+std::nth_element(begin, mid, end, cmp);
```
-时间复杂度:期望 $O(n)$
+时间复杂度:期望 $O(n)$ 。
-常用于构建 K-DTree
+常用于构建 K-DTree。
## stable_sort
-稳定的 $O(nlogn)$ 排序,即保证相等元素排序后的相对位置与原序列相同。
+稳定的 $O(n\log n)$ 排序,即保证相等元素排序后的相对位置与原序列相同。
用法
```cpp
+std::stable_sort(begin, end);
std::stable_sort(begin, end, cmp);
```
将序列中前 $k$ 小元素按顺序置于前 $k$ 个位置,后面的元素不保证顺序。
-复杂度: $O(nlogk)$
+复杂度: $O(n\log k)$
用法:
```cpp
std::partial_sort(begin, begin + k, end);
+std::partial_sort(begin, begin + k, end, cmp);
```
原理:
int a[1009], n = 10;
// ......
std::sort(a + 1, a + 1 + n); // 不重载,从小到大排序。
-std::sort(a + 1, a + 1 + n,
- greater<int>()); // 重载小于运算符为大于,从大到小排序。
+std::sort(a + 1, a + 1 + n, greater<int>()); // 重载小于运算符为大于,从大到小排序。
```
```cpp
return (u1.a == u2.a) ? (u1.b > u2.b) : (u1.a > u2.a);
}
// ......
-std::sort(da + 1, da + 1 + 10, cmp); // 不重载,从小到大排序。
-std::sort(da + 1, da + 1 + 10, cmp); // 重载小于运算符为大于,从大到小排序。
+std::sort(da + 1, da + 1 + 10); // 使用结构体中定义的 < 运算符,从小到大排序。
+std::sort(da + 1, da + 1 + 10, cmp); // 使用 cmp 函数进行比较,从大到小排序。
```
### 严格弱序
-进行排序的运算符必须满足严格弱序( [Strict weak orderings](https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings) ),否则会出现不可预料的情况(如运行时错误)。
+进行排序的运算符必须满足严格弱序( [Strict weak orderings](https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings) ),否则会出现不可预料的情况(如运行时错误、无法正确排序)。
+
严格弱序的要求:
-1. $x \not< x$ (非自反性)
+1. $x \not< x$ (非自反性)
2. 若 $x < y$ ,则 $y \not< x$ (非对称性)
3. 若 $x < y, y < z$ ,则 $x < z$ (传递性)
4. 若 $x \not< y, y \not< x, y \not< z, z \not< y$ ,则 $x \not< z, z \not< x$ (不可比性的传递性)
- 使用 `<=` 来定义排序中的小于运算符。
- 在调用排序运算符时,读取外部数值可能会改变的数组。(常见于最短路算法)
-- 将多个数的最大最小值进行比较的结果作为排序运算符。
-
-### Reference
-
-- [浅谈邻项交换排序的应用以及需要注意的问题](https://ouuan.github.io/浅谈邻项交换排序的应用以及需要注意的问题/)
+- 将多个数的最大最小值进行比较的结果作为排序运算符。(如,皇后游戏 / 加工生产调度 中的经典错误,可以参考文章 [浅谈邻项交换排序的应用以及需要注意的问题](https://ouuan.github.io/浅谈邻项交换排序的应用以及需要注意的问题/) )。
\ No newline at end of file