Skip to content

Commit

Permalink
sort: Fix binary insertion sort
Browse files Browse the repository at this point in the history
  • Loading branch information
XuShaohua committed Jul 1, 2024
1 parent 950743b commit 1a8d06e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 21 deletions.
2 changes: 1 addition & 1 deletion search/src/binary_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source is governed by General Public License that can be
// found in the LICENSE file.

//#[allow(clippy::comparison_chain)]
#[allow(clippy::comparison_chain)]
#[must_use]
pub fn binary_search<T: PartialOrd>(nums: &[T], target: &T) -> Option<usize> {
let mut low = 0;
Expand Down
2 changes: 1 addition & 1 deletion sort/benches/insertion_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use sort::insertion_sort::{binary_insertion_sort, insertion_sort, insertion_sort
use sort::util::random_ints;

fn criterion_benchmark(c: &mut Criterion) {
for exp in 1..5 {
for exp in 1..6 {
let len: usize = 2 * 10_usize.pow(exp);
let arr = random_ints(len).expect("Failed to generate random integers");
let title1 = format!("std_sort_for_insertion_sort {len}");
Expand Down
16 changes: 16 additions & 0 deletions sort/src/bin/binary_insertion_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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::insertion_sort::binary_insertion_sort;
use sort::util::{is_sorted, read_ints, show_brief};

fn main() {
let mut list = read_ints();
println!("[Binary InsertionSort] LIST:");
show_brief(&list);
binary_insertion_sort(&mut list);
println!("RESULT:");
assert!(is_sorted(&list));
show_brief(&list);
}
2 changes: 1 addition & 1 deletion sort/src/bin/insertion_sort_recursive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use sort::util::{is_sorted, read_ints, show_brief};

fn main() {
let mut list = read_ints();
println!("[InsertionSort Vanilla] LIST:");
println!("[InsertionSort Recursive] LIST:");
show_brief(&list);
insertion_sort_recursive(&mut list);
println!("RESULT:");
Expand Down
95 changes: 77 additions & 18 deletions sort/src/insertion_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Use of this source is governed by General Public License that can be
// found in the LICENSE file.

use std::cmp::Ordering;

/// 其思路是, 先将前 i 个元素调整为增序的, 随着 i 从 0 增大到 n, 整个序列就变得是增序了.
pub fn insertion_sort<T>(list: &mut [T])
where
Expand Down Expand Up @@ -44,37 +42,60 @@ where
}
}

fn binary_search<T>(list: &[T], source_index: usize) -> usize
#[allow(dead_code)]
fn binary_search_fake<T>(list: &[T], target: &T) -> usize
where
T: PartialOrd,
{
for i in (0..list.len()).rev() {
if list[i] < *target {
return i + 1;
}
}
0
}

fn binary_search<T>(list: &[T], target: &T) -> usize
where
T: Ord,
T: PartialOrd,
{
let mut low: usize = 0;
let mut high = source_index;

while low < high {
let middle = low / 2 + (high - low) / 2;
match list[middle].cmp(&list[source_index]) {
Ordering::Less => low = middle + 1,
Ordering::Equal => return middle + 1,
Ordering::Greater => high = middle - 1,
let mut left = 0;
let mut right = list.len() - 1;
while left < right {
let middle = left + (right - left) / 2;
// 找到了相等的元素, 就返回该位置的下一个位置
if list[middle] == *target {
return middle + 1;
} else if list[middle] < *target {
left = middle + 1;
} else {
right = middle;
}
}
low

// 没有找到相等的元素, 就返回期望的位置.
if list[list.len() - 1] < *target {
return list.len();
}
if list[0] > *target {
return 0;
}
left
}


/// 二分插入排序法 binary insertion sort
pub fn binary_insertion_sort<T>(list: &mut [T])
where
T: Ord,
T: PartialOrd + std::fmt::Debug,
{
let len = list.len();
if len < 2 {
return;
}

for i in 1..len {
let target_pos = binary_search(list, i);
debug_assert!(target_pos <= i);
let target_pos = binary_search(&list[..i], &list[i]);
for j in (target_pos..i).rev() {
list.swap(j, j + 1);
}
Expand All @@ -83,7 +104,7 @@ where

#[cfg(test)]
mod tests {
use super::{binary_insertion_sort, insertion_sort, insertion_sort_recursive};
use super::{binary_insertion_sort, binary_search, binary_search_fake, insertion_sort, insertion_sort_recursive};

#[test]
fn test_insertion_sort() {
Expand Down Expand Up @@ -147,6 +168,44 @@ mod tests {
);
}

#[test]
fn test_binary_search_fake() {
let list = [0, 5, 3, 2, 2];
let pos = binary_search_fake(&list[0..1], &5);
assert_eq!(pos, 1);

let list = [0, 5, 3, 2, 2];
let pos = binary_search_fake(&list[0..2], &3);
assert_eq!(pos, 1);

let list = [-5, -2, -45];
let pos = binary_search_fake(&list[0..1], &(-2));
assert_eq!(pos, 1);

let list = [-5, -2, -45];
let pos = binary_search_fake(&list[0..2], &(-45));
assert_eq!(pos, 0);
}

#[test]
fn test_binary_search() {
let list = [0, 5, 3, 2, 2];
let pos = binary_search(&list[0..1], &5);
assert_eq!(pos, 1);

let list = [0, 5, 3, 2, 2];
let pos = binary_search(&list[0..2], &3);
assert_eq!(pos, 1);

let list = [-5, -2, -45];
let pos = binary_search(&list[0..1], &(-2));
assert_eq!(pos, 1);

let list = [-5, -2, -45];
let pos = binary_search(&list[0..2], &(-45));
assert_eq!(pos, 0);
}

#[test]
fn test_binary_insertion_sort() {
let mut list = [0, 5, 3, 2, 2];
Expand Down

0 comments on commit 1a8d06e

Please sign in to comment.