Loading .github/pull_request_template.md +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ - 请在 commit 的时候写比较有意义的 commit message - 请给 PR 起比较有意义的标题。 - 如果您的 PR 可以解决某个现有的 issue,请在这个文本框的开头部分写上 fix + issue 编号。 如:fix #1622 - 关于文档内容的基本格式和基本内容规范,可以查阅 [如何参与](https://oi-wiki.org/intro/htc)。 - 请确保勾选了下方允许维护者修改的候选框(lint bot 需要在 PR 环节修正格式) Loading .travis.yml +12 −3 Original line number Diff line number Diff line Loading @@ -37,4 +37,13 @@ after_deploy: - git push coding master:master -f - git fetch origin gh-pages - git checkout -b gh-pages origin/gh-pages - git push coding gh-pages:coding-pages -f - git push coding gh-pages:gh-pages -f - git checkout -b cdn-pages origin/gh-pages - find ./ -type f -name "*.html" -exec sed -i -E 's/([^"]*)(assets[^"]*)/https:\/\/cdn-for-oi-wiki.billchn.com\/\2/g' {} + - git add . - git config user.name "Travis Builder" - git config user.email "hi@oi-wiki.org" - git commit --author "24OI-bot <15963390+24OI-bot@users.noreply.github.com>" -m "build cdn files" - git remote add gh-token "https://${GH_TOKEN}@github.com/OI-wiki/OI-wiki.git"; - git push gh-token cdn-pages -f - git push coding cdn-pages:coding-pages -f docs/basic/bubble-sort.md +32 −12 Original line number Diff line number Diff line Loading @@ -2,22 +2,42 @@ 以升序为例,冒泡排序每次检查相邻两个元素,如果前面的元素大于后面的元素,就将相邻两个元素交换。当没有相邻的元素需要交换时,排序就完成了。 不难发现,我们最多需要扫描 $n$ 遍数组才能完成排序。 经过 $i$ 次扫描后,数列的末尾 $i$ 项必然是最大的 $i$ 项,因此最多需要扫描 $n-1$ 遍数组就能完成排序。 在序列完全有序时,该算法只需遍历一遍数组,不用执行任何交换操作,时间复杂度为 $O(n)$ 。在最坏情况下,冒泡排序要执行 $\frac{(n-1)n}{2}$ 次交换操作,时间复杂度为 $O(n^2)$ 。在平均情况下,冒泡排序的时间复杂度也是 $O(n^2)$ 。 伪代码: $$ \begin{array}{ll} 1 & \textbf{Input. } \text{An array } A \text{ consisting of }n\text{ elements.} \\ 2 & \textbf{Output. } A\text{ will be sorted in nondecreasing order stably.} \\ 3 & \textbf{Method. } \\ 4 & flag\gets True\\ 5 & \textbf{while }flag\\ 6 & \qquad flag\gets False\\ 7 & \qquad\textbf{for }i\gets1\textbf{ to }n-1\\ 8 & \qquad\qquad\textbf{if }A[i]>A[i + 1]\\ 9 & \qquad\qquad\qquad flag\gets True\\ 10 & \qquad\qquad\qquad \text{Swap } A[i]\text{ and }A[i + 1] \end{array} $$ C++ 代码: ```cpp void bubble_sort() { for (int i = 1; i <= n; i++) { bool flag = false; for (int j = 1; j < n; j++) if (a[j] > a[j + 1]) { void bubble_sort(int *a, int n) { bool flag = true; while (flag) { flag = false; for (int i = 1; i < n; ++i) { if (a[i] > a[i + 1]) { flag = true; int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t; int t = a[i]; a[i] = a[i + 1]; a[i + 1] = t; } } if (!flag) break; //如果没有执行交换操作,说明数列已经有序 } } ``` 在序列完全有序时,该算法只需遍历一遍数组,不用执行任何交换操作,时间复杂度为 $O(n)$ 。在最坏情况下,冒泡排序要执行 $\frac{(n-1)n}{2}$ 次交换操作,时间复杂度为 $O(n^2)$ 。在平均情况下,冒泡排序的时间复杂度也是 $O(n^2)$ 。 docs/basic/bucket-sort.md +39 −6 Original line number Diff line number Diff line 计数排序也称桶排序,可以在 $O(n)$ 的时间复杂度内对数组进行排序,但是它的空间复杂度与需要排序的数组的值域相关。 桶排序适用于待排序数据值域较大但分布比较均匀的情况,是一个期望时间复杂度为 $O(n)$ 的排序算法。 但实际操作时,由于时空同阶,时间复杂度应为 $O(\max\left(n,U\right))$ ,其中 $U$ 代表数组元素的值域大小。 其大致思想是对值域进行分块,每块分别排序。由于每块元素不多,一般使用插入排序。如果使用稳定的内层排序,并且将元素插入桶中时不改变相对顺序,那么桶排序就是稳定的。 !!! warning "注" 注意区分 **基数排序** 与 **桶排序** 如果待排序数据是随机生成的,将值域平均分成 $n$ 块的期望时间复杂度是 $O(n)$ ,证明可以参考算法导论或 [维基百科](https://en.wikipedia.org/wiki/Bucket_sort) 。 算法流程就是记录每一个数出现了多少次,然后从小到大依次输出。 C++ 代码: 一般考虑的是某一范围内的整数,但是计数排序也可以和 [离散化](/misc/discrete) 一起使用,来对浮点数、大整数进行排序。 ```cpp const int N = 100010; int n, w, a[N]; vector<int> bucket[N]; void insertion_sort(vector<int>& A) { for (int i = 1; i < A.size(); ++i) { int key = A[i]; int j = i - 1; while (j >= 0 && A[j] > key) { A[j + 1] = A[j]; --j; } A[j + 1] = key; } } void bucket_sort() { int bucket_size = w / n + 1; for (int i = 0; i < n; ++i) { bucket[i].clear(); } for (int i = 1; i <= n; ++i) { bucket[a[i] / bucket_size].push_back(a[i]); } int p = 0; for (int i = 0; i < n; ++i) { insertion_sort(bucket[i]); for (int j = 0; j < bucket[i].size(); ++j) { a[++p] = bucket[i][j]; } } } ``` docs/basic/counting-sort.md 0 → 100644 +43 −0 Original line number Diff line number Diff line 计数排序是一种复杂度为 $O(n+w)$ 的稳定排序,其中 $w$ 代表待排序数据的值域大小。 计数排序分为三个步骤: 1. 计算每个数出现了几次。 2. 求出每个数出现次数的前缀和。 3. 利用出现次数的前缀和,从右至左计算每个数的排名。 伪代码: $$ \begin{array}{ll} 1 & \textbf{Input. } \text{An array } A \text{ consisting of }n\text{ positive integers no greater than } w. \\ 2 & \textbf{Output. } \text{Array }A\text{ after sorting in nondecreasing order stably.} \\ 3 & \textbf{Method. } \\ 4 & \textbf{for }i\gets0\textbf{ to }w\\ 5 & \qquad cnt[i]\gets0\\ 6 & \textbf{for }i\gets1\textbf{ to }n\\ 7 & \qquad cnt[A[i]]\gets cnt[A[i]]+1\\ 8 & \textbf{for }i\gets1\textbf{ to }w\\ 9 & \qquad cnt[i]\gets cnt[i]+cnt[i-1]\\ 10 & \textbf{for }i\gets n\textbf{ downto }1\\ 11 & \qquad B[cnt[A[i]]]\gets A[i]\\ 12 & \qquad cnt[A[i]]\gets cnt[A[i]]-1\\ 13 & \textbf{return } B \end{array} $$ C++ 代码: ```cpp const int N = 100010; const int W = 100010; int n, w, a[N], cnt[W], b[N]; void counting_sort() { memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= n; ++i) ++cnt[a[i]]; for (int i = 1; i <= w; ++i) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; --i) b[cnt[a[i]]--] = a[i]; } ``` Loading
.github/pull_request_template.md +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ - 请在 commit 的时候写比较有意义的 commit message - 请给 PR 起比较有意义的标题。 - 如果您的 PR 可以解决某个现有的 issue,请在这个文本框的开头部分写上 fix + issue 编号。 如:fix #1622 - 关于文档内容的基本格式和基本内容规范,可以查阅 [如何参与](https://oi-wiki.org/intro/htc)。 - 请确保勾选了下方允许维护者修改的候选框(lint bot 需要在 PR 环节修正格式) Loading
.travis.yml +12 −3 Original line number Diff line number Diff line Loading @@ -37,4 +37,13 @@ after_deploy: - git push coding master:master -f - git fetch origin gh-pages - git checkout -b gh-pages origin/gh-pages - git push coding gh-pages:coding-pages -f - git push coding gh-pages:gh-pages -f - git checkout -b cdn-pages origin/gh-pages - find ./ -type f -name "*.html" -exec sed -i -E 's/([^"]*)(assets[^"]*)/https:\/\/cdn-for-oi-wiki.billchn.com\/\2/g' {} + - git add . - git config user.name "Travis Builder" - git config user.email "hi@oi-wiki.org" - git commit --author "24OI-bot <15963390+24OI-bot@users.noreply.github.com>" -m "build cdn files" - git remote add gh-token "https://${GH_TOKEN}@github.com/OI-wiki/OI-wiki.git"; - git push gh-token cdn-pages -f - git push coding cdn-pages:coding-pages -f
docs/basic/bubble-sort.md +32 −12 Original line number Diff line number Diff line Loading @@ -2,22 +2,42 @@ 以升序为例,冒泡排序每次检查相邻两个元素,如果前面的元素大于后面的元素,就将相邻两个元素交换。当没有相邻的元素需要交换时,排序就完成了。 不难发现,我们最多需要扫描 $n$ 遍数组才能完成排序。 经过 $i$ 次扫描后,数列的末尾 $i$ 项必然是最大的 $i$ 项,因此最多需要扫描 $n-1$ 遍数组就能完成排序。 在序列完全有序时,该算法只需遍历一遍数组,不用执行任何交换操作,时间复杂度为 $O(n)$ 。在最坏情况下,冒泡排序要执行 $\frac{(n-1)n}{2}$ 次交换操作,时间复杂度为 $O(n^2)$ 。在平均情况下,冒泡排序的时间复杂度也是 $O(n^2)$ 。 伪代码: $$ \begin{array}{ll} 1 & \textbf{Input. } \text{An array } A \text{ consisting of }n\text{ elements.} \\ 2 & \textbf{Output. } A\text{ will be sorted in nondecreasing order stably.} \\ 3 & \textbf{Method. } \\ 4 & flag\gets True\\ 5 & \textbf{while }flag\\ 6 & \qquad flag\gets False\\ 7 & \qquad\textbf{for }i\gets1\textbf{ to }n-1\\ 8 & \qquad\qquad\textbf{if }A[i]>A[i + 1]\\ 9 & \qquad\qquad\qquad flag\gets True\\ 10 & \qquad\qquad\qquad \text{Swap } A[i]\text{ and }A[i + 1] \end{array} $$ C++ 代码: ```cpp void bubble_sort() { for (int i = 1; i <= n; i++) { bool flag = false; for (int j = 1; j < n; j++) if (a[j] > a[j + 1]) { void bubble_sort(int *a, int n) { bool flag = true; while (flag) { flag = false; for (int i = 1; i < n; ++i) { if (a[i] > a[i + 1]) { flag = true; int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t; int t = a[i]; a[i] = a[i + 1]; a[i + 1] = t; } } if (!flag) break; //如果没有执行交换操作,说明数列已经有序 } } ``` 在序列完全有序时,该算法只需遍历一遍数组,不用执行任何交换操作,时间复杂度为 $O(n)$ 。在最坏情况下,冒泡排序要执行 $\frac{(n-1)n}{2}$ 次交换操作,时间复杂度为 $O(n^2)$ 。在平均情况下,冒泡排序的时间复杂度也是 $O(n^2)$ 。
docs/basic/bucket-sort.md +39 −6 Original line number Diff line number Diff line 计数排序也称桶排序,可以在 $O(n)$ 的时间复杂度内对数组进行排序,但是它的空间复杂度与需要排序的数组的值域相关。 桶排序适用于待排序数据值域较大但分布比较均匀的情况,是一个期望时间复杂度为 $O(n)$ 的排序算法。 但实际操作时,由于时空同阶,时间复杂度应为 $O(\max\left(n,U\right))$ ,其中 $U$ 代表数组元素的值域大小。 其大致思想是对值域进行分块,每块分别排序。由于每块元素不多,一般使用插入排序。如果使用稳定的内层排序,并且将元素插入桶中时不改变相对顺序,那么桶排序就是稳定的。 !!! warning "注" 注意区分 **基数排序** 与 **桶排序** 如果待排序数据是随机生成的,将值域平均分成 $n$ 块的期望时间复杂度是 $O(n)$ ,证明可以参考算法导论或 [维基百科](https://en.wikipedia.org/wiki/Bucket_sort) 。 算法流程就是记录每一个数出现了多少次,然后从小到大依次输出。 C++ 代码: 一般考虑的是某一范围内的整数,但是计数排序也可以和 [离散化](/misc/discrete) 一起使用,来对浮点数、大整数进行排序。 ```cpp const int N = 100010; int n, w, a[N]; vector<int> bucket[N]; void insertion_sort(vector<int>& A) { for (int i = 1; i < A.size(); ++i) { int key = A[i]; int j = i - 1; while (j >= 0 && A[j] > key) { A[j + 1] = A[j]; --j; } A[j + 1] = key; } } void bucket_sort() { int bucket_size = w / n + 1; for (int i = 0; i < n; ++i) { bucket[i].clear(); } for (int i = 1; i <= n; ++i) { bucket[a[i] / bucket_size].push_back(a[i]); } int p = 0; for (int i = 0; i < n; ++i) { insertion_sort(bucket[i]); for (int j = 0; j < bucket[i].size(); ++j) { a[++p] = bucket[i][j]; } } } ```
docs/basic/counting-sort.md 0 → 100644 +43 −0 Original line number Diff line number Diff line 计数排序是一种复杂度为 $O(n+w)$ 的稳定排序,其中 $w$ 代表待排序数据的值域大小。 计数排序分为三个步骤: 1. 计算每个数出现了几次。 2. 求出每个数出现次数的前缀和。 3. 利用出现次数的前缀和,从右至左计算每个数的排名。 伪代码: $$ \begin{array}{ll} 1 & \textbf{Input. } \text{An array } A \text{ consisting of }n\text{ positive integers no greater than } w. \\ 2 & \textbf{Output. } \text{Array }A\text{ after sorting in nondecreasing order stably.} \\ 3 & \textbf{Method. } \\ 4 & \textbf{for }i\gets0\textbf{ to }w\\ 5 & \qquad cnt[i]\gets0\\ 6 & \textbf{for }i\gets1\textbf{ to }n\\ 7 & \qquad cnt[A[i]]\gets cnt[A[i]]+1\\ 8 & \textbf{for }i\gets1\textbf{ to }w\\ 9 & \qquad cnt[i]\gets cnt[i]+cnt[i-1]\\ 10 & \textbf{for }i\gets n\textbf{ downto }1\\ 11 & \qquad B[cnt[A[i]]]\gets A[i]\\ 12 & \qquad cnt[A[i]]\gets cnt[A[i]]-1\\ 13 & \textbf{return } B \end{array} $$ C++ 代码: ```cpp const int N = 100010; const int W = 100010; int n, w, a[N], cnt[W], b[N]; void counting_sort() { memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= n; ++i) ++cnt[a[i]]; for (int i = 1; i <= w; ++i) cnt[i] += cnt[i - 1]; for (int i = n; i >= 1; --i) b[cnt[a[i]]--] = a[i]; } ```