├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ ├── clippy.yml │ └── fmt.yml ├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── clippy.toml ├── rustfmt.toml └── src ├── lib.rs ├── numerics.rs ├── numerics ├── factorial.rs ├── fibonacci.rs ├── prime.rs └── primorial.rs ├── pattern.rs ├── search.rs └── sort.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # custom: "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RFC4CKATPS4US&source=url" 2 | custom: ["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RFC4CKATPS4US&source=url", "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FBXMZU2NLJPUW&source=url", "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=2MQZLTXACP964&source=url"] 3 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build-linux: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest] 11 | rust: [1.38.0, stable, beta, nightly] 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: ${{ matrix.rust }} 17 | override: true 18 | profile: minimal 19 | components: clippy 20 | - name: Check compilation 21 | run: cargo check --verbose 22 | - name: Run tests 23 | run: cargo test --verbose 24 | 25 | build-macos: 26 | runs-on: ${{ matrix.os }} 27 | strategy: 28 | matrix: 29 | os: [macOS-latest] 30 | rust: [1.38.0, stable, beta, nightly] 31 | steps: 32 | - uses: actions/checkout@v2 33 | - uses: actions-rs/toolchain@v1 34 | with: 35 | toolchain: ${{ matrix.rust }} 36 | override: true 37 | profile: minimal 38 | components: clippy 39 | - name: Check compilation 40 | run: cargo check --verbose 41 | - name: Run tests 42 | run: cargo test --verbose 43 | 44 | build-windows: 45 | runs-on: ${{ matrix.os }} 46 | strategy: 47 | matrix: 48 | os: [windows-latest] 49 | rust: [1.38.0, stable, beta, nightly] 50 | steps: 51 | - uses: actions/checkout@v2 52 | - uses: actions-rs/toolchain@v1 53 | with: 54 | toolchain: ${{ matrix.rust }} 55 | override: true 56 | profile: minimal 57 | components: clippy 58 | - name: Check compilation 59 | run: cargo check --verbose 60 | - name: Run tests 61 | run: cargo test --verbose 62 | -------------------------------------------------------------------------------- /.github/workflows/clippy.yml: -------------------------------------------------------------------------------- 1 | name: Clippy check 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | clippy_check: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions-rs/toolchain@v1 11 | with: 12 | toolchain: nightly 13 | components: clippy 14 | override: true 15 | - uses: actions-rs/clippy-check@v1 16 | with: 17 | token: ${{ secrets.GITHUB_TOKEN }} 18 | args: --all-features 19 | -------------------------------------------------------------------------------- /.github/workflows/fmt.yml: -------------------------------------------------------------------------------- 1 | name: Format test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | os: [ubuntu-latest] 11 | rust: [nightly] 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: ${{ matrix.rust }} 17 | override: true 18 | profile: minimal 19 | components: rustfmt 20 | - name: Check Format 21 | run: cargo fmt -- --check 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | matrix: 7 | allow_failures: 8 | - rust: nightly 9 | fast_finish: true 10 | cache: cargo 11 | script: 12 | - cargo build --verbose --all 13 | - cargo test --verbose --all 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "algos" 3 | version = "0.4.0" 4 | authors = ["GrayJack "] 5 | description = "A collection of algorithms in Rust" 6 | repository = "https://github.com/GrayJack/algos" 7 | homepage = "https://crates.io/crates/algos" 8 | documentation = "https://docs.rs/algos" 9 | license-file = "LICENSE" 10 | readme = "README.md" 11 | keywords = ["algorithm", "sort", "search", "pattern", "series"] 12 | exclude = ["/.travis.yml", "/.github/*"] 13 | edition = "2018" 14 | 15 | 16 | [dependencies] 17 | const_fn = "0.4.3" 18 | rand = "0.8.3" 19 | num = { version="0.4.0", optional=true } 20 | 21 | [features] 22 | default = ["big_num"] 23 | big_num = ["num"] 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, GrayJack 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1.Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2.Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3.Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **Algos** 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/algos.svg)](https://crates.io/crates/algos) 4 | [![Documentation](https://docs.rs/algos/badge.svg)](https://docs.rs/algos) 5 | [![Build Status](https://github.com/GrayJack/algos/workflows/Build/badge.svg)](https://github.com/GrayJack/algos/actions) 6 | [![dependency status](https://deps.rs/repo/github/GrayJack/algos/status.svg)](https://deps.rs/repo/github/GrayJack/algos) 7 | [![GitHub license](https://img.shields.io/github/license/GrayJack/algos.svg)](https://github.com/GrayJack/algos/blob/master/LICENSE) 8 | 9 | A Rust library with a collection of algorithms. Mostly intended as learning exercises for Rust. 10 | 11 | Only sort, search and pattern matching algorithms for now. 12 | It is planned to add graph algorithms as well. 13 | 14 | ## **Usage** 15 | 16 | Add this to your `Cargo.toml`: 17 | 18 | ```toml 19 | [dependencies] 20 | algos = "0.3" 21 | ``` 22 | 23 | and this to your crate root if on 2015 edition: 24 | 25 | ```rust 26 | extern crate algos; 27 | ``` 28 | 29 | ### Sorts Algorithms 30 | Add this to your crate root: 31 | 32 | ```rust 33 | use algos::sort; 34 | ``` 35 | 36 | and create an array and use like this: 37 | 38 | ```rust 39 | fn fn main() { 40 | let mut v = [2, 3, 1, 9, 8, 4]; 41 | // Crescent sorting 42 | sort::heap(&mut v, &|a,b| ab. 44 | } 45 | ``` 46 | 47 | It can also work in an array of Strings, sorting by the length of the string: 48 | 49 | ```rust 50 | fn main() { 51 | let mut v = ["bc", "a", "def", "klmno", "ghij", "pqrstu"]; 52 | // Crescent sorting 53 | sort::merge(&mut v, &|a,b| a.len() 88 | } 89 | ``` 90 | 91 | ## **Implemented** 92 | ### Sorts 93 | - [X] Selection Sort 94 | - [X] Bubble Sort 95 | - [X] Cocktail Sort 96 | - [X] Insertion Sort 97 | - [X] Merge Sort 98 | - [X] Quick Sort 99 | - [X] Heap Sort 100 | 101 | ### Searches 102 | - [X] Linear Search 103 | - [X] Binary Search 104 | - [X] Exponential Search 105 | - [X] Fibonacci Search 106 | 107 | ### String Matching 108 | - [X] Bruteforce 109 | - [X] Karp-Rabin 110 | - [ ] Boyer-Moore 111 | - [X] Horspool 112 | - [X] Quick 113 | - [ ] Two-Way 114 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | cyclomatic-complexity-threshold = 30 2 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # license_template_path = "Copyright {\\y} Eric Shimizu Karbstein." 2 | binop_separator = "Front" 3 | blank_lines_lower_bound = 0 4 | blank_lines_upper_bound = 3 5 | brace_style = "SameLineWhere" 6 | color = "Auto" 7 | combine_control_expr = true 8 | comment_width = 90 9 | condense_wildcard_suffixes = true 10 | disable_all_formatting = false 11 | edition = "2018" 12 | empty_item_single_line = true 13 | enum_discrim_align_threshold = 6 14 | fn_args_layout = "Compressed" 15 | fn_single_line = true 16 | force_explicit_abi = true 17 | force_multiline_blocks = false 18 | format_code_in_doc_comments = true 19 | format_macro_bodies = true 20 | format_macro_matchers = true 21 | format_strings = true 22 | hard_tabs = false 23 | ignore = [] 24 | imports_indent = "Block" 25 | imports_layout = "Mixed" 26 | indent_style = "Block" 27 | inline_attribute_width = 0 28 | make_backup = true 29 | match_arm_blocks = true 30 | match_block_trailing_comma = true 31 | max_width = 100 32 | merge_derives = true 33 | merge_imports = true 34 | newline_style = "Auto" 35 | normalize_comments = true 36 | normalize_doc_attributes = true 37 | overflow_delimited_expr = true 38 | remove_nested_parens = true 39 | reorder_impl_items = true 40 | reorder_imports = true 41 | reorder_modules = true 42 | skip_children = false 43 | space_after_colon = true 44 | space_before_colon = false 45 | spaces_around_ranges = false 46 | struct_field_align_threshold = 6 47 | struct_lit_single_line = true 48 | tab_spaces = 4 49 | trailing_comma = "Vertical" 50 | trailing_semicolon = true 51 | type_punctuation_density = "Wide" 52 | unstable_features = true 53 | use_field_init_shorthand = true 54 | use_small_heuristics = "Max" 55 | use_try_shorthand = true 56 | version = "Two" 57 | where_single_line = true 58 | wrap_comments = true 59 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate is a collection of algorithms, mostly intended as learning exercise. 2 | //! 3 | //! ## What is implemented: 4 | //! - Several sort algorithms 5 | //! - Some search algorithms 6 | //! - Some pattern algorithms 7 | //! - Some numeric sequence algorithms 8 | //! 9 | //! ## Features 10 | //! This crate have a feature called `big_num` and it is active by default. 11 | //! 12 | //! In case your needs don't require using big numbers and you want to reduce the crate 13 | //! numbers to be compiled and the compile time, you can disactivate the default features. 14 | 15 | pub mod numerics; 16 | pub mod pattern; 17 | pub mod search; 18 | pub mod sort; 19 | -------------------------------------------------------------------------------- /src/numerics.rs: -------------------------------------------------------------------------------- 1 | //! Module for numeric algorithms ans some iterators 2 | 3 | #[cfg(feature = "big_num")] 4 | pub mod factorial; 5 | pub mod fibonacci; 6 | pub mod prime; 7 | pub mod primorial; 8 | 9 | #[cfg(feature = "big_num")] 10 | pub use factorial::BigFactorial; 11 | #[cfg(feature = "big_num")] 12 | pub use fibonacci::BigFib; 13 | #[cfg(feature = "big_num")] 14 | pub use primorial::BigPrimorial; 15 | 16 | pub use fibonacci::Fib; 17 | pub use prime::IsPrime; 18 | -------------------------------------------------------------------------------- /src/numerics/factorial.rs: -------------------------------------------------------------------------------- 1 | //! Factorial module. 2 | //! 3 | //! Since calculate fatorial is simple enought, we will only implement the iterator that 4 | //! keeps giving a ever increasing number. 5 | //! 6 | //! _Only implement for big numbers cause the number grows big super fast._ 7 | 8 | use num::{BigUint, One}; 9 | 10 | /// Factorial iterator using big numbers. 11 | /// 12 | /// # Example 13 | /// Print the 100 first factorial numbers. 14 | /// 15 | /// ```rust 16 | /// # use algos::numerics::BigFactorial; 17 | /// # fn main() { 18 | /// BigFactorial::new().enumerate().take(100).for_each(|(i, v)| println!("{}!: {}", i, v)); 19 | /// # } 20 | /// ``` 21 | #[derive(Debug, Clone)] 22 | pub struct BigFactorial { 23 | /// Index we are in. 24 | index: u128, 25 | 26 | /// Last value calculated. 27 | /// 28 | /// We can do it without this value, but using it, we increase memory consuption, but 29 | /// the iterator became faster. 30 | last: BigUint, 31 | } 32 | 33 | impl BigFactorial { 34 | /// Creates a new iterator starting at the first number of the sequence. 35 | pub fn new() -> Self { BigFactorial { last: BigUint::one(), index: 0 } } 36 | 37 | /// Create a new iterator with the first factorial number beeing the `nth` factorial 38 | /// number. 39 | pub fn at(nth: impl Into) -> Self { 40 | let index = nth.into(); 41 | BigFactorial { index, last: (1..index).map(BigUint::from).product() } 42 | } 43 | } 44 | 45 | impl Iterator for BigFactorial { 46 | type Item = BigUint; 47 | 48 | fn next(&mut self) -> Option { 49 | if self.index == 0 { 50 | self.index += 1; 51 | Some(BigUint::one()) 52 | } else { 53 | self.last *= self.index; 54 | self.index += 1; 55 | Some(self.last.clone()) 56 | } 57 | } 58 | } 59 | 60 | #[cfg(test)] 61 | mod tests { 62 | use super::*; 63 | 64 | #[test] 65 | fn iterator_bignum_test() { 66 | let sure: Vec<_> = vec![1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362_880, 3_628_800] 67 | .iter() 68 | .map(|&x| BigUint::from(x as u64)) 69 | .collect(); 70 | 71 | let test: Vec<_> = BigFactorial::new().take(sure.len()).collect(); 72 | assert_eq!(sure, test); 73 | } 74 | 75 | #[test] 76 | fn iterator_bignum_at_test() { 77 | let sure: Vec<_> = vec![120, 720, 5040, 40320, 362_880, 3_628_800] 78 | .iter() 79 | .map(|&x| BigUint::from(x as u64)) 80 | .collect(); 81 | 82 | let test: Vec<_> = BigFactorial::at(5u32).take(sure.len()).collect(); 83 | assert_eq!(sure, test); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/numerics/fibonacci.rs: -------------------------------------------------------------------------------- 1 | //! Fibonacci sequence algorithms. 2 | use std::{convert::TryFrom, fmt::Debug}; 3 | 4 | #[cfg(feature = "big_num")] 5 | use num::{pow::Pow, rational::BigRational, BigUint, One, Zero}; 6 | 7 | use const_fn::const_fn; 8 | 9 | const GOLDEN_RATIO: f64 = 1.618033988749894848204586834365638117720309179805762862135; 10 | 11 | 12 | /// A Iterator for the fibonacci sequence. 13 | /// 14 | /// # Warning 15 | /// Note that due to using `u128` primitive, you cannot take more than the first 186 16 | /// fibonacci numbers. If you need to go past that, use [`BigFib`] iterator. 17 | /// 18 | /// [`BigFib`]: ./struct.BigFib.html 19 | /// 20 | /// # Example 21 | /// Print the 100 first fibonacci numbers. 22 | /// 23 | /// ```rust 24 | /// # use algos::numerics::Fib; 25 | /// # fn main() { 26 | /// Fib::new().enumerate().take(100).for_each(|(i, v)| println!("Fib {}: {}", i, v)); 27 | /// # } 28 | /// ``` 29 | #[derive(Debug, Clone, Default)] 30 | pub struct Fib { 31 | val: (u128, u128), 32 | } 33 | 34 | impl Fib { 35 | /// Create a new iterator starting at the first fibonacci number, zero. 36 | pub fn new() -> Self { Self { val: (0, 1) } } 37 | 38 | /// Create a new iterator with the first fibonacci number beeing the `nth` fibonacci 39 | /// number. 40 | pub fn at(nth: impl Into) -> Self { Self { val: _fib(nth.into()) } } 41 | } 42 | 43 | impl Iterator for Fib { 44 | type Item = u128; 45 | 46 | fn next(&mut self) -> Option { 47 | let next = self.val.0; 48 | self.val = (self.val.1, self.val.0 + self.val.1); 49 | Some(next) 50 | } 51 | } 52 | 53 | /// A Iterator for the fibonacci sequence using big numbers. 54 | /// 55 | /// # Example 56 | /// Print the 100 first fibonacci numbers. 57 | /// 58 | /// ```rust 59 | /// # use algos::numerics::BigFib; 60 | /// # fn main() { 61 | /// BigFib::new().enumerate().take(100).for_each(|(i, v)| println!("Fib {}: {}", i, v)); 62 | /// # } 63 | /// ``` 64 | #[cfg(feature = "big_num")] 65 | #[derive(Debug, Clone, Default)] 66 | pub struct BigFib { 67 | val: (BigUint, BigUint), 68 | } 69 | 70 | #[cfg(feature = "big_num")] 71 | impl BigFib { 72 | /// Create a new iterator starting at the first fibonacci number, zero. 73 | pub fn new() -> Self { Self { val: (BigUint::zero(), BigUint::one()) } } 74 | 75 | /// Create a new iterator with the first fibonacci number beeing the `nth` fibonacci 76 | /// number. 77 | pub fn at(nth: impl Into) -> Self { Self { val: _big_fib(&nth.into()) } } 78 | } 79 | 80 | #[cfg(feature = "big_num")] 81 | impl Iterator for BigFib { 82 | type Item = BigUint; 83 | 84 | fn next(&mut self) -> Option { 85 | let next = self.val.0.clone(); 86 | self.val = (self.val.1.clone(), &self.val.0 + &self.val.1); 87 | Some(next) 88 | } 89 | } 90 | 91 | /// Calculate the `nth` fibonacci number using the classic recursive strategy. 92 | /// 93 | /// | Case | Time complexity | Space complexity | 94 | /// |:----------|:---------------:|:----------------:| 95 | /// | Best: | Ω(n²) | Ω(n) | 96 | /// | Avrg: | Θ(n²) | Θ(n) | 97 | /// | Worst: | O(n²) | O(n) | 98 | /// 99 | /// # Panics 100 | /// This function may panic on debug builds if the internal type (u128) and happens a 101 | /// operation overflow. 102 | #[const_fn("1.46")] 103 | pub const fn recursive_fibonacci(nth: u128) -> u128 { 104 | match nth { 105 | 0 => 0, 106 | 1 | 2 => 1, 107 | _ => recursive_fibonacci(nth - 1) + recursive_fibonacci(nth - 2), 108 | } 109 | } 110 | 111 | /// Calculate the `nth` fibonacci number using the dynamic programming strategy. 112 | /// 113 | /// | Case | Time complexity | Space complexity | 114 | /// |:----------|:---------------:|:----------------:| 115 | /// | Best: | Ω(n) | Ω(1) | 116 | /// | Avrg: | Θ(n) | Θ(1) | 117 | /// | Worst: | O(n) | O(1) | 118 | /// 119 | /// # Panics 120 | /// This function may panic on debug builds if the internal type (u128) and happens a 121 | /// operation overflow. 122 | #[const_fn("1.46")] 123 | pub const fn dynamic_fibonacci(nth: u128) -> u128 { 124 | let (mut a, mut b) = (0, 1); 125 | 126 | let mut iter = 0; 127 | while iter < nth { 128 | let c = a + b; 129 | a = b; 130 | b = c; 131 | 132 | iter += 1; 133 | } 134 | 135 | a 136 | } 137 | 138 | /// Calculate the `nth` fibonacci number using the fast doubling algorithm. 139 | /// 140 | /// | Case | Time complexity | Space complexity | 141 | /// |:----------|:---------------:|:----------------:| 142 | /// | Best: | Ω(log(n)) | Ω(1) | 143 | /// | Avrg: | Θ(log(n)) | Θ(1) | 144 | /// | Worst: | O(log(n)) | O(1) | 145 | /// 146 | /// # Panics 147 | /// This function may panic on debug builds if the internal type (u128) and happens a 148 | /// operation overflow. 149 | #[const_fn("1.46")] 150 | pub const fn fast_doubling_fibonacci(nth: u128) -> u128 { _fib(nth).0 } 151 | 152 | /// Calculate the fibonacci number at index `nth` using the fast doubling strategy 153 | /// (inner). 154 | #[const_fn("1.46")] 155 | const fn _fib(nth: u128) -> (u128, u128) { 156 | if nth == 0 { 157 | (0, 1) 158 | } else { 159 | let (a, b) = _fib(nth / 2); 160 | let c = a * (b * 2 - a); 161 | let d = a * a + b * b; 162 | 163 | if nth % 2 == 0 { (c, d) } else { (d, c + d) } 164 | } 165 | } 166 | 167 | /// Calculate the `nth` fibonacci number using the binet formulae. 168 | /// 169 | /// This is a aproximation method and will stop working for `nth >= 76` 170 | /// 171 | /// | Case | Time complexity | Space complexity | 172 | /// |:----------|:---------------:|:----------------:| 173 | /// | Best: | Ω(log(n)) | Ω(1) | 174 | /// | Avrg: | Θ(log(n)) | Θ(1) | 175 | /// | Worst: | O(log(n)) | O(1) | 176 | /// 177 | /// # Panics 178 | /// This function may panic on debug builds if the internal type (u128) and happens a 179 | /// operation overflow. 180 | pub fn binet_fibonacci(nth: i32) -> u128 { 181 | ((GOLDEN_RATIO.pow(nth) - (-1.0 / GOLDEN_RATIO).pow(nth)) / 5.0f64.sqrt()).round() as u128 182 | } 183 | 184 | /// Calculate the `nth` fibonacci number using the fast doubling algorithm. 185 | /// 186 | /// | Case | Time complexity | Space complexity | 187 | /// |:----------|:---------------:|:----------------:| 188 | /// | Best: | Ω(log(n)) | Ω(1) | 189 | /// | Avrg: | Θ(log(n)) | Θ(1) | 190 | /// | Worst: | O(log(n)) | O(1) | 191 | /// 192 | /// # Panics 193 | /// This function may panic if `BigUint` type run out of allocation memory. 194 | #[cfg(feature = "big_num")] 195 | pub fn big_fast_doubling_fibonacci(nth: impl Into) -> BigUint { _big_fib(&nth.into()).0 } 196 | 197 | /// Calculate the fibonacci number at index `nth` using the fast doubling strategy 198 | /// (inner). 199 | #[cfg(feature = "big_num")] 200 | fn _big_fib(nth: &BigUint) -> (BigUint, BigUint) { 201 | if *nth == BigUint::zero() { 202 | (BigUint::zero(), BigUint::one()) 203 | } else { 204 | let (a, b) = _big_fib(&(nth / 2u8)); 205 | let c = &a * (&b * 2u8 - &a); 206 | let d = &a * &a + &b * &b; 207 | 208 | if (nth % 2u8).is_zero() { (c, d) } else { (d.clone(), c + d) } 209 | } 210 | } 211 | 212 | /// Calculate the `nth` fibonacci number using the binet formulae. 213 | /// 214 | /// This is a aproximation method and will stop working for `nth >= 265` 215 | /// 216 | /// | Case | Time complexity | Space complexity | 217 | /// |:----------|:---------------:|:----------------:| 218 | /// | Best: | Ω(log(n)) | Ω(1) | 219 | /// | Avrg: | Θ(log(n)) | Θ(1) | 220 | /// | Worst: | O(log(n)) | O(1) | 221 | /// 222 | /// # Panics 223 | /// This function may panic if `BigUint` type run out of allocation memory. 224 | #[cfg(feature = "big_num")] 225 | pub fn big_binet_fibonacci(nth: impl Into) -> BigUint { 226 | let nth = nth.into(); 227 | if nth.is_zero() { 228 | nth 229 | } else { 230 | let gr = BigRational::new( 231 | 112016498943988617255084900949u128.into(), 232 | 69230003648151669220777340178u128.into(), 233 | ); 234 | let sqrt_five = BigRational::new( 235 | 77401497119912782644696230860u128.into(), 236 | 34615001824075834610388670089u128.into(), 237 | ); 238 | let minus_one = BigRational::new((-1).into(), 1.into()); 239 | let fib = ((gr.clone().pow(nth) - (minus_one / gr)) / sqrt_five).round().to_integer(); 240 | BigUint::try_from(fib).unwrap() 241 | } 242 | } 243 | 244 | #[cfg(test)] 245 | mod tests { 246 | use super::*; 247 | use num::BigUint; 248 | 249 | #[test] 250 | fn recursive_test() { 251 | let sure = vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]; 252 | let test: Vec<_> = (0..sure.len() as u128).map(recursive_fibonacci).collect(); 253 | assert_eq!(sure, test); 254 | } 255 | 256 | #[test] 257 | fn dynamic_test() { 258 | let sure = vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]; 259 | let test: Vec<_> = (0..sure.len() as u128).map(dynamic_fibonacci).collect(); 260 | assert_eq!(sure, test); 261 | } 262 | 263 | #[test] 264 | fn fast_doubling_test() { 265 | let sure = vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]; 266 | let test: Vec<_> = (0..sure.len() as u128).map(fast_doubling_fibonacci).collect(); 267 | assert_eq!(sure, test); 268 | } 269 | 270 | #[test] 271 | fn binet_test() { 272 | let sure = vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]; 273 | let test: Vec<_> = (0..sure.len() as i32).map(binet_fibonacci).collect(); 274 | assert_eq!(sure, test); 275 | } 276 | 277 | #[test] 278 | fn fast_doubling_bignum_test() { 279 | let sure: Vec<_> = 280 | vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597] 281 | .iter() 282 | .map(|&x| BigUint::from(x as u32)) 283 | .collect(); 284 | 285 | let test: Vec<_> = (0..sure.len() as u128).map(big_fast_doubling_fibonacci).collect(); 286 | assert_eq!(sure, test); 287 | } 288 | 289 | #[test] 290 | fn binet_bignum_test() { 291 | let sure: Vec<_> = 292 | vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597] 293 | .iter() 294 | .map(|&x| BigUint::from(x as u32)) 295 | .collect(); 296 | 297 | let test: Vec<_> = (0..sure.len() as u128).map(big_binet_fibonacci).collect(); 298 | assert_eq!(sure, test); 299 | } 300 | 301 | #[test] 302 | fn iterator_test() { 303 | let sure = vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597]; 304 | let test: Vec<_> = Fib::new().take(sure.len()).collect(); 305 | assert_eq!(sure, test); 306 | } 307 | 308 | #[test] 309 | fn iterator_bignum_test() { 310 | let sure: Vec<_> = 311 | vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597] 312 | .iter() 313 | .map(|&x| BigUint::from(x as u32)) 314 | .collect(); 315 | 316 | let test: Vec<_> = BigFib::new().take(sure.len()).collect(); 317 | assert_eq!(sure, test); 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /src/numerics/prime.rs: -------------------------------------------------------------------------------- 1 | use num::{integer::Roots, One, Zero}; 2 | 3 | #[cfg(feature = "big_num")] 4 | use num::{BigInt, BigUint}; 5 | 6 | /// Trait to be implemented by types that makes sense having prime numbers 7 | pub trait IsPrime { 8 | /// Check if the number is prime 9 | fn is_prime(&self) -> bool; 10 | } 11 | 12 | /// Simple implementation for the sqrt for integers (for educational porpuses) 13 | /// All other parts of the code uses the `num` crate implementation, that have better 14 | /// performance. 15 | pub fn isqrt(num: u128) -> u128 { 16 | let mut shift = 2; 17 | let mut nshifted = num >> shift; 18 | 19 | while nshifted != 0 && nshifted != num { 20 | shift += 2; 21 | nshifted = num >> shift; 22 | } 23 | 24 | shift -= 2; 25 | 26 | let mut result = 0; 27 | while shift >= 0 { 28 | result <<= 1; 29 | let candidate_res = result + 1; 30 | 31 | if candidate_res * candidate_res <= num >> shift { 32 | result = candidate_res 33 | } 34 | 35 | shift -= 2 36 | } 37 | 38 | result 39 | } 40 | 41 | #[cfg(feature = "big_num")] 42 | impl IsPrime for BigUint { 43 | fn is_prime(&self) -> bool { 44 | if self.is_zero() || self.is_one() { 45 | return false; 46 | } 47 | 48 | num::range_inclusive(BigUint::from(2u8), self.sqrt()).all(|x| self % x != BigUint::zero()) 49 | } 50 | } 51 | 52 | #[cfg(feature = "big_num")] 53 | impl IsPrime for BigInt { 54 | fn is_prime(&self) -> bool { 55 | if self.is_zero() || self.is_one() || *self < BigInt::zero() { 56 | return false; 57 | } 58 | 59 | num::range_inclusive(BigInt::from(2u8), self.sqrt()).all(|x| self % x != BigInt::zero()) 60 | } 61 | } 62 | 63 | macro_rules! impl_is_prime_unsigned { 64 | ($($t:ty)+) => { 65 | $( 66 | impl IsPrime for $t { 67 | fn is_prime(&self) -> bool { 68 | match self { 69 | 0 | 1 => false, 70 | _ => (2..=self.sqrt()).all(|a| *self % a != 0), 71 | } 72 | } 73 | } 74 | )+ 75 | }; 76 | } 77 | 78 | macro_rules! impl_is_prime_signed { 79 | ($($t:ty)+) => { 80 | $( 81 | impl IsPrime for $t { 82 | fn is_prime(&self) -> bool { 83 | match self { 84 | 0 | 1 => false, 85 | _ if self < &0 => false, 86 | _ => (2..=self.sqrt()).all(|a| *self % a != 0), 87 | } 88 | } 89 | } 90 | )+ 91 | }; 92 | } 93 | 94 | impl_is_prime_signed!(i8 i16 i32 i64 i128); 95 | impl_is_prime_unsigned!(u8 u16 u32 u64 u128); 96 | 97 | #[cfg(test)] 98 | mod tests { 99 | use super::*; 100 | 101 | #[test] 102 | fn is_prime_big_test() { 103 | let sure: Vec<_> = vec![ 104 | 2u8, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 105 | 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 106 | 179, 181, 191, 193, 197, 199, 107 | ] 108 | .iter() 109 | .map(|&x| BigUint::from(x)) 110 | .collect(); 111 | 112 | for x in sure { 113 | assert_eq!(true, x.is_prime()) 114 | } 115 | 116 | let not_primes: Vec<_> = vec![4u8, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20] 117 | .iter() 118 | .map(|&x| BigUint::from(x)) 119 | .collect(); 120 | 121 | for x in not_primes { 122 | assert_eq!(false, x.is_prime()) 123 | } 124 | } 125 | 126 | #[test] 127 | fn is_prime_test() { 128 | let sure = vec![ 129 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 130 | 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 131 | 181, 191, 193, 197, 199, 132 | ]; 133 | 134 | for x in sure { 135 | assert_eq!(true, x.is_prime()) 136 | } 137 | 138 | let not_primes = vec![4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20]; 139 | 140 | for x in not_primes { 141 | assert_eq!(false, x.is_prime(), "{}", x) 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/numerics/primorial.rs: -------------------------------------------------------------------------------- 1 | //! Primorial 2 | use super::prime::IsPrime; 3 | 4 | #[cfg(feature = "big_num")] 5 | use num::{BigUint, One, Zero}; 6 | 7 | /// Primorial iterator using big numbers. 8 | /// 9 | /// # Example 10 | /// Print the 100 first primorial numbers. 11 | /// 12 | /// ```rust 13 | /// # use algos::numerics::BigPrimorial; 14 | /// # fn main() { 15 | /// BigPrimorial::new().enumerate().take(100).for_each(|(i, v)| println!("{}#: {}", i, v)); 16 | /// # } 17 | /// ``` 18 | #[cfg(feature = "big_num")] 19 | #[derive(Debug, Clone)] 20 | pub struct BigPrimorial { 21 | /// Index we are in. 22 | index: u128, 23 | /// Last value calculated. 24 | /// 25 | /// We can do it without this value, but using it, we increase memory consuption, but 26 | /// the iterator became faster. 27 | last: BigUint, 28 | } 29 | 30 | #[cfg(feature = "big_num")] 31 | impl BigPrimorial { 32 | /// Creates a new iterator starting at the first number of the sequence. 33 | pub fn new() -> Self { BigPrimorial { index: 0, last: BigUint::one() } } 34 | 35 | /// Create a new iterator with the first factorial number beeing the `nth` factorial 36 | /// number. 37 | pub fn at(nth: impl Into) -> Self { 38 | let index = nth.into(); 39 | BigPrimorial { index, last: primorial_big(index) } 40 | } 41 | } 42 | 43 | #[cfg(feature = "big_num")] 44 | impl Iterator for BigPrimorial { 45 | type Item = BigUint; 46 | 47 | fn next(&mut self) -> Option { 48 | let next = self.last.clone(); 49 | 50 | self.index += 1; 51 | if self.index.is_prime() { 52 | self.last *= self.index; 53 | } 54 | 55 | Some(next) 56 | } 57 | } 58 | 59 | /// Return the nth primorial number using big numbers. 60 | /// 61 | /// # Panics 62 | /// This function may panic if there the computer run out of memory. 63 | #[cfg(feature = "big_num")] 64 | pub fn primorial_big(index: impl Into) -> BigUint { 65 | let index = index.into(); 66 | 67 | num::range_inclusive(BigUint::one(), index).filter(|x| x.clone().is_prime()).product() 68 | } 69 | 70 | /// Return the nth primorial number using big numbers. 71 | /// 72 | /// # Panics 73 | /// This function may panic if there the computer run out of memory. 74 | #[cfg(feature = "big_num")] 75 | pub fn recursive_primorial_big(index: impl Into) -> BigUint { 76 | let index = index.into(); 77 | 78 | if index.is_zero() || index.is_one() { 79 | return BigUint::one(); 80 | } 81 | 82 | if index.clone().is_prime() { 83 | return &index * primorial_big((&index) - BigUint::one()); 84 | } 85 | 86 | primorial_big((&index) - BigUint::one()) 87 | } 88 | 89 | /// Return the nth primorial number using the biggest integer primitive. 90 | /// 91 | /// # Panics 92 | /// This function may panic in debug mode if there is a operation with overflow. It will 93 | /// happen when `index` ≥ 103. 94 | pub fn primorial(index: u128) -> u128 { (1..=index).filter(|&x| x.is_prime()).product() } 95 | 96 | /// Return the nth primorial number using the biggest integer primitive. 97 | /// 98 | /// # Panics 99 | /// This function may panic in debug mode if there is a operation with overflow. It will 100 | /// happen when `index` ≥ 103. 101 | /// This also may panic it it reachest stack overflow due it's recursive nature and Rust 102 | /// lack of tail call optimization. _Note that there is a change that LLVM generate a code 103 | /// that this doesn't happen when in release mode_ 104 | pub fn recursive_primorial(index: u128) -> u128 { 105 | match index { 106 | 0 | 1 => 1, 107 | _ if index.is_prime() => index * primorial(index - 1), 108 | _ => primorial(index - 1), 109 | } 110 | } 111 | 112 | #[cfg(test)] 113 | mod tests { 114 | use super::*; 115 | use num::BigUint; 116 | 117 | #[test] 118 | fn iterator_test() { 119 | let sure: Vec<_> = vec![1u16, 1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310] 120 | .iter() 121 | .map(|&x| BigUint::from(x)) 122 | .collect(); 123 | 124 | let test: Vec<_> = BigPrimorial::new().take(sure.len()).collect(); 125 | 126 | assert_eq!(sure, test) 127 | } 128 | 129 | #[test] 130 | fn primorial_big_test() { 131 | let sure: Vec<_> = vec![1u16, 1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310] 132 | .iter() 133 | .map(|&x| BigUint::from(x)) 134 | .collect(); 135 | 136 | let tests: Vec<_> = (0..sure.len() as u128).map(primorial_big).collect(); 137 | 138 | assert_eq!(sure, tests) 139 | } 140 | 141 | #[test] 142 | fn recursive_primorial_big_test() { 143 | let sure: Vec<_> = vec![1u16, 1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310] 144 | .iter() 145 | .map(|&x| BigUint::from(x)) 146 | .collect(); 147 | 148 | let tests: Vec<_> = (0..sure.len() as u128).map(recursive_primorial_big).collect(); 149 | 150 | assert_eq!(sure, tests) 151 | } 152 | 153 | #[test] 154 | fn primorial_test() { 155 | let sure = vec![1, 1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310]; 156 | let tests: Vec<_> = (0..sure.len() as u128).map(primorial).collect(); 157 | 158 | assert_eq!(sure, tests) 159 | } 160 | 161 | #[test] 162 | fn recursive_primorial_test() { 163 | let sure = vec![1, 1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310]; 164 | let tests: Vec<_> = (0..sure.len() as u128).map(recursive_primorial).collect(); 165 | 166 | assert_eq!(sure, tests) 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/pattern.rs: -------------------------------------------------------------------------------- 1 | //! A module for using pattern matching algorithms. 2 | 3 | /// **Brute Force:** Search for the pattern in the `find` parameter in a slice. 4 | /// 5 | /// It returns `Some` holding the index of the first character of `find` that was found 6 | /// or `None` if not find. 7 | /// 8 | /// | Case | Time complexity | Space complexity | 9 | /// |:----------|:---------------:|:----------------:| 10 | /// | Best: | Ω(m*(n-m+1)) | | 11 | /// | Avrg: | Θ(m*(n-m+1)) | | 12 | /// | Worst: | O(m*(n-m+1)) | O(1) | 13 | /// 14 | /// # Example 15 | /// ```rust 16 | /// use algos::pattern; 17 | /// 18 | /// let p = b"ATCGGATTTCAGAAGCT"; 19 | /// 20 | /// let find = pattern::bruteforce(p, b"TTT"); 21 | /// assert_eq!(find, Some(6)); 22 | /// ``` 23 | pub fn bruteforce(pattern: &[u8], find: &[u8]) -> Option { 24 | let (size_patt, size_find) = (pattern.len(), find.len()); 25 | for i in 0..=size_patt - size_find { 26 | if &pattern[i..(i + size_find)] == find { 27 | return Some(i); 28 | } 29 | } 30 | 31 | None 32 | } 33 | 34 | /// **Karp-Rabin:** Search for the pattern in the `find` parameter in a slice. 35 | /// 36 | /// It returns `Some` holding the index of the first character of `find` that was found 37 | /// or `None` if not find. 38 | /// 39 | /// | Case | Time complexity | Space complexity | 40 | /// |:----------|:---------------:|:----------------:| 41 | /// | Best: | Ω(n+m) | | 42 | /// | Avrg: | Θ(n+m) | | 43 | /// | Worst: | O(m*(n+m)) | O(1) | 44 | /// 45 | /// # Example 46 | /// ```rust 47 | /// use algos::pattern; 48 | /// 49 | /// let p = b"ATCGGATTTCAGAAGCT"; 50 | /// 51 | /// let find = pattern::karp_rabin(p, b"TTT"); 52 | /// assert_eq!(find, Some(6)); 53 | /// ``` 54 | pub fn karp_rabin(pattern: &[u8], find: &[u8]) -> Option { 55 | let (size_patt, size_find) = (pattern.len() - 1, find.len()); 56 | 57 | // Preprocessing 58 | // TODO: There is a way to do the preprocessing using dynamic programming, making the 59 | // preprocessing time linear, making the worst case O(n+m) 60 | let rehash = |a, b, hash, base| (((hash - a * base) << 1) + b); 61 | 62 | // 2^(m-1) 63 | let base: u64 = 1 << (size_find - 1); 64 | 65 | // Calculate the hashes 66 | let (hash_find, mut hash_patt) = find.iter().take(size_find).zip(pattern.iter()).fold( 67 | (0_u64, 0_u64), 68 | |(hash_find, hash_patt), (&find, &patt)| { 69 | ((hash_find << 1) + u64::from(find), (hash_patt << 1) + u64::from(patt)) 70 | }, 71 | ); 72 | 73 | // Searching 74 | let mut i = 0; 75 | while i <= size_patt - size_find { 76 | if hash_patt == hash_find && &pattern[i..(i + size_find)] == find { 77 | return Some(i); 78 | } 79 | 80 | hash_patt = 81 | rehash(u64::from(pattern[i]), u64::from(pattern[i + size_find]), hash_patt, base); 82 | i += 1; 83 | } 84 | // Check again after the loops end. 85 | if hash_patt == hash_find && &pattern[i..(i + size_find)] == find { 86 | return Some(i); 87 | } 88 | 89 | None 90 | } 91 | 92 | /// **Boyer-Moore:** Search for the pattern in the `find` parameter in a slice. 93 | /// 94 | /// It returns `Some` holding the index of the first character of `find` that was found 95 | /// or `None` if not find. 96 | /// 97 | /// | Case | Time complexity | Space complexity | 98 | /// |:----------|:---------------:|:----------------:| 99 | /// | Best: | Ω(n/m) | | 100 | /// | Avrg: | Θ(n+m) | | 101 | /// | Worst: | O(nm) | O(m+δ) | 102 | /// 103 | /// 104 | /// **Obs.:** δ is the max size of u8. 105 | /// 106 | /// # Example 107 | /// ```rust 108 | /// use algos::pattern; 109 | /// 110 | /// let p = b"ATCGGATTTCAGAAGCT"; 111 | /// 112 | /// let find = pattern::boyer_moore(p, b"TTT"); 113 | /// assert_eq!(find, Some(6)); 114 | /// ``` 115 | pub fn boyer_moore(pattern: &[u8], find: &[u8]) -> Option { 116 | let (size_patt, size_find) = (pattern.len() - 1, find.len()); 117 | let mut good_sufix_table = vec![0_usize; size_find]; 118 | let mut bad_char_table = [0_usize; 256]; 119 | 120 | // Preprocessing 121 | preprocess_good_sufix(find, &mut good_sufix_table[..]); 122 | preprocess_bad_char(find, &mut bad_char_table[..]); 123 | 124 | // Searching 125 | let mut i = 0; 126 | while i <= size_patt - size_find { 127 | let mut j = size_find - 1; 128 | while find[j] == pattern[j + i] && j > 0 { 129 | j -= 1; 130 | } 131 | if j == 0 { 132 | if &pattern[i..(i + size_find)] == find { 133 | return Some(i); 134 | } 135 | i += good_sufix_table[0]; 136 | } else { 137 | i += good_sufix_table[j] 138 | .max(bad_char_table[pattern[j + i] as usize - size_find + 1 + j]); 139 | } 140 | } 141 | 142 | None 143 | } 144 | 145 | /// **Horspool:** Search for the pattern in the `find` parameter in a slice. 146 | /// 147 | /// It returns `Some` holding the index of the first character of `find` that was found 148 | /// or `None` if not find. 149 | /// 150 | /// It is a variation of the Boyer-Moore algorithm. 151 | /// 152 | /// | Case | Time complexity | Space complexity | 153 | /// |:----------|:---------------:|:----------------:| 154 | /// | Best: | Ω(n/m) | | 155 | /// | Avrg: | Θ(n+m) | | 156 | /// | Worst: | O(nm) | O(δ) | 157 | /// 158 | /// 159 | /// **Obs.:** δ is the max size of u8. 160 | /// 161 | /// # Example 162 | /// ```rust 163 | /// use algos::pattern; 164 | /// 165 | /// let p = b"ATCGGATTTCAGAAGCT"; 166 | /// 167 | /// let find = pattern::horspool(p, b"TTT"); 168 | /// assert_eq!(find, Some(6)); 169 | /// ``` 170 | pub fn horspool(pattern: &[u8], find: &[u8]) -> Option { 171 | let (size_patt, size_find) = (pattern.len(), find.len()); 172 | let mut bad_char_table = [0_usize; 256]; 173 | 174 | // Preprocessing 175 | preprocess_bad_char(find, &mut bad_char_table[..]); 176 | 177 | // Searching 178 | let mut i = 0; 179 | while i <= size_patt - size_find { 180 | let c = pattern[i + size_find - 1]; 181 | if find[size_find - 1] == c && &pattern[i..(i + size_find)] == find { 182 | return Some(i); 183 | } 184 | 185 | i += bad_char_table[c as usize]; 186 | } 187 | 188 | None 189 | } 190 | 191 | fn preprocess_good_sufix(find: &[u8], good_sufix_table: &mut [usize]) { 192 | let size = find.len(); 193 | 194 | // Good sufix 195 | let mut suff = vec![0; size]; 196 | let mut good = size - 1; 197 | let mut f = 0; 198 | suff[size - 1] = size; 199 | for i in (0..suff.len()).rev() { 200 | if i > good && suff[i + size - 1 + f] < i - good { 201 | suff[i] = suff[i + size - 1 + f]; 202 | } else { 203 | good = if (good) < i { i } else { good }; 204 | f = i; 205 | while good == 0 && find[good] == find[good + size - 1 - f] { 206 | good -= 1; 207 | } 208 | suff[i] = good - f; 209 | } 210 | } 211 | 212 | for i in good_sufix_table.iter_mut().take(size) { 213 | *i = size; 214 | } 215 | for i in (0..size).rev() { 216 | if suff[i] == i + 1 { 217 | for j in good_sufix_table.iter_mut().take(size - 1) { 218 | if *j == size { 219 | *j = size - i - 1; 220 | } 221 | } 222 | } 223 | } 224 | for i in 0..size { 225 | good_sufix_table[size - 1 - suff[i] as usize] = size - 1 - i; 226 | } 227 | } 228 | 229 | fn preprocess_bad_char(find: &[u8], bad_char_table: &mut [usize]) { 230 | let size: usize = find.len(); 231 | 232 | for i in bad_char_table.iter_mut() { 233 | *i = size; 234 | } 235 | for i in 0..size - 1 { 236 | bad_char_table[find[i] as usize] = size - i - 1; 237 | } 238 | } 239 | 240 | /// **Quick:** Search for the pattern in the `find` parameter in a slice. 241 | /// 242 | /// It returns `Some` holding the index of the first character of `find` that was found 243 | /// or `None` if not find. 244 | /// 245 | /// It is a simplification of the Boyer-Moore algorithm. 246 | /// 247 | /// | Case | Time complexity | Space complexity | 248 | /// |:----------|:---------------:|:----------------:| 249 | /// | Best: | Ω(n/m) | | 250 | /// | Avrg: | Θ(n+m) | | 251 | /// | Worst: | O(nm) | O(δ) | 252 | /// 253 | /// 254 | /// **Obs.:** δ is the max size of u8. 255 | /// 256 | /// # Example 257 | /// ```rust 258 | /// use algos::pattern; 259 | /// 260 | /// let p = b"ATCGGATTTCAGAAGCT"; 261 | /// 262 | /// let find = pattern::quick_matching(p, b"TTT"); 263 | /// assert_eq!(find, Some(6)); 264 | /// ``` 265 | pub fn quick_matching(pattern: &[u8], find: &[u8]) -> Option { 266 | let (size_patt, size_find) = (pattern.len(), find.len()); 267 | let mut bad_char_table = [0_usize; 256]; 268 | 269 | // Preprocessing 270 | preprocess_quick_bad_char(&find, &mut bad_char_table); 271 | 272 | // Searching 273 | let mut i = 0; 274 | while i <= size_patt - size_find { 275 | if &pattern[i..(i + size_find)] == find { 276 | return Some(i); 277 | } 278 | 279 | i += bad_char_table[pattern[i + size_find] as usize]; 280 | } 281 | 282 | None 283 | } 284 | 285 | fn preprocess_quick_bad_char(find: &[u8], bad_char_table: &mut [usize]) { 286 | for i in bad_char_table.iter_mut() { 287 | *i = find.len() + 1; 288 | } 289 | for i in 0..find.len() { 290 | bad_char_table[find[i] as usize] = find.len() - i; 291 | } 292 | } 293 | 294 | 295 | #[cfg(test)] 296 | pub mod test { 297 | use super::*; 298 | 299 | #[test] 300 | pub fn bruteforce_cases() { 301 | let p = b"ATCGGATTTCAGAAGCT"; 302 | 303 | let start = bruteforce(p, b"ATC"); 304 | let middle1 = bruteforce(p, b"TTT"); 305 | let middle2 = bruteforce(p, b"AAG"); 306 | let end = bruteforce(p, b"GCT"); 307 | let none = bruteforce(p, b"TTTT"); 308 | assert_eq!(start, Some(0)); 309 | assert_eq!(middle1, Some(6)); 310 | assert_eq!(middle2, Some(12)); 311 | assert_eq!(end, Some(14)); 312 | assert_eq!(none, None); 313 | } 314 | 315 | #[test] 316 | pub fn karp_rabin_cases() { 317 | let p = b"ATCGGATTTCAGAAGCT"; 318 | 319 | let start = karp_rabin(p, b"ATC"); 320 | let middle1 = karp_rabin(p, b"TTT"); 321 | let middle2 = karp_rabin(p, b"AAG"); 322 | let end = karp_rabin(p, b"GCT"); 323 | let none = karp_rabin(p, b"TTTT"); 324 | assert_eq!(start, Some(0)); 325 | assert_eq!(middle1, Some(6)); 326 | assert_eq!(middle2, Some(12)); 327 | assert_eq!(end, Some(14)); 328 | assert_eq!(none, None); 329 | } 330 | 331 | #[test] 332 | #[ignore] 333 | pub fn boyer_moore_cases() { 334 | let p = b"ATCGGATTTCAGAAGCT"; 335 | 336 | let start = boyer_moore(p, b"ATC"); 337 | let middle1 = boyer_moore(p, b"TTT"); 338 | let middle2 = boyer_moore(p, b"AAG"); 339 | let end = boyer_moore(p, b"GCT"); 340 | let none = boyer_moore(p, b"TTTT"); 341 | assert_eq!(start, Some(0)); 342 | assert_eq!(middle1, Some(6)); 343 | assert_eq!(middle2, Some(12)); 344 | assert_eq!(end, Some(14)); 345 | assert_eq!(none, None); 346 | } 347 | 348 | #[test] 349 | pub fn horspool_cases() { 350 | let p = b"ATCGGATTTCAGAAGCT"; 351 | 352 | let start = horspool(p, b"ATC"); 353 | let middle1 = horspool(p, b"TTT"); 354 | let middle2 = horspool(p, b"AAG"); 355 | let end = horspool(p, b"GCT"); 356 | let none = horspool(p, b"TTTT"); 357 | assert_eq!(start, Some(0)); 358 | assert_eq!(middle1, Some(6)); 359 | assert_eq!(middle2, Some(12)); 360 | assert_eq!(end, Some(14)); 361 | assert_eq!(none, None); 362 | } 363 | 364 | #[test] 365 | pub fn quick_cases() { 366 | let p = b"ATCGGATTTCAGAAGCT"; 367 | 368 | let start = quick_matching(p, b"ATC"); 369 | let middle1 = quick_matching(p, b"TTT"); 370 | let middle2 = quick_matching(p, b"AAG"); 371 | let end = quick_matching(p, b"GCT"); 372 | let none = quick_matching(p, b"TTTT"); 373 | assert_eq!(start, Some(0)); 374 | assert_eq!(middle1, Some(6)); 375 | assert_eq!(middle2, Some(12)); 376 | assert_eq!(end, Some(14)); 377 | assert_eq!(none, None); 378 | } 379 | } 380 | -------------------------------------------------------------------------------- /src/search.rs: -------------------------------------------------------------------------------- 1 | //! A module for using searching algorithms. 2 | //! 3 | //! The array **must** be crescent ordered. 4 | 5 | /// **Linear Search:** Search for the value `x` in an array. 6 | /// 7 | /// If the value is found then `Ok` is returned, containing the index of the matching 8 | /// element; if the value is not found then `Err` is returned, containing the index where 9 | /// a matching element could be inserted while maintaining sorted order. 10 | /// 11 | /// Returns `Err` holding the last iterator if `x` not found and `v[i] > x`. 12 | /// 13 | /// 14 | /// | Case | Time complexity | Space complexity | 15 | /// |:----------|:---------------:|:----------------:| 16 | /// | Best: | Ω(1) | | 17 | /// | Avrg: | Θ(n) | | 18 | /// | Worst: | O(n) | O(1) | 19 | /// 20 | /// # Example 21 | /// ```rust 22 | /// use algos::search; 23 | /// 24 | /// let v = [1, 3, 4, 8, 11, 17, 23]; 25 | /// 26 | /// let find = search::linear(&v, &11); 27 | /// assert_eq!(find, Ok(4)); 28 | /// 29 | /// let find2 = search::linear(&v, &19); 30 | /// assert_eq!(find2, Err(6)); 31 | /// ``` 32 | pub fn linear(v: &[T], x: &T) -> Result { 33 | for (i, e) in v.iter().enumerate() { 34 | if e == x { 35 | return Ok(i); 36 | } else if e > x { 37 | return Err(i); 38 | } 39 | } 40 | Err(0) 41 | } 42 | 43 | /// **Binary Search:** Search for the value `x` in an array. 44 | /// 45 | /// If the value is found then `Ok` is returned, containing the index of the matching 46 | /// element; if the value is not found then `Err` is returned, containing the index where 47 | /// a matching element could be inserted while maintaining sorted order. 48 | /// 49 | /// Returns `Err` holding the leftmost term if `x` not found. 50 | /// 51 | /// 52 | /// | Case | Time complexity | Space complexity | 53 | /// |:----------|:---------------:|:----------------:| 54 | /// | Best: | Ω(1) | | 55 | /// | Avrg: | Θ(log(n)) | | 56 | /// | Worst: | O(log(n)) | O(1) | 57 | /// 58 | /// # Example 59 | /// ```rust 60 | /// use algos::search; 61 | /// 62 | /// let v = [1, 3, 4, 8, 11, 17, 23]; 63 | /// 64 | /// let find = search::binary(&v, &11); 65 | /// assert_eq!(find, Ok(4)); 66 | /// 67 | /// let find2 = search::binary(&v, &19); 68 | /// assert_eq!(find2, Err(6)); 69 | /// ``` 70 | pub fn binary(v: &[T], x: &T) -> Result { 71 | let (mut l, mut r) = (0, v.len()); 72 | // Looks like I'm unable to make v recursive implementation, so I made interative. 73 | while l <= r { 74 | // This has the same result as (l+r)/2, but it's probably the same or faster. 75 | let mid = (l + r) >> 1; 76 | 77 | if v[mid] > *x { 78 | r = mid - 1; 79 | } else if v[mid] < *x { 80 | l = mid + 1; 81 | } else { 82 | return Ok(mid); 83 | } 84 | } 85 | Err(l) 86 | } 87 | 88 | /// **Exponential Search:** Search for the value `x` in an array. 89 | /// 90 | /// If the value is found then `Ok` is returned, containing the index of the matching 91 | /// element; if the value is not found then `Err` is returned, containing the index where 92 | /// a matching element could be inserted while maintaining sorted order. 93 | /// 94 | /// Returns `Err` holding the leftmost term if `x` not found. 95 | /// 96 | /// **Obs.:** Variation of binary search. 97 | /// 98 | /// | Case | Time complexity | Space complexity | 99 | /// |:----------|:---------------:|:----------------:| 100 | /// | Best: | Ω(1) | | 101 | /// | Avrg: | Θ(log(n)) | | 102 | /// | Worst: | O(log(n)) | O(1) | 103 | /// 104 | /// # Example 105 | /// ```rust 106 | /// use algos::search; 107 | /// 108 | /// let v = [1, 3, 4, 8, 11, 17, 23]; 109 | /// 110 | /// let find = search::exponential(&v, &11); 111 | /// assert_eq!(find, Ok(4)); 112 | /// 113 | /// let find2 = search::exponential(&v, &19); 114 | /// assert_eq!(find2, Err(6)); 115 | /// ``` 116 | pub fn exponential(v: &[T], x: &T) -> Result { 117 | if v[0] == *x { 118 | return Ok(0); 119 | } 120 | 121 | let mut range = 1; 122 | while range < v.len() && v[range] <= *x { 123 | range *= 2; 124 | } 125 | 126 | let (mut l, mut r) = (range / 2, range.min(v.len())); 127 | while l <= r { 128 | // This has the same result as (l+r)/2, but it's probably the same or faster. 129 | let mid = (l + r) >> 1; 130 | 131 | if v[mid] > *x { 132 | r = mid - 1; 133 | } else if v[mid] < *x { 134 | l = mid + 1; 135 | } else { 136 | return Ok(mid); 137 | } 138 | } 139 | Err(l) 140 | } 141 | 142 | /// **Fibonacci Search:** Search for the value `x` in an array. 143 | /// 144 | /// If the value is found then `Ok` is returned, containing the index of the matching 145 | /// element; if the value is not found then `Err` is returned, containing the index where 146 | /// a matching element could be inserted while maintaining sorted order. 147 | /// 148 | /// 149 | /// **Obs.:** Variation of binary search. 150 | /// 151 | /// | Case | Time complexity | Space complexity | 152 | /// |:----------|:---------------:|:----------------:| 153 | /// | Best: | Ω(1) | | 154 | /// | Avrg: | Θ(log(n)) | | 155 | /// | Worst: | O(log(n)) | O(1) | 156 | /// 157 | /// # Example 158 | /// ```rust 159 | /// use algos::search; 160 | /// 161 | /// let v = [1, 3, 4, 8, 11, 17, 23]; 162 | /// 163 | /// let find = search::fibonacci(&v, &11); 164 | /// assert_eq!(find, Ok(4)); 165 | /// 166 | /// let find2 = search::fibonacci(&v, &19); 167 | /// assert_eq!(find2, Err(3)); 168 | /// ``` 169 | pub fn fibonacci(v: &[T], x: &T) -> Result { 170 | let (mut fib1, mut fib2) = (0, 1); 171 | let mut fibn = fib1 + fib2; 172 | 173 | // We are recalculating numbers, we can do better using dynamic programming. 174 | // Stores the smallest Fibonacci Number greater than or equal to v.len(). 175 | while fibn < v.len() { 176 | fib1 = fib2; 177 | fib2 = fibn; 178 | fibn = fib1 + fib2; 179 | } 180 | 181 | let mut off = 0; 182 | while fibn > 1 { 183 | let i = (off + fib1 - 1).min(v.len()); 184 | 185 | if v[i] < *x { 186 | fibn = fib2; 187 | fib2 = fib1; 188 | fib1 = fibn - fib2; 189 | off = i; 190 | } else if v[i] > *x { 191 | fibn = fib1; 192 | fib2 -= fib1; 193 | fib1 = fibn - fib2; 194 | } else { 195 | return Ok(i); 196 | } 197 | } 198 | 199 | if fib2 == 1 && v[off + 1] == *x { 200 | return Ok(off + 1); 201 | } 202 | 203 | Err(off) 204 | } 205 | 206 | 207 | #[cfg(test)] 208 | pub mod test { 209 | use super::*; 210 | 211 | #[test] 212 | pub fn linear_test() { 213 | let v = [1, 3, 4, 8, 11, 17, 23]; 214 | 215 | let ok1 = linear(&v, &1); 216 | let ok2 = linear(&v, &11); 217 | assert_eq!(ok1, Ok(0)); 218 | assert_eq!(ok2, Ok(4)); 219 | 220 | let err1 = linear(&v, &19); 221 | let err2 = linear(&v, &13); 222 | assert_eq!(err1, Err(6)); 223 | assert_eq!(err2, Err(5)); 224 | } 225 | #[test] 226 | pub fn binary_test() { 227 | let v = [1, 3, 4, 8, 11, 17, 23]; 228 | 229 | let ok1 = binary(&v, &1); 230 | let ok2 = binary(&v, &11); 231 | assert_eq!(ok1, Ok(0)); 232 | assert_eq!(ok2, Ok(4)); 233 | 234 | let err1 = binary(&v, &19); 235 | let err2 = binary(&v, &13); 236 | assert_eq!(err1, Err(6)); 237 | assert_eq!(err2, Err(5)); 238 | } 239 | #[test] 240 | pub fn exponential_test() { 241 | let v = [1, 3, 4, 8, 11, 17, 23]; 242 | 243 | let ok1 = exponential(&v, &1); 244 | let ok2 = exponential(&v, &11); 245 | assert_eq!(ok1, Ok(0)); 246 | assert_eq!(ok2, Ok(4)); 247 | 248 | let err1 = exponential(&v, &19); 249 | let err2 = exponential(&v, &13); 250 | assert_eq!(err1, Err(6)); 251 | assert_eq!(err2, Err(5)); 252 | } 253 | #[test] 254 | pub fn fibonacci_test() { 255 | let v = [1, 3, 4, 8, 11, 17, 23]; 256 | 257 | let ok1 = fibonacci(&v, &1); 258 | let ok2 = fibonacci(&v, &11); 259 | assert_eq!(ok1, Ok(0)); 260 | assert_eq!(ok2, Ok(4)); 261 | 262 | let err1 = fibonacci(&v, &19); 263 | let err2 = fibonacci(&v, &13); 264 | assert_eq!(err1, Err(3)); 265 | assert_eq!(err2, Err(3)); 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /src/sort.rs: -------------------------------------------------------------------------------- 1 | //! A module for using sorting algorithms. 2 | //! 3 | //! It contains all major sorting algorithms. 4 | 5 | use rand::prelude::{thread_rng, Rng}; 6 | 7 | /// **Selection Sort:** Sort `v` slice according to the way you define the `cmp` 8 | /// parameter. 9 | /// 10 | /// This sort is stable. 11 | /// 12 | /// | Case | Time complexity | Space complexity | 13 | /// |:----------|:---------------:|:----------------:| 14 | /// | Best: | Ω(n²) | | 15 | /// | Avrg: | Θ(n²) | | 16 | /// | Worst: | O(n²) | O(1) | 17 | /// 18 | /// # Example 19 | /// ```rust 20 | /// use algos::sort; 21 | /// 22 | /// let mut v = [9, 3, 5, 7, 8, 7]; 23 | /// // Crescent sorting 24 | /// sort::selection(&mut v, &|v, b| v < b); 25 | /// ``` 26 | pub fn selection bool>(v: &mut [T], cmp: &C) { 27 | for i in 0..=v.len() { 28 | let mut i_min = i; 29 | for j in i + 1..v.len() { 30 | if cmp(&v[j], &v[i_min]) { 31 | i_min = j; 32 | } 33 | } 34 | if i_min != i { 35 | v.swap(i_min, i); 36 | } 37 | } 38 | } 39 | 40 | /// **Bubble Sort:** Sort `v` slice according to the way you define the `cmp` parameter. 41 | /// 42 | /// This sort is stable. 43 | /// 44 | /// | Case | Time complexity | Space complexity | 45 | /// |:----------|:---------------:|:----------------:| 46 | /// | Best: | Ω(n) | | 47 | /// | Avrg: | Θ(n²) | | 48 | /// | Worst: | O(n²) | O(1) | 49 | /// 50 | /// # Example 51 | /// ```rust 52 | /// use algos::sort; 53 | /// 54 | /// let mut v = [9, 3, 5, 7, 8, 7]; 55 | /// // Crescent sorting 56 | /// sort::bubble(&mut v, &|v, b| v < b); 57 | /// ``` 58 | pub fn bubble bool>(v: &mut [T], cmp: &C) { 59 | for i in (0..v.len()).rev() { 60 | for j in 0..i { 61 | if cmp(&v[j + 1], &v[j]) { 62 | v.swap(j, j + 1); 63 | } 64 | } 65 | } 66 | } 67 | 68 | /// **Cocktail Sort:** Sort `v` slice according to the way you define the `cmp` parameter. 69 | /// It's a variation of Bubble Sort. 70 | /// 71 | /// This sort is stable. 72 | /// 73 | /// | Case | Time complexity | Space complexity | 74 | /// |:----------|:---------------:|:----------------:| 75 | /// | Best: | Ω(n) | | 76 | /// | Avrg: | Θ(n²) | | 77 | /// | Worst: | O(n²) | O(1) | 78 | /// 79 | /// # Example 80 | /// ```rust 81 | /// use algos::sort; 82 | /// 83 | /// let mut v = [9, 3, 5, 7, 8, 7]; 84 | /// // Crescent sorting 85 | /// sort::cocktail(&mut v, &|v, b| v < b); 86 | /// ``` 87 | pub fn cocktail bool>(v: &mut [T], cmp: &C) { 88 | let mut changed: bool = true; 89 | let mut start = 0; 90 | let mut end = v.len() - 1; 91 | while changed { 92 | changed = false; 93 | for i in start..end { 94 | if cmp(&v[i + 1], &v[i]) { 95 | v.swap(i, i + 1); 96 | changed = true; 97 | } 98 | } 99 | end -= 1; 100 | 101 | if !changed { 102 | break; 103 | } 104 | 105 | changed = true; 106 | for i in (start..end - 1).rev() { 107 | if cmp(&v[i + 1], &v[i]) { 108 | v.swap(i, i + 1); 109 | changed = true; 110 | } 111 | } 112 | start += 1; 113 | } 114 | } 115 | 116 | /// **Insection Sort:** Sort `v` slice according to the way you define the `cmp` 117 | /// parameter. 118 | /// 119 | /// This sort is stable. 120 | /// 121 | /// | Case | Time complexity | Space complexity | 122 | /// |:----------|:---------------:|:----------------:| 123 | /// | Best: | Ω(n) | | 124 | /// | Avrg: | Θ(n²) | | 125 | /// | Worst: | O(n²) | O(1) | 126 | /// 127 | /// # Example 128 | /// ```rust 129 | /// use algos::sort; 130 | /// 131 | /// let mut v = [9, 3, 5, 7, 8, 7]; 132 | /// // Crescent sorting 133 | /// sort::insection(&mut v, &|v, b| v < b); 134 | /// ``` 135 | pub fn insection bool>(v: &mut [T], cmp: &C) { 136 | for i in 1..v.len() { 137 | for j in (0..i).rev() { 138 | if cmp(&v[j + 1], &v[j]) { 139 | v.swap(j, j + 1); 140 | } 141 | } 142 | } 143 | } 144 | 145 | /// **Merge Sort:** Sort `v` slice according to the way you define the `cmp` parameter. 146 | /// 147 | /// This sort is stable. 148 | /// 149 | /// | Case | Time complexity | Space complexity | 150 | /// |:----------|:---------------:|:----------------:| 151 | /// | Best: | Ω(nlog(n)) | | 152 | /// | Avrg: | Θ(nlog(n)) | | 153 | /// | Worst: | O(nlog(n)) | O(n) | 154 | /// 155 | /// # Example 156 | /// ```rust 157 | /// use algos::sort; 158 | /// 159 | /// let mut v = [9, 3, 5, 7, 8, 7]; 160 | /// // Crescent sorting 161 | /// sort::merge(&mut v, &|v, b| v < b); 162 | /// ``` 163 | pub fn merge bool>(v: &mut [T], cmp: &C) { 164 | let (start, mid, end) = (0, v.len() / 2, v.len()); 165 | if end <= 1 { 166 | return; 167 | } 168 | merge(&mut v[start..mid], cmp); 169 | merge(&mut v[mid..end], cmp); 170 | // Copy array "v" to auxiliar array "o" 171 | let mut o: Vec = v.to_vec(); 172 | combine(&v[start..mid], &v[mid..end], &mut o[..], cmp); 173 | // Copy itens of "o" into "v" 174 | v.copy_from_slice(&o); 175 | } 176 | 177 | /// Combines `l` and `r` arrays into `o` 178 | /// 179 | /// # Panic 180 | /// This function may panic if `left` size + `right` size is different of `o` size. 181 | fn combine bool>( 182 | left: &[T], right: &[T], o: &mut [T], cmp: &C, 183 | ) { 184 | assert_eq!(right.len() + left.len(), o.len()); 185 | let (mut i, mut j, mut k) = (0, 0, 0); 186 | while i < left.len() && j < right.len() { 187 | if cmp(&left[i], &right[j]) { 188 | o[k] = left[i]; 189 | k += 1; 190 | i += 1; 191 | } else { 192 | o[k] = right[j]; 193 | k += 1; 194 | j += 1; 195 | } 196 | } 197 | if i < left.len() { 198 | o[k..].copy_from_slice(&left[i..]); 199 | } 200 | if j < right.len() { 201 | o[k..].copy_from_slice(&right[j..]); 202 | } 203 | } 204 | 205 | 206 | /// **Quick Sort:** Sort `v` slice according to the way you define the `cmp` parameter. 207 | /// 208 | /// This sort is unstable. 209 | /// 210 | /// | Case | Time complexity | Space complexity | 211 | /// |:----------|:---------------:|:----------------:| 212 | /// | Best: | Ω(nlog(n)) | | 213 | /// | Avrg: | Θ(nlog(n)) | | 214 | /// | Worst: | O(n²) | O(log(n)) | 215 | /// 216 | /// # Example 217 | /// ```rust 218 | /// use algos::sort; 219 | /// 220 | /// let mut v = [9, 3, 5, 7, 8, 7]; 221 | /// // Crescent sorting 222 | /// sort::quick(&mut v, &|v, b| v < b); 223 | /// ``` 224 | pub fn quick bool>(v: &mut [T], cmp: &C) { 225 | let (start, end) = (0, v.len()); 226 | if end <= 1 { 227 | return; 228 | } 229 | let mid = partition(v, cmp); 230 | quick(&mut v[start..mid - 1], cmp); 231 | quick(&mut v[mid..end], cmp); 232 | } 233 | 234 | /// Establish where is the middle of `v` and returns it. 235 | fn partition bool>(v: &mut [T], cmp: &C) -> usize { 236 | let (start, end) = (0, v.len() - 1); 237 | // We randomize the choice of the pivot so we have less probability to have Worst case. 238 | // Then we swap the random element to the end of the array. 239 | let rand = thread_rng().gen_range(start..=end); 240 | let pivot = v[rand]; 241 | v.swap(rand, end); 242 | 243 | let mut i = start; 244 | for j in start..end { 245 | if cmp(&v[j], &pivot) { 246 | v.swap(i, j); 247 | i += 1; 248 | } 249 | } 250 | v.swap(i, end); 251 | i + 1 252 | } 253 | 254 | /// **Heap Sort:** Sort `v` slice according to the way you define the `cmp` parameter. 255 | /// 256 | /// This sort is unstable. 257 | /// 258 | /// | Case | Time complexity | Space complexity | 259 | /// |:----------|:---------------:|:----------------:| 260 | /// | Best: | Ω(nlog(n)) | | 261 | /// | Avrg: | Θ(nlog(n)) | | 262 | /// | Worst: | O(nlog(n)) | O(1) | 263 | /// 264 | /// # Example 265 | /// ```rust 266 | /// use algos::sort; 267 | /// 268 | /// let mut v = [9, 3, 5, 7, 8, 7]; 269 | /// // Crescent sorting 270 | /// sort::heap(&mut v, &|v, b| v < b); 271 | /// ``` 272 | pub fn heap bool>(v: &mut [T], cmp: &C) { 273 | let (start, end) = (0, v.len()); 274 | for i in (start..end / 2).rev() { 275 | heapify(&mut v[..], cmp, i); 276 | } 277 | for i in (0..end).rev() { 278 | v.swap(0, i); 279 | heapify(&mut v[..i], cmp, 0); 280 | } 281 | } 282 | 283 | /// Creates a heap with `node` which is an index in `v`. 284 | fn heapify bool>(v: &mut [T], cmp: &C, node: usize) { 285 | let end = v.len(); 286 | let mut root = node; 287 | let (left_child, right_child) = (2 * node, 2 * node + 1); 288 | if left_child < end && cmp(&v[root], &v[left_child]) { 289 | root = left_child; 290 | } 291 | if right_child < end && cmp(&v[root], &v[right_child]) { 292 | root = right_child; 293 | } 294 | if root != node { 295 | v.swap(node, root); 296 | heapify(v, cmp, root); 297 | } 298 | } 299 | 300 | 301 | #[cfg(test)] 302 | pub mod test { 303 | use super::*; 304 | 305 | #[test] 306 | pub fn selection_test() { 307 | let p = [3, 5, 7, 7, 8, 9, 12, 15, 23, 30, 99]; 308 | let mut v = [9, 3, 5, 7, 8, 7, 99, 30, 23, 15, 12]; 309 | 310 | selection(&mut v, &|a, b| a < b); 311 | assert_eq!(v, p); 312 | } 313 | 314 | #[test] 315 | pub fn selection_floats_test() { 316 | let p = [3.1, 5.2, 7.3, 7.3, 8.4, 9.5, 12.6, 15.7, 23.8, 30.9, 99.0]; 317 | let mut v = [9.5, 3.1, 5.2, 7.3, 8.4, 7.3, 99.0, 30.9, 23.8, 15.7, 12.6]; 318 | 319 | selection(&mut v, &|a, b| a < b); 320 | assert_eq!(v, p); 321 | } 322 | 323 | #[test] 324 | pub fn bubble_test() { 325 | let p = [3, 5, 7, 7, 8, 9, 12, 15, 23, 30, 99]; 326 | let mut v = [9, 3, 5, 7, 8, 7, 99, 30, 23, 15, 12]; 327 | 328 | bubble(&mut v, &|a, b| a < b); 329 | assert_eq!(v, p); 330 | } 331 | 332 | #[test] 333 | pub fn bubble_floats_test() { 334 | let p = [3.1, 5.2, 7.3, 7.3, 8.4, 9.5, 12.6, 15.7, 23.8, 30.9, 99.0]; 335 | let mut v = [9.5, 3.1, 5.2, 7.3, 8.4, 7.3, 99.0, 30.9, 23.8, 15.7, 12.6]; 336 | 337 | bubble(&mut v, &|a, b| a < b); 338 | assert_eq!(v, p); 339 | } 340 | 341 | #[test] 342 | pub fn cocktail_test() { 343 | let p = [3, 5, 7, 7, 8, 9, 12, 15, 23, 30, 99]; 344 | let mut v = [9, 3, 5, 7, 8, 7, 99, 30, 23, 15, 12]; 345 | 346 | cocktail(&mut v, &|a, b| a < b); 347 | assert_eq!(v, p); 348 | } 349 | 350 | #[test] 351 | pub fn cocktail_floats_test() { 352 | let p = [3.1, 5.2, 7.3, 7.3, 8.4, 9.5, 12.6, 15.7, 23.8, 30.9, 99.0]; 353 | let mut v = [9.5, 3.1, 5.2, 7.3, 8.4, 7.3, 99.0, 30.9, 23.8, 15.7, 12.6]; 354 | 355 | cocktail(&mut v, &|a, b| a < b); 356 | assert_eq!(v, p); 357 | } 358 | 359 | #[test] 360 | pub fn insection_test() { 361 | let p = [3, 5, 7, 7, 8, 9, 12, 15, 23, 30, 99]; 362 | let mut v = [9, 3, 5, 7, 8, 7, 99, 30, 23, 15, 12]; 363 | 364 | insection(&mut v, &|a, b| a < b); 365 | assert_eq!(v, p); 366 | } 367 | 368 | #[test] 369 | pub fn insection_floats_test() { 370 | let p = [3.1, 5.2, 7.3, 7.3, 8.4, 9.5, 12.6, 15.7, 23.8, 30.9, 99.0]; 371 | let mut v = [9.5, 3.1, 5.2, 7.3, 8.4, 7.3, 99.0, 30.9, 23.8, 15.7, 12.6]; 372 | 373 | insection(&mut v, &|a, b| a < b); 374 | assert_eq!(v, p); 375 | } 376 | 377 | #[test] 378 | pub fn merge_test() { 379 | let p = [3, 5, 7, 7, 8, 9, 12, 15, 23, 30, 99]; 380 | let mut v = [9, 3, 5, 7, 8, 7, 99, 30, 23, 15, 12]; 381 | 382 | merge(&mut v, &|a, b| a < b); 383 | assert_eq!(v, p); 384 | } 385 | 386 | #[test] 387 | pub fn merge_floats_test() { 388 | let p = [3.1, 5.2, 7.3, 7.3, 8.4, 9.5, 12.6, 15.7, 23.8, 30.9, 99.0]; 389 | let mut v = [9.5, 3.1, 5.2, 7.3, 8.4, 7.3, 99.0, 30.9, 23.8, 15.7, 12.6]; 390 | 391 | merge(&mut v, &|a, b| a < b); 392 | assert_eq!(v, p); 393 | } 394 | 395 | #[test] 396 | pub fn quick_test() { 397 | let p = [3, 5, 7, 7, 8, 9, 12, 15, 23, 30, 99]; 398 | let mut v = [9, 3, 5, 7, 8, 7, 99, 30, 23, 15, 12]; 399 | 400 | quick(&mut v, &|a, b| a < b); 401 | assert_eq!(v, p); 402 | } 403 | 404 | #[test] 405 | pub fn quick_floats_test() { 406 | let p = [3.1, 5.2, 7.3, 7.3, 8.4, 9.5, 12.6, 15.7, 23.8, 30.9, 99.0]; 407 | let mut v = [9.5, 3.1, 5.2, 7.3, 8.4, 7.3, 99.0, 30.9, 23.8, 15.7, 12.6]; 408 | 409 | quick(&mut v, &|a, b| a < b); 410 | assert_eq!(v, p); 411 | } 412 | 413 | #[test] 414 | pub fn heap_test() { 415 | let p = [3, 5, 7, 7, 8, 9, 12, 15, 23, 30, 99]; 416 | let mut v = [9, 3, 5, 7, 8, 7, 99, 30, 23, 15, 12]; 417 | 418 | heap(&mut v, &|a, b| a < b); 419 | assert_eq!(v, p); 420 | } 421 | 422 | #[test] 423 | pub fn heap_floats_test() { 424 | let p = [3.1, 5.2, 7.3, 7.3, 8.4, 9.5, 12.6, 15.7, 23.8, 30.9, 99.0]; 425 | let mut v = [9.5, 3.1, 5.2, 7.3, 8.4, 7.3, 99.0, 30.9, 23.8, 15.7, 12.6]; 426 | 427 | heap(&mut v, &|a, b| a < b); 428 | assert_eq!(v, p); 429 | } 430 | } 431 | --------------------------------------------------------------------------------