Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[pull] main from itcharge:main #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
pull merged 3 commits into AlgorithmAndLeetCode:main from itcharge:main
Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 38 additions & 13 deletions Contents/01.Array/02.Array-Sort/01.Array-Bubble-Sort.md
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,37 +1,62 @@
## 1. 冒泡排序算法思想

> 冒泡排序(Bubble Sort)基本思想:
> **冒泡排序(Bubble Sort)基本思想**:
>
> 第 `i (i = 1,2,... )` 趟排序时从序列中前 `n - i + 1` 个元素的第 `1` 个元素开始,相邻两个元素进行比较,若前者大于后者,两者交换位置,否则不交换。
> 第 `i (i = 1, 2, ...)` 趟排序时从序列中前 `n - i + 1` 个元素的第 `1` 个元素开始,相邻两个元素进行比较,若前者大于后者,两者交换位置,否则不交换。

冒泡排序法是通过相邻元素之间的比较与交换,使值较小的元素逐步从后面移到前面,值较大的元素从前面移到后面,就像水底的气泡一样向上冒,故称这种排序方法为冒泡排序法。
简单来说,「冒泡排序法」通过相邻元素之间的比较与交换,使值较小的元素逐步从后面移到前面,值较大的元素从前面移到后面。

这个过程就像水底的气泡一样向上冒,这也是冒泡排序法名字的由来。

## 2. 冒泡排序算法步骤

- 先将序列中第 `1` 个元素与第 `2` 个元素进行比较,若前者大于后者,则两者交换位置,否则不交换;
- 然后将第 `2` 个元素与第 `3` 个元素比较,若前者大于后者,则两者交换位置,否则不交换;
- 依次类推,直到第 `n - 1` 个元素与第 `n` 个元素比较(或交换)为止。经过如此一趟排序,使得 `n` 个元素中值最大元素被安置在序列的第 `n` 个位置上。
- 此后,再对前 `n - 1` 个元素进行同样过程,使得该 `n - 1` 个元素中值最大元素被安置在第 `n - 1` 个位置上。
- 然后再对前 `n - 2` 个元素重复上述过程,直到某一趟排序过程中不出现元素交换位置的动作,排序结束。
1. 第 `1` 趟排序,从序列中前 `n` 个元素的第 `1` 个元素开始,相邻两个元素依次进行比较和交换:
1. 先将序列中第 `1` 个元素与第 `2` 个元素进行比较,如果前者大于后者,则两者交换位置,否则不交换;
2. 然后将第 `2` 个元素与第 `3` 个元素比较,如果前者大于后者,则两者交换位置,否则不交换;
3. 依次类推,直到第 `n - 1` 个元素与第 `n` 个元素比较(或交换)为止。
4. 经过第 `1` 趟排序,使得 `n` 个元素中第 `i` 个值最大元素被安置在第 `n` 个位置上。
2. 第 `2` 趟排序,从序列中前 `n - 1` 个元素的第 `1` 个元素开始,相邻两个元素依次进行比较和交换:
1. 先将序列中第 `1` 个元素与第 `2` 个元素进行比较,若前者大于后者,则两者交换位置,否则不交换;
2. 然后将第 `2` 个元素与第 `3` 个元素比较,若前者大于后者,则两者交换位置,否则不交换;
3. 依次类推,直到对 `n - 2` 个元素与第 `n - 1` 个元素比较(或交换)为止。
4. 经过第 `2` 趟排序,使得数组中第 `2` 个值最大元素被安置在第 `n - 1` 个位置上。
3. 依次类推,对前 `n - 2` 个元素重复上述排序过程,直到某一趟排序过程中不出现元素交换位置的动作,则排序结束。

## 3. 冒泡排序动画演示

![img](https://www.runoob.com/wp-content/uploads/2019/03/bubbleSort.gif)
![](https://qcdn.itcharge.cn/images/20220812131649.gif)

1. 初始序列为:`[6, 2, 3, 5, 1, 4]`。
2. 第 `1` 趟排序,从序列中前 `6` 个元素的第 `1` 个元素开始,相邻两个元素进行比较和交换::
1. 先将序列中第 `1` 个元素与第 `2` 个元素进行比较,也就是将 `6` 和 `2` 进行比较。因为 `6 > 2`,所以两者交换位置,交换位置后,`2` 在第 `1` 位,`6` 在第 `2` 位。
2. 然后将第 `2` 个元素与第 `3` 个元素比较,也就是将 `2` 和 `3` 进行比较。因为 `2 < 3`,所以不用交换;
3. 依次类推,直到第 `5` 个元素与第 `6` 个元素比较(或交换)为止。
4. 经过第 `1` 趟排序,使得 `6` 个元素中第 `6` 个值最大元素被安置在第 `6` 个位置上。此时序列变为: `[2, 3, 5, 1, 4, 6]`。
3. 第 `2` 趟排序,从序列中前 `5` 个元素的第 `1` 个元素开始,相邻两个元素进行比较和交换::
1. 先将序列中第 `1` 个元素与第 `2` 个元素进行比较,也就是将 `2` 和 `3` 进行比较。因为 `2 < 3`,所以不用交换;
2. 然后将第 `2` 个元素与第 `3` 个元素比较,也就是将 `3` 和 `4` 进行比较。因为 `3 < 5`,所以不用交换;
3. 然后将第 `3` 个元素与第 `4` 个元素比较,也就是将 `5` 和 `1` 进行比较。因为 `5 > 1`,所以两者交换位置,交换位置后,`1` 在第 `3` 位,`5` 在第 `4` 位。
4. 依次类推,直到第 `4` 个元素与第 `5` 个元素比较(或交换)为止。
5. 经过第 `2` 趟排序,使得 `5` 个元素中第 `5` 个值最大元素被安置在第 `5` 个位置上。此时序列变为: `[2, 3, 1, 4, 5, 6]`。
4. 依次类推,对前 `4` 个元素重复上述排序过程,直到某一趟排序过程中不出现元素交换位置的动作,则排序结束。此时序列变为:`[1, 2, 3, 4, 5, 6]`。

## 4. 冒泡排序算法分析

- 最好的情况下,初始时序列已经是从小到大有序(升序),则只需经过一趟 `n - 1` 次元素之间的比较,并且不移动元素,算法就可结束排序。此时,算法的时间复杂度为 $O(n)$。
- 最差的情况是当参加排序的初始序列为逆序,或者最小值元素处在序列的最后时,则需要进行 `n - 1` 趟排序,总共进行 $∑^n_{i=2}(i−1) = \frac{n(n−1)}{2}$ 次元素之间的比较,因此,冒泡排序算法的平均时间复杂度为 $O(n^2)$。
- 冒泡排序方法在排序过程中需要移动较多次数的元素。因此,冒泡排序方法比较适合于参加排序序列的数据量较小的情况,尤其是当序列的初始状态为基本有序的情况;而对于一般情况,这种方法是排序时间效率最低的一种方法
- 由于元素交换是在相邻元素之间进行的,不会改变值相同元素的相对位置,因此,冒泡排序法是一种 **稳定排序法**。
- **最佳时间复杂度**:$O(n)$。最好的情况下(初始时序列已经是升序排列),则只需经过 `1` 趟排序,总共经过 `n - 1` 次元素之间的比较,并且不移动元素,算法就可结束排序。因此,冒泡排序算法的最佳时间复杂度为 $O(n)$。
- **最坏时间复杂度**:$O(n^2)$。最差的情况下(初始时序列已经是降序排列,或者最小值元素处在序列的最后),则需要进行 `n - 1` 趟排序,总共进行 $∑^n_{i=2}(i−1) = \frac{n(n−1)}{2}$ 次元素之间的比较,因此,冒泡排序算法的最坏时间复杂度为 $O(n^2)$。
- **冒泡排序适用情况**:冒泡排序方法在排序过程中需要移动较多次数的元素,并且排序时间效率比较低。因此,冒泡排序方法比较适合于参加排序序列的数据量较小的情况,尤其是当序列的初始状态为基本有序的情况。
- **排序稳定性**:由于元素交换是在相邻元素之间进行的,不会改变值相同元素的相对位置,因此,冒泡排序法是一种 **稳定排序算法**。

## 5. 冒泡排序代码实现

```Python
class Solution:
def bubbleSort(self, arr):
# 第 i 趟排序
for i in range(len(arr)):
# 从序列中前 n - i + 1 个元素的第 1 个元素开始,相邻两个元素进行比较
for j in range(len(arr) - i - 1):
# 相邻两个元素进行比较,如果前者大于后者,则交换位置
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]

Expand Down
46 changes: 31 additions & 15 deletions Contents/01.Array/02.Array-Sort/02.Array-Selection-Sort.md
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -1,43 +1,59 @@
## 1. 选择排序算法思想

> 选择排序(Selection Sort)基本思想:
> **选择排序(Selection Sort)基本思想**:
>
> 第 `i` 趟排序从序列的后 `n − i + 1 (i = 1, 2, ..., n − 1)` 个元素中选择一个值最小的元素与该 `n - i + 1` 个元素的最前面那个元素交换位置,即与整个序列的第 `i` 个位置上的元素交换位置。如此下去,直到 `i == n − 1`,排序结束。
> 将序列分为两部分:前边 `i - 1` 个元素为已排序部分,后边 `n - i + 1` 个元素为未排序部分。第 `i` 趟排序从未排序部分 `n − i + 1 (i = 1, 2, ..., n − 1)` 个元素中选择一个值最小的元素与未排序部分最前面那个元素交换位置,即与整个序列的第 `i` 个位置上的元素交换位置。如此下去,直到所有元素都变为已排序部分,排序结束。

可以简述为:每一趟排序中,从剩余未排序元素中选择一个最小的元素,与未排好序的元素最前面的那个元素交换位置
简单来说,「选择排序算法」是在每一趟排序中,从未排序部分中选出一个值最小的元素,与未排序部分第 `1` 个元素交换位置,从而将该元素划分到已排序部分

## 2. 选择排序算法步骤

- 在算法中设置整型变量 `i`,既可以作为排序趟数的计算,同时也作为执行第 `i` 趟排序时,参加排序的后 `n − i + 1` 个元素的第 `1` 个元素的位置。
- 整型变量 `min_i` 记录这 `n − i + 1` 个元素中值最小元素的位置。
- 每一趟排序开始,先另 `min_i = i` (即暂时假设序列的第 `i` 个元素为值最小者,以后经过比较后视实际情况再正式确定最小值元素的位置)。
- 第 `i` 趟排序比较结束时,这 `n − i + 1` 个元素中真正的值最小元素为下标 `min_i` 对应的元素。此时,若有 `min_i == i`,说明值最小元素就是这 `n − i + 1` 个元素的第 `1` 个元素,意味着此趟排序不必进行元素交换。
1. 第 `1` 趟排序:
1. 无已排序部分,把第 `1` ~ `n `个元素(总共 `n ` 个元素)作为未排序部分。
2. 遍历 `n` 个元素,使用变量 `min_i` 记录 `n` 个元素中值最小的元素位置。
3. 将 `min_i` 与未排序部分第 `1` 个元素(也就是序列的第 `1` 个元素)交换位置。如果未排序部分第 `1` 个元素就是值最小的元素位置,则不用交换。
4. 此时第 `1` 个元素为已排序部分,剩余第 `2` ~ `n` 个元素(总共 `n - 1` 个元素)为未排序部分。
2. 第 `2` 趟排序:
1. 遍历剩余 `n - 1` 个元素,使用变量 `min_i` 记录 `n - 1` 个元素中值最小的元素位置。
2. 将 `min_i` 与未排序部分第 `1` 个元素(也就是序列的第 `2` 个元素)交换位置。如果未排序部分第 `1` 个元素就是值最小的元素位置,则不用交换。
3. 此时第 `1` ~ `2` 个元素为已排序部分,剩余第 `3` ~ `n` 个元素(总共 `n - 2` 个元素)为未排序部分。
3. 依次类推,对剩余 `n - 2` 个元素重复上述排序过程,直到所有元素都变为已排序部分,则排序结束。

## 3. 选择排序动画演示

![](https://www.runoob.com/wp-content/uploads/2019/03/selectionSort.gif)
![](https://qcdn.itcharge.cn/images/20220812145555.gif)

1. 初始序列为:`[6, 2, 3, 5, 1, 4]`。
2. 第 `1` 趟排序,无已排序部分,把 `[6, 2, 3, 5, 1, 4]`(总共 `6 ` 个元素)作为未排序部分:
1. 遍历这 `6` 个元素,使用变量 `min_i` 记录 `6` 个元素中值最小(值为 `1`)的元素位置,也就是第 `5` 个元素位置。
2. 将 `min_i` 与未排序部分第 `1` 个元素(也就是序列的第 `1` 个元素)交换位置,就是将元素 `6` 和元素 `1` 交换位置。
3. 此时 `[1]` 为已排序部分,剩余 `[2, 3, 5, 6, 4]`(总共 `5` 个元素)为未排序部分。此时序列为 `[1, 2, 3, 5, 6, 4]`。
3. 第 `2` 趟排序,把 `[1]` 作为已排序部分,把剩余 `[2, 3, 5, 6, 4] `(总共 `5` 个元素)作为未排序部分。
1. 遍历剩余 `5` 个元素,使用变量 `min_i` 记录 `5` 个元素中值最小的元素位置,也就是第 `2` 个元素位置。
2. 因为值最小的元素位置 `min_i` 就是未排序部分第 `1` 个元素,所以不用交换。
3. 此时 `[1, 2]` 为已排序部分,剩余 `[3, 5, 6, 4]`(总共 `4` 个元素)为未排序部分。
4. 依次类推,对剩余 `4` 个元素重复上述排序过程,直到所有元素都变为已排序部分,则排序结束。此时,序列变为 `[1, 2, 3, 4, 5, 6]`。

## 4. 选择排序算法分析

对于具有 `n` 个元素的序列采用选择排序方法要经过 `n - 1` 趟排序。
- **时间复杂度**:排序法所进行的元素之间的比较次数与序列的原始状态无关,时间复杂度总是 $O(n^2)$。
- 这是因为无论序列中元素的初始排列状态如何,第 `i` 趟排序要找出值最小元素都需要进行 `n − i` 次元素之间的比较。因此,整个排序过程需要进行的元素之间的比较次数都相同,为 $∑^n_{i=2}(i - 1) = \frac{n(n−1)}{2}$ 次。
- **选择排序适用情况**:选择排序方法在排序过程中需要移动较多次数的元素,并且排序时间效率比较低。因此,选择排序方法比较适合于参加排序序列的数据量较小的情况。选择排序的主要优点是仅需要原地操作无需占用其他空间就可以完成排序,因此在空间复杂度要求较高时,可以考虑选择排序。

- 当原始序列是一个按值递增序列(升序)时,元素的移动次数最少,为 `0` 次。当序列初始时是一个按值递减序列(逆序)时,元素的移动次数最多,为 3ドル(n − 1)$ 次(`3` 是交换 `arr[i]` 与 `arr[min_i]` 的执行次数)。
- 但是,无论序列中元素的初始排列状态如何,第 `i` 趟排序要找出值最小元素都需要进行 `n − i` 次元素之间的比较。因此,整个排序过程需要进行的元素之间的比较次数都相同,为 $∑^n_{i=2}(i - 1) = \frac{n(n−1)}{2}$ 次。
- 这说明选择排序法所进行的元素之间的比较次数与序列的原始状态无关,同时可以确定算法的时间复杂度为 $O(n^2)$。
- 由于值最小元素与未排好序的元素中第 `1` 个元素的交换动作是在不相邻的元素之间进行的,因此很有可能会改变值相同元素的前后位置,因此,选择排序法是一种不稳定的排序方法。
- **排序稳定性**:由于值最小元素与未排序部分第 `1` 个元素的交换动作是在不相邻的元素之间进行的,因此很有可能会改变值相同元素的前后位置,因此,选择排序法是一种 **不稳定排序算法**。

## 5. 选择排序代码实现

```Python
class Solution:
def selectionSort(self, arr):
for i in range(len(arr) - 1):
# 记录未排序序列中最小数的索引
# 记录未排序部分中最小值的位置
min_i = i
for j in range(i + 1, len(arr)):
if arr[j] < arr[min_i]:
min_i = j
# 如果找到最小数,将 i 位置上元素与最小数位置上元素进行交换
# 如果找到最小值的位置,将 i 位置上元素与最小值位置上的元素进行交换
if i != min_i:
arr[i], arr[min_i] = arr[min_i], arr[i]
return arr
Expand Down
Loading

AltStyle によって変換されたページ (->オリジナル) /