Skip to content

Commit

Permalink
sorts: Add binary of selection_sort_recursive
Browse files Browse the repository at this point in the history
  • Loading branch information
XuShaohua committed Jun 30, 2024
1 parent 278d041 commit 31a85ce
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 4 deletions.
18 changes: 17 additions & 1 deletion sort/benches/selection_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use criterion::{Criterion, criterion_group, criterion_main};

use sort::selection_sort;
use sort::{selection_sort, selection_sort_min_max, selection_sort_recursive};
use sort::util::random_ints;

fn criterion_benchmark(c: &mut Criterion) {
Expand All @@ -13,14 +13,30 @@ fn criterion_benchmark(c: &mut Criterion) {
let arr = random_ints(len).expect("Failed to generate random integers");
let title1 = format!("std_sort {len}");
let title2 = format!("selection_sort {len}");
let title3 = format!("selection_sort_recursive {len}");
let title4 = format!("selection_sort_min_max {len}");
let mut arr_sorted = arr.clone();
arr_sorted.sort();

c.bench_function(&title1, |b| b.iter(|| {
let mut arr1 = arr.clone();
arr1.sort();
assert_eq!(arr1, arr_sorted);
}));
c.bench_function(&title2, |b| b.iter(|| {
let mut arr2 = arr.clone();
selection_sort(&mut arr2);
assert_eq!(arr2, arr_sorted);
}));
c.bench_function(&title3, |b| b.iter(|| {
let mut arr3 = arr.clone();
selection_sort_recursive(&mut arr3);
assert_eq!(arr3, arr_sorted);
}));
c.bench_function(&title4, |b| b.iter(|| {
let mut arr4 = arr.clone();
selection_sort_min_max(&mut arr4);
assert_eq!(arr4, arr_sorted);
}));
}
}
Expand Down
14 changes: 14 additions & 0 deletions sort/src/bin/selection_sort_min_max.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2020 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by General Public License that can be found
// in the LICENSE file.

use sort::selection_sort_min_max;
use sort::util::{is_sorted, read_ints, show_brief};

fn main() {
let mut list = read_ints();
selection_sort_min_max(&mut list);
assert!(is_sorted(&list));
println!("RESULT:");
show_brief(&list);
}
14 changes: 14 additions & 0 deletions sort/src/bin/selection_sort_recursive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2020 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by General Public License that can be found
// in the LICENSE file.

use sort::selection_sort_recursive;
use sort::util::{is_sorted, read_ints, show_brief};

fn main() {
let mut list = read_ints();
selection_sort_recursive(&mut list);
assert!(is_sorted(&list));
println!("RESULT:");
show_brief(&list);
}
2 changes: 1 addition & 1 deletion sort/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use merge_sort::merge_sort;
pub use odd_even_sort::odd_even_sort;
pub use quick_sort::quick_sort;
pub use radix_sort::radix_sort;
pub use selection_sort::{selection_sort, selection_sort_recursive};
pub use selection_sort::{selection_sort, selection_sort_min_max, selection_sort_recursive};
pub use shaker_sort::shaker_sort;
pub use shell_sort::shell_sort;

Expand Down
99 changes: 98 additions & 1 deletion sort/src/selection_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,59 @@ where
selection_sort_recursive(&mut list[1..]);
}

/// 选择排序的一个小优化.
///
/// 将最小的元素放在左侧的同时, 将最大的元素放在右侧.
pub fn selection_sort_min_max<T>(list: &mut [T])
where
T: PartialOrd + std::fmt::Debug,
{
let len = list.len();
if list.len() < 2 {
return;
}

let mut start = 0;
let mut end = len - 1;
while start < end {
// 找到最小元素的索引
let mut min_index = start;
let mut max_index = start;
for i in start..=end {
if list[i] < list[min_index] {
min_index = i;
}
if list[i] > list[max_index] {
max_index = i;
}
}

println!("start: {start}, end: {end}, min: {min_index}, max: {max_index}");
println!("start value: {:?}, end: {:?}, min: {:?}, max: {:?}",
list[start], list[end], list[min_index], list[max_index]);
if min_index == 497 {
println!("list slice: {list:?}");
}

if start != min_index {
list.swap(start, min_index);
}

if end != max_index && !(start == max_index && end == min_index) {
list.swap(end, max_index);
}

start += 1;
if end > 1 {
end -= 1;
}
}
println!("END of sort");
}

#[cfg(test)]
mod tests {
use super::{selection_sort, selection_sort_recursive};
use super::{selection_sort, selection_sort_min_max, selection_sort_recursive};

#[test]
fn test_selection_sort() {
Expand Down Expand Up @@ -113,4 +163,51 @@ mod tests {
]
);
}

#[test]
fn test_selection_sort_min_max() {
let mut list = [0, 5, 3, 2, 2];
selection_sort_min_max(&mut list);
assert_eq!(list, [0, 2, 2, 3, 5]);

let mut list = [-2, -5, -45];
selection_sort_min_max(&mut list);
assert_eq!(list, [-45, -5, -2]);

let mut list = [
-998_166, -996_360, -995_703, -995_238, -995_066, -994_740, -992_987, -983_833,
-987_905, -980_069, -977_640,
];
selection_sort_min_max(&mut list);
assert_eq!(
list,
[
-998_166, -996_360, -995_703, -995_238, -995_066, -994_740, -992_987, -987_905,
-983_833, -980_069, -977_640,
]
);

let mut list = [
28894, 30024, 31175, 29332, 36942
];
selection_sort_min_max(&mut list);
assert_eq!(
list,
[
28894, 29332, 30024, 31175, 36942
]
);

let mut list = [
3713, 13249, 19224, 13962, -3804, -10101, 19000, 13820, 13993, 799, 14012
, 3752, -12288,
];
selection_sort_min_max(&mut list);
assert_eq!(
list,
[
-12288, -10101, -3804, 799, 3713, 3752, 13249, 13820, 13962, 13993, 14012, 19000, 19224,
]
);
}
}
2 changes: 1 addition & 1 deletion src/array/sort/insertion-sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
- 插入排序比较适合元素较少的数组
- 插入排序适合基本已排序好的数组
- 插入排序常用于组合排序算法中, 用于排序较少元素的部分数组; 比如 cpp 里面的 `std::sort()` 以及 python
里的 `vector.sort()`
里的 `timsort()`
9 changes: 9 additions & 0 deletions src/array/sort/selection-sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@
{{#include assets/selection_sort.rs:30:63}}
```

## 优化选择排序

默认实现的选择排序, 在每次循环时会找到最小的元素, 然后把它放在数组的左侧部分.
每次循环时, 我们可以同时找到最大的元素, 然后把它放在数组的右侧部分. 这样的话, 每个循环就可以同时找到最小和最大的元素.

```rust
{{#include assets/selection_sort.rs:65:103 }}
```

## 选择排序的特点

1. 即使数组中的元素基本排序好, 也需要遍历所有元素并比较大小, 这种情况下效率较低, 依然需要 `N^2 / 2` 次比较操作
Expand Down

0 comments on commit 31a85ce

Please sign in to comment.