From 611512bbebfe3c62e741a142b00c04c679de8e81 Mon Sep 17 00:00:00 2001 From: U2A5F Date: Tue, 21 Nov 2023 22:27:23 +0800 Subject: [PATCH] selection sort --- README.md | 11 +++++ tuples/Cargo.toml | 4 +- tuples/src/lib.rs | 5 +++ tuples/src/sort.rs | 108 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 tuples/src/sort.rs diff --git a/README.md b/README.md index 5c2a309..87dc5a1 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Provides many useful tools related to tuples - Shorthand Macro - Call - Apply +- Sort ## Examples @@ -245,3 +246,13 @@ Provides many useful tools related to tuples let r = foo.apply_tuple(a); assert_eq!(r, 6) ``` +- sort + currently implemented + + - selection sort + + ```rust + let mut a = (6, 2, 6, 8, 0, 5); + a.sort_selection(); + assert_eq!(a, (0, 2, 5, 6, 6, 8)) + ``` diff --git a/tuples/Cargo.toml b/tuples/Cargo.toml index 67af2e4..e283057 100644 --- a/tuples/Cargo.toml +++ b/tuples/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "tuples" readme = "../README.md" repository = "https://github.com/libsugar/tuplers" -version = "1.13.0" +version = "1.14.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -35,10 +35,12 @@ default = [ "re-exports", "capt", "tuple_get", + "sort", ] flatten = [] re-exports = [] shorthand = [] +sort = ["tuple_meta", "tuple_get"] split = ["split_parts", "split_by", "split_to_tuple_by", "split_at", "split_to_tuple_at"] split_at = [] split_by = [] diff --git a/tuples/src/lib.rs b/tuples/src/lib.rs index 611e91e..aa53627 100644 --- a/tuples/src/lib.rs +++ b/tuples/src/lib.rs @@ -195,3 +195,8 @@ pub use capt::*; pub mod tuple_get; #[cfg(all(feature = "tuple_get", feature = "re-exports"))] pub use tuple_get::*; + +#[cfg(all(feature = "sort", feature = "tuple_meta", feature = "tuple_get"))] +pub mod sort; +#[cfg(all(feature = "sort", feature = "tuple_meta", feature = "tuple_get", feature = "re-exports"))] +pub use sort::*; diff --git a/tuples/src/sort.rs b/tuples/src/sort.rs new file mode 100644 index 0000000..67620e3 --- /dev/null +++ b/tuples/src/sort.rs @@ -0,0 +1,108 @@ +//! Sort tuples + +use crate::{TupleGetMut, TupleSame}; + +/// Sort tuples using selection sort +pub trait TupleSortSelection { + /// Sort tuples using selection sort + /// + /// It has an `O(n2)` time complexity + fn sort_selection(&mut self); +} + +impl + TupleGetMut> TupleSortSelection for S { + #[inline] + fn sort_selection(&mut self) { + if sort_base(self, T::lt) { + return; + } + selection_sort(self, T::lt) + } +} + +fn sort_base + TupleGetMut>(v: &mut S, mut is_less: impl FnMut(&T, &T) -> bool) -> bool { + if core::mem::size_of::() == 0 { + return true; + } + + let len = v.arity(); + if len <= 1 { + return true; + } + if len == 2 { + let this = v as *mut S; + let a = unsafe { (&mut *this).get_mut(0) }; + let b = unsafe { (&mut *this).get_mut(1) }; + + if is_less(a, b) { + return true; + } else if is_less(b, a) { + core::mem::swap(a, b); + return true; + } else { + return true; + } + } + + false +} + +fn selection_sort + TupleGetMut>(v: &mut S, mut is_less: impl FnMut(&T, &T) -> bool) { + let len = v.arity(); + for i in 0..(len - 1) { + let mut min_index = i; + + for j in (i + 1)..len { + if is_less(v.get(j), v.get(min_index)) { + min_index = j; + } + } + + if min_index != i { + let this = v as *mut S; + let a = unsafe { (&mut *this).get_mut(i) }; + let b = unsafe { (&mut *this).get_mut(min_index) }; + core::mem::swap(a, b); + } + } +} + +#[cfg(test)] +mod test_selection_sort { + use super::*; + + #[test] + fn test1() { + let mut a = (6, 2, 6, 8, 0, 5); + a.sort_selection(); + assert_eq!(a, (0, 2, 5, 6, 6, 8)) + } + + #[test] + fn test2() { + let mut a = (1, 2, 3, 4, 5, 6); + a.sort_selection(); + assert_eq!(a, (1, 2, 3, 4, 5, 6)) + } + + #[test] + fn test3() { + let mut a = (2, 1); + a.sort_selection(); + assert_eq!(a, (1, 2)) + } + + #[test] + fn test4() { + let mut a = (1, 2); + a.sort_selection(); + assert_eq!(a, (1, 2)) + } + + #[test] + fn test5() { + let mut a = (1.5, 7.1, 3.0, 9.9, 0.3, 0.125, 0.1 + 0.2); + a.sort_selection(); + assert_eq!(a, (0.125, 0.3, 0.1 + 0.2, 1.5, 3.0, 7.1, 9.9)) + } +}