diff --git a/Cargo.lock b/Cargo.lock index 7868865f..9aec2e51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,6 +248,17 @@ version = "0.1.0" name = "geodesy" version = "0.1.0" +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "graphs" version = "0.1.0" @@ -522,6 +533,12 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.66" @@ -540,6 +557,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" version = "1.7.0" @@ -663,6 +710,9 @@ dependencies = [ [[package]] name = "sorts" version = "0.1.0" +dependencies = [ + "rand", +] [[package]] name = "syn" @@ -701,6 +751,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.87" diff --git a/sorts/Cargo.toml b/sorts/Cargo.toml index 59a01624..4c381f32 100644 --- a/sorts/Cargo.toml +++ b/sorts/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" publish = false [dependencies] +rand = "0.8.5" diff --git a/sorts/src/bin/bubble_sort.rs b/sorts/src/bin/bubble_sort.rs new file mode 100644 index 00000000..4cf7809c --- /dev/null +++ b/sorts/src/bin/bubble_sort.rs @@ -0,0 +1,16 @@ +// Copyright (c) 2020 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +use sorts::bubble_sort; +use sorts::util::{is_sorted, read_ints, show_brief}; + +fn main() { + let mut list = read_ints(); + println!("[BubbleSort] LIST:"); + show_brief(&list); + bubble_sort(&mut list); + println!("RESULT:"); + assert!(is_sorted(&list)); + show_brief(&list); +} diff --git a/sorts/src/bin/insertion_sort.rs b/sorts/src/bin/insertion_sort.rs new file mode 100644 index 00000000..f7d9cdce --- /dev/null +++ b/sorts/src/bin/insertion_sort.rs @@ -0,0 +1,20 @@ +// Copyright (c) 2020 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +use sorts::util::{is_sorted, read_ints, show_brief}; +use sorts::{insertion_sort, insertion_sort_vanilla}; + +fn main() { + let mut list = read_ints(); + println!("[InsertionSort] LIST:"); + show_brief(&list); + let mut list2 = list.clone(); + insertion_sort(&mut list); + println!("RESULT:"); + assert!(is_sorted(&list)); + show_brief(&list); + + insertion_sort_vanilla(&mut list2); + assert!(is_sorted(&list2)); +} diff --git a/sorts/src/bin/merge_sort.rs b/sorts/src/bin/merge_sort.rs new file mode 100644 index 00000000..2e1d5f45 --- /dev/null +++ b/sorts/src/bin/merge_sort.rs @@ -0,0 +1,16 @@ +// Copyright (c) 2020 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +use sorts::merge_sort; +use sorts::util::{is_sorted, read_ints, show_brief}; + +fn main() { + let mut list = read_ints(); + println!("[MergeSort] list"); + show_brief(&list); + merge_sort(&mut list); + println!("Result:"); + show_brief(&list); + assert!(is_sorted(&list)); +} diff --git a/sorts/src/bin/selection_sort.rs b/sorts/src/bin/selection_sort.rs new file mode 100644 index 00000000..18cd4c20 --- /dev/null +++ b/sorts/src/bin/selection_sort.rs @@ -0,0 +1,14 @@ +// Copyright (c) 2020 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +use sorts::selection_sort; +use sorts::util::{is_sorted, read_ints, show_brief}; + +fn main() { + let mut list = read_ints(); + selection_sort(&mut list); + assert!(is_sorted(&list)); + println!("RESULT:"); + show_brief(&list); +} diff --git a/sorts/src/bin/shell_sort.rs b/sorts/src/bin/shell_sort.rs new file mode 100644 index 00000000..aa620565 --- /dev/null +++ b/sorts/src/bin/shell_sort.rs @@ -0,0 +1,16 @@ +// Copyright (c) 2020 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +use sorts::shell_sort; +use sorts::util::{is_sorted, read_ints, show_brief}; + +fn main() { + let mut list = read_ints(); + println!("[ShellSort] LIST:"); + show_brief(&list); + shell_sort(&mut list); + println!("RESULT:"); + assert!(is_sorted(&list)); + show_brief(&list); +} diff --git a/sorts/src/bin/sort_compare.rs b/sorts/src/bin/sort_compare.rs new file mode 100644 index 00000000..d1f4e9b7 --- /dev/null +++ b/sorts/src/bin/sort_compare.rs @@ -0,0 +1,54 @@ +// Copyright (c) 2020 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +use rand::Rng; +use std::time::Instant; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum SortVariant { + Insertion, + Selection, + Shell, +} + +fn time_sort(array: &mut [f64], variant: SortVariant) -> u128 { + let instance = Instant::now(); + match variant { + SortVariant::Insertion => sorts::insertion_sort(array), + SortVariant::Selection => sorts::selection_sort(array), + SortVariant::Shell => sorts::shell_sort(array), + } + instance.elapsed().as_nanos() +} + +fn time_random_input(variant: SortVariant, len: usize, times: i32) -> u128 { + let mut total = 0; + let mut rng = rand::thread_rng(); + let mut array = vec![0.0; len]; + for _t in 0..times { + for item in array.iter_mut() { + *item = rng.gen(); + } + total += time_sort(&mut array, variant); + } + + total +} + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() != 3 { + panic!("Usage: number times"); + } + let num: usize = args[1].parse().expect("Invalid total length"); + let times: i32 = args[2].parse().expect("Invalid times"); + let t1 = time_random_input(SortVariant::Insertion, num, times); + let t2 = time_random_input(SortVariant::Selection, num, times); + let t3 = time_random_input(SortVariant::Shell, num, times); + + println!("Insertion: {t1}, Selection: {t2}, ShellSort: {t3}"); + let ratio1: f64 = (t1 as f64) / (t3 as f64); + let ratio2: f64 = t2 as f64 / t3 as f64; + println!("Insertion ratio: {ratio1:.2}, Selection ratio: {ratio2:.2}, Shell ratio: 1.0"); +} diff --git a/sorts/src/lib.rs b/sorts/src/lib.rs index b686ff4f..31c9fdf8 100644 --- a/sorts/src/lib.rs +++ b/sorts/src/lib.rs @@ -20,6 +20,7 @@ mod odd_even_sort; mod selection_sort; mod shaker_sort; mod shell_sort; +pub mod util; pub use bubble_sort::bubble_sort; pub use double_sort::double_sort; diff --git a/sorts/src/util.rs b/sorts/src/util.rs new file mode 100644 index 00000000..bc4fb8f2 --- /dev/null +++ b/sorts/src/util.rs @@ -0,0 +1,76 @@ +// Copyright (c) 2020 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +use std::fmt; +use std::io::{self, BufRead, BufReader}; + +pub fn is_sorted(list: &[T]) -> bool +where + T: PartialOrd + fmt::Debug, +{ + for i in 0..(list.len() - 1) { + if list[i] > list[i + 1] { + println!( + "Order error at: {i}, values: ({:?}, {:?})", + list[i], + list[i + 1] + ); + return false; + } + } + true +} + +pub fn show(slice: &[T]) +where + T: fmt::Display, +{ + for s in slice { + print!("{s} "); + } + println!(); +} + +pub fn show_brief(slice: &[T]) +where + T: fmt::Display, +{ + if slice.len() < 128 { + show(slice); + } else { + show(&slice[..128]); + println!("...\n..."); + } +} + +/// Read integers from stdin. +/// +/// # Panics +/// Raise panic if invalid integer found. +#[must_use] +pub fn read_ints() -> Vec { + let mut v = vec![]; + let buffer = BufReader::new(io::stdin()); + let input_iter = buffer.lines(); + for line in input_iter.flatten() { + for word in line.split_whitespace() { + let value = word.parse::().expect("Invalid integer"); + v.push(value); + } + } + v +} + +#[must_use] +pub fn read_strings() -> Vec { + let buffer = BufReader::new(io::stdin()); + let input_iter = buffer.lines(); + let mut v = vec![]; + for line in input_iter.flatten() { + for word in line.split_whitespace() { + v.push(word.to_string()); + } + } + v +}