Unverified Commit 308a16a9 authored by Shuhao Zhang's avatar Shuhao Zhang Committed by GitHub
Browse files

make fork up-to-date

parents 995a982d 3368938a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

- 请在 commit 的时候写比较有意义的 commit message
- 请给 PR 起比较有意义的标题。
- 如果您的 PR 可以解决某个现有的 issue,请在这个文本框的开头部分写上 fix + issue 编号。 如:fix #1622
- 关于文档内容的基本格式和基本内容规范,可以查阅 [如何参与](https://oi-wiki.org/intro/htc)
- 请确保勾选了下方允许维护者修改的候选框(lint bot 需要在 PR 环节修正格式)

+12 −3
Original line number Diff line number Diff line
@@ -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
+32 −12
Original line number Diff line number Diff line
@@ -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)$ 。
+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];
    }
  }
}
```
+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