Skip to content

Commit

Permalink
docs: add new doc
Browse files Browse the repository at this point in the history
  • Loading branch information
daiwanxing committed Jun 11, 2023
1 parent 131fd19 commit 2622a58
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 2 deletions.
13 changes: 12 additions & 1 deletion docs/.vitepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,17 @@ export default defineConfig({
]
}
],
"/articles/algorithm": [
{
text: "Overview",
items: [
{
text: "冒泡排序",
link: "/articles/algorithm/bubble-sort"
},
]
}
],
"/life/": [
{
text: "My Life",
Expand Down Expand Up @@ -263,7 +274,7 @@ export default defineConfig({
},
{
text: "前端算法",
link: articleRef("algorithm"),
link: articleRef("algorithm/"),
},
{
text: "git常见操作",
Expand Down
175 changes: 175 additions & 0 deletions docs/articles/algorithm/bubble-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# 冒泡排序

## 概念

冒泡排序核心概念在于每次都会对**相邻的两个数**进行比较

> 在升序排序的情况下,交换的条件需要满足,左边的数据**大于**右边的数据
>
> 在降序排序的情况下,交换的条件需要满足,左边的数据**小于**右边的数据
冒泡排序的思想是每一次遍历未排序的数列后,都会将一个数据元素浮上去(这个数据会排序到左侧或者右侧,具体取决于升序还是降序)。

冒泡排序的需要 _N - 1_ 轮排序,其中 _N_ 为数组的长度

例如有一个如下的数组,长度为 5,那么总共需要 4 轮排序,每一轮排序都是左右两个数相互比较并判断是否需要交换位置。

```js
const data = [5, 1, 2, 9, -1];
```

### 进行冒泡(升序)排序:

- _第一轮_
- `5``1` 进行比较,`5 > 1`,则两个数交换位置。
```js
// 最终排序结果
[1, 5, 2, 9, -1];
```
- `5``2` 进行比较, `5 > 2`,则两个数交换位置。
```js
// 最终排序结果
[1, 2, 5, 9, -1];
```
- `5``9` 进行比较, `5 < 9`,则不做处理。
- `9``-1` 进行比较, `9 > -1`,则两个数交换位置。
```js
// 最终排序结果
[1, 2, 5, -1, 9];
```
- _第二轮_
- `1``2` 进行比较,`1 < 2`,则不做处理。
- `2``5` 进行比较,`2 < 5`,则不做处理。
- `5``-1` 进行比较,`5 > -1`,则两个数交换位置。
```js
// 最终排序结果
[1, 2, -1, 5, 9];
```
- `5``9` 进行比较,`5 > 9`,则不做处理。
- _第三轮_
- `1``2` 进行比较,`1 < 2`,则不做处理。
- `2``-1` 进行比较,`2 > -1`,则两个数交换位置。
```js
// 最终排序结果
[1, -1, 2, 5, 9];
```
- `2``5` 进行比较,`2 < 5`,则不做处理。
- `5``9` 进行比较,`5 > 9`,则不做处理。
- _第四轮_
- `1``-1` 进行比较,`1 > -1`,则两个数交换位置。
```js
// 最终排序结果
[-1, 1, 2, 5, 9];
```
- `1``2` 进行比较,`1 < 2`,则不做处理。
- `2``5` 进行比较,`2 < 5`,则不做处理。
- `5``9` 进行比较,`5 > 9`,则不做处理。

最终执行了四轮排序操作,至此整个冒泡排序结束。

排序后的最终结果:`[-1, 1,2, 5, 9]`

## 算法实现(JavaScript)

可以看出,每次进行新一轮排序,都是两个相邻的数彼此判断是否需要交换位置,那么需要用到两个 for 循环。

外层的 for 循环负责遍历新一轮排序,内层的 for 循环负责交换新一轮排序下的元素。

代码实现如下:

```js
function bubbleSort(data) {
const len = data.length;
// 前面提到过,冒泡排序最终需要进行 N - 1 轮排序,其中 N 为数组的长度
const sortCount = len - 1;
for (let i = 0; i < sortCount; i++) {
for (let j = 0; j < len; j++) {
if (data[j] > data[j + 1]) {
const temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
}
}
}
return data;
}
```

执行该函数得到以下的输出结果:

```js
bubbleSort([5, 1, 2, 9, -1]); // [-1, 1,2, 5, 9]
```

## 着手优化

这种为了交换数据,开辟一个临时变量的做法不能说不好,但是还能更简洁(装逼)的做法:

原方案:

```js{3-5}
function bubbleSort(data) {
//...
const temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
///...
}
```

改进后:

```js{3}
function bubbleSort(data) {
// ...
[data[j + 1], data[j]] = [data[j], data[j + 1]];
// ...
}
```

我们还可以借助位运算,达到更快的值交换:

```js
data[j] ^= data[j + 1];
data[j + 1] ^= data[j];
data[j] ^= data[j + 1];
```

## 更进一步优化

通过上面的排序步骤示例,我们不难看每一轮比较完毕后,*排序好的数据*不再参与任何的位置交换。

每一轮比较,参与比较的数据的个数 = 总轮数 - 当前的轮数,也就是说我们不必每一轮都需要将数组中的每个元素进行比较,这是毫无意义的。

而且当数据量过大时,排序耗时会很长。

下面是优化后的排序算法:

```js{6}
function bubbleSort(data) {
const len = data.length;
const sortCount = len - 1;
for (let i = 0; i < sortCount; i++) {
// 内循环每次需要比较的个数为总个数减去当前的趟数
for (let j = 0; j < len - i; j++) {
if (data[j] > data[j + 1]) {
[data[j + 1], data[j]] = [data[j], data[j + 1]];
}
}
}
return data;
}
```

## 算法复杂度

**时间复杂度**: O(n<sup>2</sup>)

**空间复杂度**: O(1)


## 总结

冒泡排序是一种最基础、也是性能最低的排序算法,因为它的时间复杂度取决于数组的长度,数组越大,其排序的性能也就越低。

一般不会用到这个算法,但是了解它的核心概念是非常重要的。
6 changes: 5 additions & 1 deletion docs/articles/algorithm/index.md
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
# 一些业务中可能会用到的算法整理
# 算法

### 排序算法

- [冒泡排序(Bubble Sort)](/articles/algorithm/bubble-sort)

0 comments on commit 2622a58

Please sign in to comment.