Skip to content

Commit

Permalink
选择排序内容优化
Browse files Browse the repository at this point in the history
  • Loading branch information
itcharge committed Aug 16, 2023
1 parent 57f8db6 commit 06892d6
Showing 1 changed file with 56 additions and 34 deletions.
90 changes: 56 additions & 34 deletions Contents/01.Array/02.Array-Sort/02.Array-Selection-Sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,64 @@

> **选择排序(Selection Sort)基本思想**
>
> 将序列分为两部分:前边 `i - 1` 个元素为已排序部分,后边 `n - i + 1` 个元素为未排序部分。第 `i` 趟排序从未排序部分 `n − i + 1 (i = 1, 2, …, n − 1)` 个元素中选择一个值最小的元素与未排序部分最前面那个元素交换位置,即与整个序列的第 `i` 个位置上的元素交换位置。如此下去,直到所有元素都变为已排序部分,排序结束
> 将数组分为两个区间:左侧为已排序区间,右侧为未排序区间。每轮从未排序区间中选择一个值最小的元素,放到已排序区间的末尾,从而将该元素划分到已排序区间
简单来说,「选择排序算法」是在每一趟排序中,从未排序部分中选出一个值最小的元素,与未排序部分第 `1` 个元素交换位置,从而将该元素划分到已排序部分
选择排序是一种简单直观的排序算法,其思想简单,代码也相对容易

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

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://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]`
1. 初始状态下,无已排序区间,未排序区间为 $[0, n - 1]$。
2. 第 $1$ 趟选择:
1. 遍历未排序区间 $[0, n - 1]$,使用变量 $min\underline{}i$ 记录区间中值最小的元素位置。
2. 将 $min\underline{}i$ 与下标为 $0$ 处元素交换位置。如果下标为 $0$ 处元素就是值最小的元素位置,则不用交换。
3. 此时,$[0, 0]$ 为已排序区间,$[1, n - 1]$(总共 $n - 1$ 个元素)为未排序区间。
3. 第 $2$ 趟选择:
1. 遍历未排序区间 $[1, n - 1]$,使用变量 $min\underline{}i$ 记录区间中值最小的元素位置。
2. 将 $min\underline{}i$ 与下标为 $1$ 处元素交换位置。如果下标为 $1$ 处元素就是值最小的元素位置,则不用交换。
3. 此时,$[0, 1]$ 为已排序区间,$[2, n - 1]$(总共 $n - 2$ 个元素)为未排序区间。
4. 依次类推,对剩余未排序区间重复上述选择过程,直到所有元素都划分到已排序区间,排序结束。

## 4. 选择排序算法分析
我们以 $[5, 2, 3, 6, 1, 4]$ 为例,演示一下选择排序的整个过程。

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

@tab <1>

![选择排序 1](http://qcdn.itcharge.cn/images/20230816155042.png)

@tab <2>

![选择排序 2](http://qcdn.itcharge.cn/images/20230816155017.png)

@tab <3>

![选择排序 3](http://qcdn.itcharge.cn/images/20230816154955.png)

@tab <4>

![选择排序 4](http://qcdn.itcharge.cn/images/20230816154924.png)

@tab <5>

![选择排序 5](http://qcdn.itcharge.cn/images/20230816154859.png)

- **排序稳定性**:由于值最小元素与未排序部分第 `1` 个元素的交换动作是在不相邻的元素之间进行的,因此很有可能会改变值相同元素的前后位置,因此,选择排序法是一种 **不稳定排序算法**
@tab <6>

## 5. 选择排序代码实现
![选择排序 6](http://qcdn.itcharge.cn/images/20230816154836.png)

@tab <7>

![选择排序 7](http://qcdn.itcharge.cn/images/20230816153324.png)

:::

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

```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]:
Expand All @@ -62,3 +73,14 @@ class Solution:
return self.selectionSort(nums)
```

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

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

- **排序稳定性**:由于值最小元素与未排序区间第 $1$ 个元素的交换动作是在不相邻的元素之间进行的,因此很有可能会改变值相同元素的前后位置,因此,选择排序法是一种 **不稳定排序算法**



0 comments on commit 06892d6

Please sign in to comment.