听说你们在家闷得快要发霉了,来点新鲜的吧。集中注意力,让时间过得更快一些!
以下是来自菜鸟教程中的排序过程和动图示意:
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复直到所有元素均排序完毕。
我们来捋一捋,选择排序的主要逻辑为:
- 外循环先指定一个数,通常是第一个数
- 接着在内循环中将这个外循环指定数与右侧数逐个比较,记录下右侧数当中最小的那位
- 左侧为排序好的元素,遂内循环中的比较是外循环指定数不停地与右侧元素进行比较
- 内循环时,每次发现比外循环指定数小的数就记录下来,循环结束后记录的数便是右侧最小数
- 在内循环结束后将外循环指定数与内循环得出的右侧最小数交换位置
- 依此类推,直到外层循环结束
现在有一组需要排序的元素:
[7, 21, 9, 13, 109, 9, 2, 50, 33, -1, 20, 11]
按照选择排序的逻辑外循环指定下标为 0 的第一个数 7,选定后 for 循环将从下标为 0 的元素开始循环。代码表现为:
for i in 0..vectors.len(){}
for 循环从下标为 0 的第一个数 7 开始。在内循环中将这个外循环指定数与右侧数 [21, 9, 13, 109, 9, 2, 50, 33, -1, 20, 11] 逐个比较,当外循环指定数小于左边元素时记录最小值,内循环结束后 vectors[i] 与 vectors[j] 交换位置。本轮最小数为 -1,遂元素组变为:
[-1, 21, 9, 13, 109, 9, 2, 50, 33, 7, 20, 11]
此时进入下一轮外循环,指定下标为 1 的第二个数 21。在内循环中将这个外循环指定数与右侧数 [9, 13, 109, 9, 2, 50, 33, -1, 20, 11] 逐个比较,当外循环指定数小于左边元素时记录最小值,内循环结束后 vectors[i] 与 vectors[j] 交换位置。本轮最小数为 2,遂元素组变为:
[-1, 2, 21, 13, 109, 9, 9, 50, 33, 7, 20, 11]
以此规则类推,元素排序的最终结果为:
[-1, 2, 7, 9, 9, 11, 13, 20, 21, 33, 50, 109]
具体代码实现
首先定义一组元素,并打印:
1 fn main() { 2 let mut vectors = vec![7, 21, 9, 13, 109, 9, 2, 50, 33, -1, 20, 11]; 3 println!("vectors: {:?}", vectors); 4 }
然后定义排序方法:
1 fn insert_sort(vectors: &mut Vec<i32>) -> &Vec<i32>{ 2 vectors 3 }
排序方法的外循环是 for 循环:
1 fn insert_sort(vectors: &mut Vec<i32>) -> &Vec<i32>{ 2 for i in 0..vectors.len(){ 3 4 } 5 vectors 6 }
这里的 index 代表最小值的下标:
1 fn insert_sort(vectors: &mut Vec<i32>) -> &Vec<i32>{ 2 for i in 0..vectors.len(){ 3 let mut index = i; 4 } 5 vectors 6 }
在内循环中的将外循环指定数与右侧数逐个比较,当外循环指定数小于右侧元素时记录右侧元素的下标,否则不动。
不停地与右侧元素比较用 for j in i+1..vectors.len() 和 vectors[j] < vectors[index] 表示;
下标的记录其实可以用交换代替,这样内层 for 循环结束时,index 一定是右侧中小元素的下标;
交换位置无法像 Python 那样 a, b = b, a,只能用 c = a, a = b, b = c 这种加入第三个数的方式倒腾。遂代码如下
1 fn selection_sort(vectors: &mut Vec<i32>) -> &Vec<i32>{ 2 for i in 0..vectors.len(){ 3 // 寻找未排序元素中的最小值,即[i, n)中的最小元素 4 let mut index = i; 5 for j in i+1..vectors.len(){ 6 if vectors[j] < vectors[index]{ 7 index = j; 8 } 9 } 10 let middle = vectors[index]; 11 vectors[index] = vectors[i]; 12 vectors[i] = middle; 13 } 14 vectors 15 }
理论的验证
上面的理论看似有理有据令人信服,但究竟对不对呢?
我们可以通过打印程序执行过程中每一轮的轮次、最小值和当前元素组。添加了打印语句的代码如下:
1 fn selection_sort(vectors: &mut Vec<i32>) -> &Vec<i32>{ 2 for i in 0..vectors.len(){ 3 // 寻找未排序元素中的最小值,即[i, n)中的最小元素 4 let mut index = i; 5 for j in i+1..vectors.len(){ 6 if vectors[j] < vectors[index]{ 7 index = j; 8 } 9 } 10 println!("现在是第 {} 轮, 最小值: {}, vectors: {:?}", i, vectors[index], vectors); 11 let middle = vectors[index]; 12 vectors[index] = vectors[i]; 13 vectors[i] = middle; 14 } 15 vectors 16 }
代码运行后的打印结果如为:
1 现在是第 0 轮, 最小值: -1, vectors: [7, 21, 9, 13, 109, 9, 2, 50, 33, -1, 20, 11] 2 现在是第 1 轮, 最小值: 2, vectors: [-1, 21, 9, 13, 109, 9, 2, 50, 33, 7, 20, 11] 3 现在是第 2 轮, 最小值: 7, vectors: [-1, 2, 9, 13, 109, 9, 21, 50, 33, 7, 20, 11] 4 现在是第 3 轮, 最小值: 9, vectors: [-1, 2, 7, 13, 109, 9, 21, 50, 33, 9, 20, 11] 5 现在是第 4 轮, 最小值: 9, vectors: [-1, 2, 7, 9, 109, 13, 21, 50, 33, 9, 20, 11] 6 现在是第 5 轮, 最小值: 11, vectors: [-1, 2, 7, 9, 9, 13, 21, 50, 33, 109, 20, 11] 7 现在是第 6 轮, 最小值: 13, vectors: [-1, 2, 7, 9, 9, 11, 21, 50, 33, 109, 20, 13] 8 现在是第 7 轮, 最小值: 20, vectors: [-1, 2, 7, 9, 9, 11, 13, 50, 33, 109, 20, 21] 9 现在是第 8 轮, 最小值: 21, vectors: [-1, 2, 7, 9, 9, 11, 13, 20, 33, 109, 50, 21] 10 现在是第 9 轮, 最小值: 33, vectors: [-1, 2, 7, 9, 9, 11, 13, 20, 21, 109, 50, 33] 11 现在是第 10 轮, 最小值: 50, vectors: [-1, 2, 7, 9, 9, 11, 13, 20, 21, 33, 50, 109] 12 现在是第 11 轮, 最小值: 109, vectors: [-1, 2, 7, 9, 9, 11, 13, 20, 21, 33, 50, 109]
由此可见,理论部分的描述是正确的,即每轮次将右侧元素中的最小值与当前轮次元素的位置交换。
完整的 Rust 选择排序代码如下:
Rust 算法代码仓库地址 github.com/asyncins/ac…
作者:华为云云享专家 韦世东