From f700da279f29f31937bbf3e3ee1dbfc5004240da Mon Sep 17 00:00:00 2001 From: c1m50c <58411864+c1m50c@users.noreply.github.com> Date: Fri, 10 Jun 2022 18:48:24 -0500 Subject: [PATCH 1/4] Start on 2.0 --- Cargo.toml | 4 +- README.MD | 52 +------- src/hashing/mod.rs | 1 - src/hashing/sha256.rs | 184 --------------------------- src/lib.rs | 5 - src/searching/binary_search.rs | 55 -------- src/searching/concatenated_search.rs | 70 ---------- src/searching/linear_search.rs | 51 -------- src/searching/mod.rs | 4 - src/sorting/bubble_sort.rs | 56 -------- src/sorting/comb_sort.rs | 62 --------- src/sorting/concatenated_sort.rs | 87 ------------- src/sorting/gnome_sort.rs | 48 ------- src/sorting/heap_sort.rs | 93 -------------- src/sorting/insertion_sort.rs | 48 ------- src/sorting/merge_sort.rs | 95 -------------- src/sorting/mod.rs | 11 -- src/sorting/quick_sort.rs | 74 ----------- src/sorting/selection_sort.rs | 53 -------- src/sorting/shell_sort.rs | 56 -------- 20 files changed, 3 insertions(+), 1106 deletions(-) delete mode 100644 src/hashing/mod.rs delete mode 100644 src/hashing/sha256.rs delete mode 100644 src/searching/binary_search.rs delete mode 100644 src/searching/concatenated_search.rs delete mode 100644 src/searching/linear_search.rs delete mode 100644 src/searching/mod.rs delete mode 100644 src/sorting/bubble_sort.rs delete mode 100644 src/sorting/comb_sort.rs delete mode 100644 src/sorting/concatenated_sort.rs delete mode 100644 src/sorting/gnome_sort.rs delete mode 100644 src/sorting/heap_sort.rs delete mode 100644 src/sorting/insertion_sort.rs delete mode 100644 src/sorting/merge_sort.rs delete mode 100644 src/sorting/mod.rs delete mode 100644 src/sorting/quick_sort.rs delete mode 100644 src/sorting/selection_sort.rs delete mode 100644 src/sorting/shell_sort.rs diff --git a/Cargo.toml b/Cargo.toml index 72323c9..524ed36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rust-algorithms" -version = "1.0.0" -edition = "2018" +version = "2.0.0" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.MD b/README.MD index ae03e95..16d3e86 100644 --- a/README.MD +++ b/README.MD @@ -1,51 +1 @@ -# **📚 rust-algorithms** -[![Build](https://github.com/c1m50c/rust-algorithms/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/c1m50c/rust-algorithms/actions/workflows/build.yml) - -Library containing various algorithms implemented with a Rust counter-part. - - -## **Running** -You can test the algorithms to ensure they work by using `cargo test`, an example of it's usage is shown below. -```bash -$ cd rust-algorithms # Change directory to repository. -$ cargo test # Run the `cargo test` command to run the library's tests. -... -test result: ok. # If things go well all tests should pass. -``` - - -## **Implemented Algorithms** - -
-🥔 Hashing Algorithms - -
- -
-🔎 Searching Algorithms - -
- -
-🧮 Sorting Algorithms - -
- - -## **License** -MIT License \ No newline at end of file +# rust-algorithms diff --git a/src/hashing/mod.rs b/src/hashing/mod.rs deleted file mode 100644 index 0835abd..0000000 --- a/src/hashing/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod sha256; \ No newline at end of file diff --git a/src/hashing/sha256.rs b/src/hashing/sha256.rs deleted file mode 100644 index 0b8a7c8..0000000 --- a/src/hashing/sha256.rs +++ /dev/null @@ -1,184 +0,0 @@ -/* - SHA256 - ====== - -- Rust implementation of the Secure Hashing Algorithm. - |> Specification Sheet: https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf - |> Wikipedia: https://en.wikipedia.org/wiki/SHA-2 -*/ - - -use core::{u8, u32, u64}; -use std::string::String; -use std::vec::Vec; - -const MODULO: u32 = 4294967295; // TODO: This is (2^32)-1 not 2^32, so this might not work properly??? - -const K: [u32; 64] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -]; - - -// TODO: The actual function -pub fn sha256(message: String) -> Vec { - let mut message_vec = message.bytes().collect::>(); - - /* - Padding - ======= - -- Pads the input message for it to be evenly split into 512-Bit Chunks. - */ - let message_length = message_vec.len() * 8; - message_vec.push(0x80 as u8); - while (message_vec.len() * 8 + 64) % 512 != 0 { message_vec.push(0x00 as u8); } - for b in message_length.to_ne_bytes() { message_vec.push(b); } - assert_eq!((message_vec.len() * 8) % 512, 0, "Message was not properly padded."); - - - /* - Parsing - ======= - -- Parse the padded message into 512-Bit Chunks. - */ - let mut chunks: Vec> = Vec::new(); - while message_vec.len() != 0 { - let mut new_chunk = Vec::with_capacity(64); - - for _ in 0 .. 64 { - new_chunk.push(message_vec.pop().unwrap()); - } - - assert_eq!(new_chunk.len(), 64, "Could not parse message into chunks properly."); - - chunks.push(new_chunk); - } - - assert_ne!(chunks.len(), 0, "Could not split message into any chunks."); - - - let mut hash: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, - ]; - - - /* - Computation - =========== - |> TODO: Finish this section. - */ - for c in chunks { - let mut w = Vec::::with_capacity(64); - - for t in 0 .. 64 { - /* FIXME: Conversion to u32 might result in miscalculation later? */ - /* FIXME: Addition overflow error */ - if t <= 15 { w.push(c[t] as u32); } - else { w.push((lc_sigma_1(w[t - 2]) + w[t - 7] + lc_sigma_0(w[t - 15]) + w[t - 16]) % MODULO); } - } - - assert_eq!(w.len(), 64, "Could not properly create a message schedule."); - - let mut a = hash[0]; - let mut b = hash[1]; - let mut c = hash[2]; - let mut d = hash[3]; - let mut e = hash[4]; - let mut f = hash[5]; - let mut g = hash[6]; - let mut h = hash[7]; - - for t in 0 .. 64 { - let t1: u32 = (h + sigma_1(e) + ch(e, f, g) + K[t] + w[t]) % MODULO; - let t2: u32 = (sigma_0(a) + maj(a, b, c)) % MODULO; - - h = g; - g = f; - f = e; - e = (d + t1) % MODULO; - d = c; - c = b; - b = a; - a = (t1 + t2) % MODULO; - } - - hash[0] = (a + hash[0]) % MODULO; - hash[1] = (b + hash[1]) % MODULO; - hash[2] = (c + hash[2]) % MODULO; - hash[3] = (d + hash[3]) % MODULO; - hash[4] = (e + hash[4]) % MODULO; - hash[5] = (f + hash[5]) % MODULO; - hash[6] = (g + hash[6]) % MODULO; - hash[7] = (h + hash[7]) % MODULO; - } - - let mut bytes: Vec = Vec::with_capacity(8 * 4); - bytes.append(&mut hash[0].to_be_bytes().to_vec().to_owned()); - bytes.append(&mut hash[1].to_be_bytes().to_vec().to_owned()); - bytes.append(&mut hash[2].to_be_bytes().to_vec().to_owned()); - bytes.append(&mut hash[3].to_be_bytes().to_vec().to_owned()); - bytes.append(&mut hash[4].to_be_bytes().to_vec().to_owned()); - bytes.append(&mut hash[5].to_be_bytes().to_vec().to_owned()); - bytes.append(&mut hash[6].to_be_bytes().to_vec().to_owned()); - bytes.append(&mut hash[7].to_be_bytes().to_vec().to_owned()); - - return bytes; -} - - -/* - Helper Functions - ================ - -- Simple functions for ease of use, operations defined in specification sheet. -*/ -#[inline(always)] -const fn rotate_right(x: u32, n: u32) -> u32 { (x >> n) | (x << u32::BITS - n) } - -#[inline(always)] -const fn rotate_left(x: u32, n: u32) -> u32 { (x << n) | (x >> u32::BITS - n) } - -#[inline(always)] -const fn ch(x: u32, y: u32, z: u32) -> u32 { (x & y) ^ (x & z) } - -#[inline(always)] -const fn maj(x: u32, y: u32, z: u32) -> u32 { (x & y) ^ (x & z) ^ (y & z) } - -#[inline(always)] -const fn sigma_0(x: u32) -> u32 { rotate_right(x, 2) ^ rotate_right(x, 13) ^ rotate_right(x, 22) } - -#[inline(always)] -const fn sigma_1(x: u32) -> u32 { rotate_right(x, 6) ^ rotate_right(x, 11) ^ rotate_right(x, 25) } - -#[inline(always)] -const fn lc_sigma_0(x: u32) -> u32 { rotate_right(x, 7) ^ rotate_right(x, 18) ^ (x >> 3) } - -#[inline(always)] -const fn lc_sigma_1(x: u32) -> u32 { rotate_right(x, 17) ^ rotate_right(x, 19) ^ (x >> 10) } - - -// #[cfg(test)] -// mod tests { -// use super::sha256; - -// #[test] -// #[ignore] -// fn hash_one() { -// let to_be_hashed: &str = "Hello, World!"; -// let proper_hash: &str = "DFFD6021BB2BD5B0AF676290809EC3A53191DD81C7F70A4B28688A362182986F"; -// assert_eq!(sha256(to_be_hashed.to_owned()), String::from(proper_hash)); -// } - -// #[test] -// #[ignore] -// fn hash_two() { -// let to_be_hashed: &str = "qwertypassword1"; -// let proper_hash: &str = "D8A5EC5F100B86C9CAD1AB984E0C2AF3D045AE6CFC9529A6F7C9CD0678E719D1"; -// assert_eq!(sha256(to_be_hashed.to_owned()), String::from(proper_hash)); -// } -// } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 2f19430..c35a601 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,3 @@ -pub(crate) mod searching; -pub(crate) mod sorting; -pub(crate) mod hashing; - - #[cfg(test)] mod tests { diff --git a/src/searching/binary_search.rs b/src/searching/binary_search.rs deleted file mode 100644 index 01ff5e2..0000000 --- a/src/searching/binary_search.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::option::Option; -use std::vec::Vec; - - -/// ## Complexities -/// ```py -/// Worst Case Time Complexity == O(log n) -/// Average Case Time Complexity == O(log n) -/// Best Case Time Complexity == O(1) -/// Space Complexity == O(1) -/// ``` -#[allow(dead_code)] -pub fn binary_search(vec: &Vec, finding: T) -> Option { - let (mut left, mut right) = (0, vec.len()); - - while left < right { - let middle: usize = left + (right - left) / 2; - if finding == vec[middle] { return Some(middle); } - else if finding < vec[middle] { right = middle; } - else { left = middle + 1; } - } - - return None; -} - - -#[cfg(test)] -mod tests { - /* Note: Ensure all vectors are properly sorted within the tests. */ - use super::binary_search; - - #[test] - fn find_integer() { - let vec: Vec = vec![-1, 2, 3, 4, 5, 6, 7]; - let found: Option = binary_search(&vec, 4); - assert!(found.is_some()); - assert_eq!(3, found.unwrap()); - } - - #[test] - fn find_unsigned() { - let vec: Vec = vec![0, 2, 4, 6, 8, 10, 12]; - let found: Option = binary_search(&vec, 10); - assert!(found.is_some()); - assert_eq!(5, found.unwrap()); - } - - #[test] - fn find_floating() { - let vec: Vec = vec![1.28, 1.337, 3.33, 4.2, 7.331, 9.6, 9.745]; - let found: Option = binary_search(&vec, 1.337); - assert!(found.is_some()); - assert_eq!(1, found.unwrap()); - } -} \ No newline at end of file diff --git a/src/searching/concatenated_search.rs b/src/searching/concatenated_search.rs deleted file mode 100644 index 5cbe3ab..0000000 --- a/src/searching/concatenated_search.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::option::Option; -use std::vec::Vec; -use super::*; - - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy)] -pub enum SearchingAlgorithms { - LinearSearch, - BinarySearch, -} - - -#[allow(dead_code)] -impl SearchingAlgorithms { - const ALGORITHMS: [Self; 2] = [ - Self::LinearSearch, - Self::BinarySearch, - ]; - - pub fn iterator() -> impl Iterator { - return Self::ALGORITHMS.iter().copied(); - } -} - - -#[allow(dead_code)] -pub fn concatenated_search(vec: &Vec, finding: T, algorithm: SearchingAlgorithms) -> Option { - match algorithm { - SearchingAlgorithms::LinearSearch => { return binary_search::binary_search(vec, finding); } - SearchingAlgorithms::BinarySearch => { return linear_search::linear_search(vec, finding); } - } -} - - -#[cfg(test)] -mod tests { - /* Note: Ensure all vectors are properly sorted within the tests. */ - use super::{SearchingAlgorithms, concatenated_search}; - - #[test] - fn find_integer() { - for alg in SearchingAlgorithms::iterator() { - let vec: Vec = vec![-1, 2, 3, 4, 5, 6, 7]; - let found: Option = concatenated_search(&vec, 4, alg); - assert!(found.is_some()); - assert_eq!(3, found.unwrap()); - } - } - - #[test] - fn find_unsigned() { - for alg in SearchingAlgorithms::iterator() { - let vec: Vec = vec![0, 2, 4, 6, 8, 10, 12]; - let found: Option = concatenated_search(&vec, 10, alg); - assert!(found.is_some()); - assert_eq!(5, found.unwrap()); - } - } - - #[test] - fn find_floating() { - for alg in SearchingAlgorithms::iterator() { - let vec: Vec = vec![1.28, 1.337, 3.33, 4.2, 7.331, 9.6, 9.745]; - let found: Option = concatenated_search(&vec, 1.337, alg); - assert!(found.is_some()); - assert_eq!(1, found.unwrap()); - } - } -} \ No newline at end of file diff --git a/src/searching/linear_search.rs b/src/searching/linear_search.rs deleted file mode 100644 index f12fef5..0000000 --- a/src/searching/linear_search.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::option::Option; -use std::vec::Vec; - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n) -/// Average Case Time Complexity == O(n / 2) -/// Best Case Time Complexity == O(1) -/// Space Complexity == O(1) -/// ``` -#[allow(dead_code)] -pub fn linear_search(vec: &Vec, finding: T) -> Option { - for index in 0 .. vec.len() { - if vec[index] == finding { - return Some(index); - } - } - - return None; -} - - -#[cfg(test)] -mod tests { - use super::linear_search; - - #[test] - fn find_integer() { - let vec: Vec = vec![-1, 2, 3, 4, 5, 6, 7]; - let found: Option = linear_search(&vec, 4); - assert!(found.is_some()); - assert_eq!(3, found.unwrap()); - } - - #[test] - fn find_unsigned() { - let vec: Vec = vec![0, 2, 4, 6, 8, 10, 12]; - let found: Option = linear_search(&vec, 10); - assert!(found.is_some()); - assert_eq!(5, found.unwrap()); - } - - #[test] - fn find_floating() { - let vec: Vec = vec![1.28, 1.337, 3.33, 4.2, 7.331, 9.6, 9.745]; - let found: Option = linear_search(&vec, 1.337); - assert!(found.is_some()); - assert_eq!(1, found.unwrap()); - } -} \ No newline at end of file diff --git a/src/searching/mod.rs b/src/searching/mod.rs deleted file mode 100644 index 27b743a..0000000 --- a/src/searching/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub(crate) mod concatenated_search; - -pub(crate) mod linear_search; -pub(crate) mod binary_search; \ No newline at end of file diff --git a/src/sorting/bubble_sort.rs b/src/sorting/bubble_sort.rs deleted file mode 100644 index 7402165..0000000 --- a/src/sorting/bubble_sort.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::vec::Vec; - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n * n) -/// Average Case Time Complexity == O(n * n) -/// Best Case Time Complexity == O(n) -/// Space Complexity == O(n) Total, O(1) Auxiliary -/// ``` -#[allow(dead_code)] -pub fn bubble_sort(vec: &mut Vec) { - let vec_len: usize = vec.len(); - - for i in 0 .. vec_len { - let mut swapped: bool = false; - - for j in 0 .. vec_len - i - 1 { - if vec[j] > vec[j + 1] { - vec.swap(j, j + 1); - swapped = true; - } - } - - if swapped == false { - break; - } - } -} - - -#[cfg(test)] -mod tests { - use super::bubble_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - bubble_sort(&mut vec); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - bubble_sort(&mut vec); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - bubble_sort(&mut vec); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/comb_sort.rs b/src/sorting/comb_sort.rs deleted file mode 100644 index d5a7705..0000000 --- a/src/sorting/comb_sort.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::vec::Vec; - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n * n) -/// Average Case Time Complexity == O(n * n / 2^p) # p = number of increments -/// Best Case Time Complexity == O(n log n) -/// Space Complexity == O(1) -/// ``` -#[allow(dead_code)] -pub fn comb_sort(vec: &mut Vec) { - const GAP_SHRINK_FACTOR: f64 = 1.3; - let mut gap: f64 = vec.len() as f64; - let mut sorted: bool = false; - - while sorted == false { - gap = f64::from(gap / GAP_SHRINK_FACTOR).floor(); - - if gap <= 1.0 { - sorted = true; - gap = 1.0; - } - - let mut i = 0; - while (i as f64 + gap) < vec.len() as f64 { - if vec[i] > vec[i + gap as usize] { - vec.swap(i, i + gap as usize); - sorted = false; - } - - i += 1; - } - } -} - - -#[cfg(test)] -mod tests { - use super::comb_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - comb_sort(&mut vec); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - comb_sort(&mut vec); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - comb_sort(&mut vec); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/concatenated_sort.rs b/src/sorting/concatenated_sort.rs deleted file mode 100644 index de6fc6c..0000000 --- a/src/sorting/concatenated_sort.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::vec::Vec; -use super::*; - - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy)] -pub enum SortingAlgorithms { - SelectionSort, - InsertionSort, - BubbleSort, - GnomeSort, - QuickSort, - MergeSort, - ShellSort, - HeapSort, - CombSort, -} - - -#[allow(dead_code)] -impl SortingAlgorithms { - const ALGORITHMS: [Self; 9] = [ - Self::SelectionSort, - Self::InsertionSort, - Self::BubbleSort, - Self::GnomeSort, - Self::QuickSort, - Self::MergeSort, - Self::ShellSort, - Self::HeapSort, - Self::CombSort, - ]; - - pub fn iterator() -> impl Iterator { - return Self::ALGORITHMS.iter().copied(); - } -} - - -#[allow(dead_code)] -pub fn concatenated_sort(vec: &mut Vec, algorithm: SortingAlgorithms) { - let high: usize = vec.len() - 1; - match algorithm { - SortingAlgorithms::SelectionSort => { selection_sort::selection_sort(vec); } - SortingAlgorithms::InsertionSort => { insertion_sort::insertion_sort(vec); } - SortingAlgorithms::BubbleSort => { bubble_sort::bubble_sort(vec); } - SortingAlgorithms::GnomeSort => { gnome_sort::gnome_sort(vec); } - SortingAlgorithms::QuickSort => { quick_sort::quick_sort(vec, 0, high as isize); } - SortingAlgorithms::MergeSort => { merge_sort::merge_sort(vec, 0, high); } - SortingAlgorithms::ShellSort => { shell_sort::shell_sort(vec); } - SortingAlgorithms::HeapSort => { heap_sort::heap_sort(vec); } - SortingAlgorithms::CombSort => { comb_sort::comb_sort(vec); } - } -} - - -#[cfg(test)] -mod tests { - use super::{SortingAlgorithms, concatenated_sort}; - - #[test] - pub fn sort_integer_vector() { - for alg in SortingAlgorithms::iterator() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - concatenated_sort(&mut vec, alg); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - } - - #[test] - pub fn sort_unsigned_vector() { - for alg in SortingAlgorithms::iterator() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - concatenated_sort(&mut vec, alg); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - } - - #[test] - pub fn sort_floating_vector() { - for alg in SortingAlgorithms::iterator() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - concatenated_sort(&mut vec, alg); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } - } -} \ No newline at end of file diff --git a/src/sorting/gnome_sort.rs b/src/sorting/gnome_sort.rs deleted file mode 100644 index 9d52ca7..0000000 --- a/src/sorting/gnome_sort.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::vec::Vec; - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n * n) -/// Average Case Time Complexity == O(n * n) -/// Best Case Time Complexity == O(n) -/// Space Complexity == O(1) Auxiliary -/// ``` -#[allow(dead_code)] -pub fn gnome_sort(vec: &mut Vec) { - for p in 1 .. vec.len() { - let mut position: usize = p; - - while position > 0 && vec[position - 1] > vec[position] { - vec.swap(position - 1, position); - position -= 1; - } - } -} - - -#[cfg(test)] -mod tests { - use super::gnome_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - gnome_sort(&mut vec); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - gnome_sort(&mut vec); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - gnome_sort(&mut vec); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/heap_sort.rs b/src/sorting/heap_sort.rs deleted file mode 100644 index 853c671..0000000 --- a/src/sorting/heap_sort.rs +++ /dev/null @@ -1,93 +0,0 @@ -/* Based around: https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/heap_sort.rs */ -use std::vec::Vec; - - -/// Move the element at `root` down until `slice` is a max heap again. -#[allow(dead_code)] -fn move_down(slice: &mut [T], mut root: usize) { - let last: usize = slice.len() - 1; - - loop { - let left: usize = 2 * root + 1; - if left > last { - break; - } - - let right: usize = left + 1; - let max: usize; - - if right <= last && slice[right] > slice[left] { - max = right; - } else { - max = left; - } - - if slice[max] > slice[root] { - slice.swap(root, max); - } - - root = max; - } -} - - -/// Creates a heap within the given vector. -#[allow(dead_code)] -fn create_heap(vec: &mut Vec) { - let last_parent: usize = (vec.len() - 2) / 2; - - for i in (0 ..=last_parent).rev() { - move_down(vec.as_mut_slice(), i); - } -} - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n log n) -/// Average Case Time Complexity == O(n log n) -/// Best Case Time Complexity == O(n) -/// Space Complexity == O(n) Total, O(1) Auxiliary -/// ``` -#[allow(dead_code)] -pub fn heap_sort(vec: &mut Vec) { - let vec_len: usize = vec.len(); - - if vec_len <= 1 { - return; - } - - create_heap(vec); - - for end in (1 .. vec_len).rev() { - vec.swap(0, end); - move_down(&mut vec[..end], 0); - } -} - - -#[cfg(test)] -mod tests { - use super::heap_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - heap_sort(&mut vec); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - heap_sort(&mut vec); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - heap_sort(&mut vec); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/insertion_sort.rs b/src/sorting/insertion_sort.rs deleted file mode 100644 index 57533db..0000000 --- a/src/sorting/insertion_sort.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::vec::Vec; - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n * n) -/// Average Case Time Complexity == O(n * n) -/// Best Case Time Complexity == O(n) -/// Space Complexity == O(n) Total, O(1) Auxiliary -/// ``` -#[allow(dead_code)] -pub fn insertion_sort(vec: &mut Vec) { - for i in 1 .. vec.len() { - let mut j: usize = i; - - while j > 0 && vec[j] < vec[j - 1] { - vec.swap(j - 1, j); - j -= 1; - } - } -} - - -#[cfg(test)] -mod tests { - use super::insertion_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - insertion_sort(&mut vec); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - insertion_sort(&mut vec); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - insertion_sort(&mut vec); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/merge_sort.rs b/src/sorting/merge_sort.rs deleted file mode 100644 index eab0601..0000000 --- a/src/sorting/merge_sort.rs +++ /dev/null @@ -1,95 +0,0 @@ -/* Based on: https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/merge_sort.rs */ -use std::vec::Vec; - - -/// Deals with merging and comparison aspect of the `merge_sort` algorithm. -#[allow(dead_code)] -fn merge(left: usize, middle: usize, right: usize, vec: &mut Vec) { - /* Temporay vectors for each half in `vec` */ - let (mut left_vec, mut right_vec) = (Vec::new(), Vec::new()); - - for v in vec.iter().take(middle + 1).skip(left) { - left_vec.push(*v); - } - - for v in vec.iter().take(right + 1).skip(middle + 1) { - right_vec.push(*v); - } - - let (left_len, right_len) = (left_vec.len(), right_vec.len()); - - /* Track positions while merging */ - let (mut l, mut r, mut v) = (0, 0, left); - - /* Pick smaller elements one by one from both halves */ - while l < left_len && r < right_len { - if left_vec[l] < right_vec[r] { - vec[v] = left_vec[l]; - l += 1; - } else { - vec[v] = right_vec[r]; - r += 1 - } - - v += 1; - } - - /* Finish up putting away all elements in left half */ - while l < left_len { - vec[v] = left_vec[l]; - l += 1; - v += 1; - } - - /* Finish up putting away all elements in right half */ - while r < right_len { - vec[v] = right_vec[r]; - r += 1; - v += 1; - } -} - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n log n) -/// Average Case Time Complexity == O(n log n) -/// Best Case Time Complexity == O(n log n) -/// Space Complexity == O(n) -/// ``` -#[allow(dead_code)] -pub fn merge_sort(vec: &mut Vec, left: usize, right: usize) { - if left < right { - let middle: usize = left + (right - left) / 2; - merge_sort(vec, left, middle); - merge_sort(vec, middle + 1, right); - merge(left, middle, right, vec); - } -} - - -#[cfg(test)] -mod tests { - use super::merge_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - merge_sort(&mut vec, 0, 6); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - merge_sort(&mut vec, 0, 6); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - merge_sort(&mut vec, 0, 6); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/mod.rs b/src/sorting/mod.rs deleted file mode 100644 index 10130b2..0000000 --- a/src/sorting/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub(crate) mod concatenated_sort; - -pub(crate) mod selection_sort; -pub(crate) mod insertion_sort; -pub(crate) mod bubble_sort; -pub(crate) mod gnome_sort; -pub(crate) mod quick_sort; -pub(crate) mod merge_sort; -pub(crate) mod shell_sort; -pub(crate) mod heap_sort; -pub(crate) mod comb_sort; \ No newline at end of file diff --git a/src/sorting/quick_sort.rs b/src/sorting/quick_sort.rs deleted file mode 100644 index 5ed547b..0000000 --- a/src/sorting/quick_sort.rs +++ /dev/null @@ -1,74 +0,0 @@ -use std::vec::Vec; - - -/// Handles the sorting aspect of `quick_sort`. -#[allow(dead_code)] -fn partition(vec: &mut Vec, left: isize, right: isize) -> isize { - let (mut i, mut j) = (left - 1, right); - let pivot: usize = right as usize; - - loop { - i += 1; - while vec[i as usize] < vec[pivot] { - i += 1; - } - - j -= 1; - while j >= 0 && vec[j as usize] > vec[pivot] { - j -= 1; - } - - if i >= j { - break; - } else { - vec.swap(i as usize, j as usize); - } - } - - vec.swap(i as usize, pivot); - return i; -} - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n * n) -/// Average Case Time Complexity == O(n log n) -/// Best Case Time Complexity == O(n log n) -/// Space Complexity == O(n) -/// ``` -#[allow(dead_code)] -pub fn quick_sort(vec: &mut Vec, left: isize, right: isize) { - if left < right { - let part: isize = partition(vec, left, right); - quick_sort(vec, left, part - 1); - quick_sort(vec, part + 1, right); - } -} - - -#[cfg(test)] -mod tests { - use super::quick_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - quick_sort(&mut vec, 0, 6); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - quick_sort(&mut vec, 0, 6); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - quick_sort(&mut vec, 0, 6); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/selection_sort.rs b/src/sorting/selection_sort.rs deleted file mode 100644 index e8f4022..0000000 --- a/src/sorting/selection_sort.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::vec::Vec; - - -/// ## Complexities: -/// ```py -/// Worst Case Time Complexity == O(n * n) -/// Average Case Time Complexity == O(n * n) -/// Best Case Time Complexity == O(n * n) -/// Space Complexity == O(1) -/// ``` -#[allow(dead_code)] -pub fn selection_sort(vec: &mut Vec) { - let vec_len: usize = vec.len(); - - for i in 0 .. vec_len { - let mut current_minimum_index: usize = i; - - for j in i + 1 .. vec_len { - if vec[j] < vec[current_minimum_index] { - current_minimum_index = j; - } - } - - vec.swap(i, current_minimum_index); - } -} - - -#[cfg(test)] -mod tests { - use super::selection_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - selection_sort(&mut vec); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - selection_sort(&mut vec); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - selection_sort(&mut vec); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file diff --git a/src/sorting/shell_sort.rs b/src/sorting/shell_sort.rs deleted file mode 100644 index 188b7d8..0000000 --- a/src/sorting/shell_sort.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::vec::Vec; - - -/// ## Complexities: -/// ```py -/// # Time Complexities strongly depend on the gap sequence. -/// Worst Case Time Complexity == O(?) -/// Average Case Time Complexity == O(?) -/// Best Case Time Complexity == O(?) -/// Space Complexity == O(n) Total, O(1) Auxiliary -/// ``` -#[allow(dead_code)] -pub fn shell_sort(vec: &mut Vec) { - const GAP_SEQUENCE: [usize; 8] = [ 701, 301, 132, 57, 23, 10, 4, 1 ]; - - for gap in GAP_SEQUENCE { - for i in gap .. vec.len() { - let temp: T = vec[i]; - let mut j = i; - - while j >= gap && vec[j - gap] > temp { - vec[j] = vec[j - gap]; - j -= gap; - } - - vec[j] = temp; - } - } -} - - -#[cfg(test)] -mod tests { - use super::shell_sort; - - #[test] - fn sort_integer_vector() { - let mut vec: Vec = vec![0, 3, 1, 5, 6, 8, 7]; - shell_sort(&mut vec); - assert_eq!(vec, vec![0, 1, 3, 5, 6, 7, 8]); - } - - #[test] - fn sort_unsigned_vector() { - let mut vec: Vec = vec![4, 3, 2, 6, 3, 1, 9]; - shell_sort(&mut vec); - assert_eq!(vec, vec![1, 2, 3, 3, 4, 6, 9]); - } - - #[test] - fn sort_floating_vector() { - let mut vec: Vec = vec![0.5, 1.32, 1.11, 5.72, 4.20, 1.337, 8.04]; - shell_sort(&mut vec); - assert_eq!(vec, vec![0.5, 1.11, 1.32, 1.337, 4.20, 5.72, 8.04]); - } -} \ No newline at end of file From 738e83bfd533db0672f77cf672c517a0c9b65d89 Mon Sep 17 00:00:00 2001 From: c1m50c <58411864+c1m50c@users.noreply.github.com> Date: Fri, 10 Jun 2022 19:57:34 -0500 Subject: [PATCH 2/4] Basic Searching Algorithms --- src/lib.rs | 3 +++ src/search/binary.rs | 31 +++++++++++++++++++++++++++++++ src/search/linear.rs | 23 +++++++++++++++++++++++ src/search/mod.rs | 9 +++++++++ src/search/tests.rs | 17 +++++++++++++++++ 5 files changed, 83 insertions(+) create mode 100644 src/search/binary.rs create mode 100644 src/search/linear.rs create mode 100644 src/search/mod.rs create mode 100644 src/search/tests.rs diff --git a/src/lib.rs b/src/lib.rs index c35a601..cfe2109 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +pub mod search; + + #[cfg(test)] mod tests { diff --git a/src/search/binary.rs b/src/search/binary.rs new file mode 100644 index 0000000..7b8d861 --- /dev/null +++ b/src/search/binary.rs @@ -0,0 +1,31 @@ +use core::cmp::{PartialEq, PartialOrd}; +use core::option::Option; + + +/// Searchs through the `slice` to retrieve the index of `finding`. +/// +/// # Example +/// ```rust +/// use rust_algorithms::search::binary_search; +/// +/// let slice = &[1, 2, 3, 4, 5]; +/// let found = binary_search(slice, 3).unwrap(); +/// assert_eq!(found, 2); +/// ``` +pub fn binary_search(slice: &[T], finding: T) -> Option { + let (mut left, mut right) = (0, slice.len()); + + while left < right { + let middle = left + (right - left) / 2; + + if finding == slice[middle] { + return Some(middle); + } else if finding < slice[middle] { + right = middle; + } else { + left = middle + 1; + } + } + + return None; +} \ No newline at end of file diff --git a/src/search/linear.rs b/src/search/linear.rs new file mode 100644 index 0000000..d4bbc2a --- /dev/null +++ b/src/search/linear.rs @@ -0,0 +1,23 @@ +use core::cmp::PartialEq; +use core::option::Option; + + +/// Searchs through the `slice` to retrieve the index of `finding`. +/// +/// # Example +/// ```rust +/// use rust_algorithms::search::linear_search; +/// +/// let slice = &[1, 2, 3, 4, 5]; +/// let found = linear_search(slice, 3).unwrap(); +/// assert_eq!(found, 2); +/// ``` +pub fn linear_search(slice: &[T], finding: T) -> Option { + for (idx, ele) in slice.iter().enumerate() { + if ele == &finding { + return Some(idx); + } + } + + return None; +} \ No newline at end of file diff --git a/src/search/mod.rs b/src/search/mod.rs new file mode 100644 index 0000000..ed47b5a --- /dev/null +++ b/src/search/mod.rs @@ -0,0 +1,9 @@ +pub mod linear; +pub use linear::linear_search; + +pub mod binary; +pub use binary::binary_search; + + +#[cfg(test)] +mod tests; \ No newline at end of file diff --git a/src/search/tests.rs b/src/search/tests.rs new file mode 100644 index 0000000..c1af735 --- /dev/null +++ b/src/search/tests.rs @@ -0,0 +1,17 @@ +macro_rules! impl_tests { + ($name: ident, $function: expr) => { + #[test] + fn $name() { + let slice = &[1, 2, 3, 4, 5]; + let found = $function(slice, 3).unwrap(); + assert_eq!(found, 2); + } + }; +} + + +use super::linear_search as linear; +impl_tests!(linear_search, linear); + +use super::binary_search as binary; +impl_tests!(binary_search, binary); \ No newline at end of file From 73bc7dbef4433bdc1a551a106effce8c509e32a3 Mon Sep 17 00:00:00 2001 From: c1m50c <58411864+c1m50c@users.noreply.github.com> Date: Sun, 12 Jun 2022 18:25:05 -0500 Subject: [PATCH 3/4] Start on Sorting Algorithms --- src/lib.rs | 5 ++--- src/sorting/insertion.rs | 27 +++++++++++++++++++++++++++ src/sorting/mod.rs | 6 ++++++ src/sorting/tests.rs | 17 +++++++++++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/sorting/insertion.rs create mode 100644 src/sorting/mod.rs create mode 100644 src/sorting/tests.rs diff --git a/src/lib.rs b/src/lib.rs index cfe2109..d363772 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ +pub mod sorting; pub mod search; #[cfg(test)] -mod tests { - -} \ No newline at end of file +mod tests { } \ No newline at end of file diff --git a/src/sorting/insertion.rs b/src/sorting/insertion.rs new file mode 100644 index 0000000..0c4a4e8 --- /dev/null +++ b/src/sorting/insertion.rs @@ -0,0 +1,27 @@ +use core::cmp::PartialOrd; + + +/// Sorts the `slice` from least to greatest. +/// +/// # Example +/// ```rust +/// use rust_algorithms::sorting::insertion_sort; +/// +/// let slice = &mut [4, 1, 2, 4, 0, 9, 8]; +/// insertion_sort(slice); +/// +/// // Ensure the slice is properly sorted +/// for i in 1 .. slice.len() { +/// assert!(slice[i] >= slice[i - 1]); +/// } +/// ``` +pub fn insertion_sort(slice: &mut [T]) { + for i in 1 .. slice.len() { + let mut j = i; + + while j > 0 && slice[j] < slice[j - 1] { + slice.swap(j - 1, j); + j -= 1; + } + } +} \ No newline at end of file diff --git a/src/sorting/mod.rs b/src/sorting/mod.rs new file mode 100644 index 0000000..29ab3c6 --- /dev/null +++ b/src/sorting/mod.rs @@ -0,0 +1,6 @@ +pub mod insertion; +pub use insertion::insertion_sort; + + +#[cfg(test)] +mod tests; \ No newline at end of file diff --git a/src/sorting/tests.rs b/src/sorting/tests.rs new file mode 100644 index 0000000..01ff6d0 --- /dev/null +++ b/src/sorting/tests.rs @@ -0,0 +1,17 @@ +macro_rules! impl_tests { + ($name: ident, $function: expr) => { + #[test] + fn $name() { + let slice = &mut [3, 2, 14, 4, 1, 0, 9, 2, 1, 4, 5]; + $function(slice); + + for i in 1 .. slice.len() { + assert!(slice[i] >= slice[i - 1]); + } + } + }; +} + + +use super::insertion_sort as insertion; +impl_tests!(insertion_sort, insertion); \ No newline at end of file From 738ea0674c60e4c95ed82ae4818142b3f56a63f0 Mon Sep 17 00:00:00 2001 From: c1m50c <58411864+c1m50c@users.noreply.github.com> Date: Sun, 12 Jun 2022 18:26:47 -0500 Subject: [PATCH 4/4] Update Build Workflow --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b86831c..e3c5ef3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: Build on: push: - branches: [ main ] + branches: [ v2.0 ] pull_request: - branches: [ main ] + branches: [ v2.0 ] env: CARGO_TERM_COLOR: always