Skip to content

Commit a2c1c89

Browse files
feat: add bogobogo + tree + bitonic + pigeonhole sort (#67)
1 parent 66e1ceb commit a2c1c89

File tree

9 files changed

+656
-0
lines changed

9 files changed

+656
-0
lines changed

src/math/derivative_method.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
const DERIVATIVE_PRECISION: f64 = 0.0001;
2+
3+
pub fn derivative_method<F>(x: f64, y: f64, f: F) -> f64
4+
where
5+
F: Fn(f64, f64) -> f64,
6+
{
7+
let h = DERIVATIVE_PRECISION;
8+
(f(x + h, y) - f(x, y)) / h
9+
}
10+
11+
#[cfg(test)]
12+
mod tests {
13+
use super::*;
14+
15+
fn test_function(x: f64, y: f64) -> f64 {
16+
x.powi(2) + y.powi(2)
17+
}
18+
19+
#[test]
20+
fn test_derivative() {
21+
let x = 1.0;
22+
let y = 2.0;
23+
let f = test_function;
24+
let df_dx = derivative_method(x, y, f);
25+
let df_dy = derivative_method(y, x, f);
26+
assert_eq!(df_dx, 2.000100000003613);
27+
assert_eq!(df_dy, 4.0001000000078335);
28+
}
29+
30+
#[test]
31+
fn test_error() {
32+
let x = 1.0;
33+
let y = 2.0;
34+
let f = test_function;
35+
let df_dx = derivative_method(x, y, f);
36+
let df_dy = derivative_method(y, x, f);
37+
assert_ne!(df_dx, 2.0);
38+
assert_ne!(df_dy, 4.0);
39+
}
40+
41+
#[test]
42+
fn test_nan() {
43+
let x = 1.0;
44+
let y = 2.0;
45+
let f = test_function;
46+
let df_dx = derivative_method(x, y, f);
47+
let df_dy = derivative_method(y, x, f);
48+
assert!(!df_dx.is_nan());
49+
assert!(!df_dy.is_nan());
50+
}
51+
52+
#[test]
53+
fn test_inf() {
54+
let x = 1.0;
55+
let y = 2.0;
56+
let f = test_function;
57+
let df_dx = derivative_method(x, y, f);
58+
let df_dy = derivative_method(y, x, f);
59+
assert!(!df_dx.is_infinite());
60+
assert!(!df_dy.is_infinite());
61+
}
62+
63+
#[test]
64+
fn test_zero() {
65+
let x = 1.0;
66+
let y = 2.0;
67+
let f = test_function;
68+
let df_dx = derivative_method(x, y, f);
69+
let df_dy = derivative_method(y, x, f);
70+
assert_ne!(df_dx, 0.0);
71+
assert_ne!(df_dy, 0.0);
72+
}
73+
74+
#[test]
75+
fn test_subnormal() {
76+
let x = 1.0;
77+
let y = 2.0;
78+
let f = test_function;
79+
let df_dx = derivative_method(x, y, f);
80+
let df_dy = derivative_method(y, x, f);
81+
assert!(!df_dx.is_subnormal());
82+
assert!(!df_dy.is_subnormal());
83+
}
84+
}

src/math/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod armstrong_number;
22
mod baby_step_giant_step;
3+
mod derivative_method;
34
mod extended_euclidean_algorithm;
45
mod fast_fourier_transform;
56
mod fast_power;
@@ -30,6 +31,7 @@ mod zellers_congruence_algorithm;
3031

3132
pub use self::armstrong_number::is_armstrong_number;
3233
pub use self::baby_step_giant_step::baby_step_giant_step;
34+
pub use self::derivative_method::derivative_method;
3335
pub use self::extended_euclidean_algorithm::extended_euclidean_algorithm;
3436
pub use self::fast_fourier_transform::{
3537
fast_fourier_transform, fast_fourier_transform_input_permutation,

src/sorting/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
### [Bitonic Sort](./bitonic_sort.rs)
2+
3+
Bitonic Sort is an efficient sorting algorithm based on the bitonic sequence concept and is often used in parallel processing due to its regular and repetitive structure. It works by first sorting sub-arrays in different directions and then combining them in a special merging process, ensuring a fully sorted array. This algorithm is particularly efficient when dealing with data sets whose size is a power of two.
4+
5+
* Parallel Processing: Bitonic sort is highly parallelizable, making it suitable for multi-threading and distributed systems, a strength that Rust can capitalize on with its robust concurrency features.
6+
* Recursive Strategy: The algorithm uses recursive division of the array, which is elegantly handled in Rust with its strong support for recursion and memory safety.
7+
* Efficiency: For medium-sized arrays, especially in parallel computing environments, bitonic sort can be very efficient, leveraging Rust's performance capabilities.
8+
9+
__Properties__
10+
* Special Case Input: Bitonic sort is most efficient when the input size is a power of two.
11+
* Time Complexity: In the worst-case scenario, the time complexity of bitonic sort is O(n log² n).
12+
* Not-in-place Sorting: While it doesn't sort in place, it requires less extra space compared to other non-in-place sorting algorithms.
13+
14+
__Sources to read:__
15+
* [Wikipedia](https://en.wikipedia.org/wiki/Bitonic_sorter)
16+
* [Geeksforgeeks](https://www.geeksforgeeks.org/bitonic-sort/)
17+
* [TutorialsPoint](https://www.tutorialspoint.com/bitonic-sort-in-data-structure)
18+
119
### [Bogo Sort](./bogo_sort.rs)
220

321
From [Wikipedia][bogosort-wiki]: In computer science, bogosort (also known as permutation sort, stupid sort, slowsort or bozosort) is a sorting algorithm based on the generate and test paradigm. The function successively generates permutations of its input until it finds one that is sorted. It is not considered useful for sorting, but may be used for educational purposes, to contrast it with more efficient algorithms.
@@ -6,6 +24,18 @@ Two versions of this algorithm exist: a deterministic version that enumerates al
624

725
[bogosort-wiki]:https://en.wikipedia.org/wiki/Bogosort
826

27+
### [Bogo-Bogo-sort](./bogo_bogo_sort.rs)
28+
From [leonardini.dev][bogo-bogo-doc]: BogoBogo Sort is a humorously inefficient sorting
29+
algorithm inspired by the original Bogosort. It adds a layer of complexity by recursively
30+
sorting the first n-1 elements before placing the nth element. This process is repeated until
31+
the array is sorted. The algorithm's performance is exceptionally poor, making it impractical
32+
for sorting but a useful tool for educational purposes, especially in understanding
33+
algorithm efficiency and recursive functions.
34+
__Properties__
35+
* Worst case performance (unbounded, extremely poor)
36+
* Best case performance O(n!)
37+
* Average case performance (unpredictable and impractical)
38+
939
### [Bucket_Sort](./bucket_sort.rs)
1040

1141
From [Wikipedia][bucketsort-wiki]: Bucket sort, or bin sort, is a sorting algorithm that works by distributing the elements of an array into a number of buckets. Each bucket is then sorted individually, either using a different sorting algorithm, or by recursively applying the bucket sorting algorithm. It is a distribution sort, a generalization of pigeonhole sort that allows multiple keys per bucket, and is a cousin of radix sort in the most-to-least significant digit flavor. Bucket sort can be implemented with comparisons and therefore can also be considered a comparison sort algorithm. The computational complexity depends on the algorithm used to sort each bucket, the number of buckets to use, and whether the input is uniformly distributed.
@@ -238,5 +268,59 @@ __Sources to read:__
238268
* [Geeksforgeeks](https://www.geeksforgeeks.org/insertion-sort/)
239269
* [Programiz](https://www.programiz.com/dsa/insertion-sort)
240270

271+
### [Strand Sort](./strand_sort.rs)
272+
273+
Strand Sort is a sorting algorithm that works by repeatedly pulling sorted sublists out of the list to be sorted and merging them with the already sorted part. It is particularly effective for sorting lists where there are large numbers of ordered elements. The algorithm is intuitive and simple, iterating through the list, picking up elements in order, and merging these 'strands' into a final sorted list.
274+
275+
* Simplicity: The algorithm is straightforward and easy to implement, making it a good choice for introductory sorting algorithm education.
276+
* Adaptive: Strand sort performs well on lists that are already partially sorted, as it can quickly identify and extract these ordered sublists.
277+
* In-place Sorting: The nature of the algorithm allows it to be implemented in an in-place fashion, although this is not always the case.
278+
279+
![Alt text](image-7.png)
280+
281+
__Properties__
282+
* Not-in-place Sorting: Typically, strand sort requires additional space for the strands, though in-place variants exist.
283+
* Time Complexity: The average and worst-case time complexity of strand sort can vary greatly depending on the input but typically is O(n²).
284+
* Stability: The algorithm is stable, maintaining the relative order of equal elements.
285+
286+
__Sources to read:__
287+
* [Wikipedia](https://en.wikipedia.org/wiki/Strand_sort)
288+
* [Geeksforgeeks](https://www.geeksforgeeks.org/strand-sort/)
289+
* [Tutorialspoint](https://www.tutorialspoint.com/strand-sort-in-data-structure)
290+
291+
## Pigeonhole Sort Implementation in Rust
292+
293+
Pigeonhole Sort is a sorting algorithm that is efficient for sorting data with a known, limited range of key values. It works by creating an array of 'holes' (each representing a position in the range of the data) and then sorting the data by 'placing' each item into its corresponding hole. The algorithm then collects the items from each hole in order, resulting in a sorted array.
294+
295+
### Rust Implementation
296+
The Rust implementation of Pigeonhole Sort involves the following steps:
297+
298+
* Initialization: First, it checks if the input array is empty. If so, it returns immediately as there's nothing to sort.
299+
300+
* Finding the Range: The implementation identifies the minimum and maximum values in the array. The range is the difference between these values plus one.
301+
302+
* Creating Holes: A vector of vectors (`Vec<Vec<i32>>`) is created to represent the holes. The size of this outer vector is equal to the range of the input data.
303+
304+
* Filling the Holes: The algorithm iterates over each element in the array, placing it into the corresponding hole based on its value.
305+
306+
* Reconstructing the Array: Finally, it iterates over the holes in order, placing each element back into the original array, now sorted.
307+
308+
### [Tree Sort](./tree_sort.rs)
309+
310+
Tree Sort is a sorting algorithm that builds a binary search tree from the elements of the array to be sorted and then performs an in-order traversal to generate a sorted array. The essence of tree sort lies in leveraging the properties of a binary search tree, where elements are inserted in such a way that for any given node, all elements in the left subtree are less than the node and all elements in the right subtree are greater.
311+
312+
* Safety: Rust’s adherence to memory safety is a significant asset in the implementation of tree sort. The algorithm makes use of Rust's ownership and borrowing rules to manage the tree structure without the risk of memory leaks or dangling pointers.
313+
* Tree Construction: Rust’s powerful data handling capabilities facilitate the efficient construction and manipulation of the binary search tree, a crucial aspect of tree sort.
314+
* Performance: While not the most efficient in all cases, tree sort in Rust can be quite performant especially for datasets that are not large, thanks to Rust's optimization capabilities.
315+
316+
![Alt text](image-5.png)
317+
318+
__Properties__
319+
* Not-in-place sorting: Tree sort requires additional memory for the binary search tree, hence it's not an in-place sorting algorithm.
320+
* Time complexity: The average case time complexity of tree sort is O(n log n), but it can degrade to O(n²) in the worst case when the tree becomes unbalanced.
321+
322+
__Sources to read:__
323+
* [Wikipedia](https://en.wikipedia.org/wiki/Tree_sort)
324+
* [Geeksforgeeks](https://www.geeksforgeeks.org/tree-sort/)
241325

242326

src/sorting/bitonic_sort.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
pub fn bitonic_sort(up: bool, x: &mut [i32]) {
2+
if x.len() <= 1 {
3+
return;
4+
}
5+
6+
let mid = x.len() / 2;
7+
let (first, second) = x.split_at_mut(mid);
8+
bitonic_sort(true, first);
9+
bitonic_sort(false, second);
10+
11+
bitonic_merge(up, x);
12+
}
13+
14+
pub struct BitonicSort;
15+
16+
fn bitonic_merge(up: bool, x: &mut [i32]) {
17+
if x.len() <= 1 {
18+
return;
19+
}
20+
21+
let mid = x.len() / 2;
22+
for i in 0..mid {
23+
if up == (x[i] > x[mid + i]) {
24+
x.swap(i, mid + i);
25+
}
26+
}
27+
28+
let (first, second) = x.split_at_mut(mid);
29+
bitonic_merge(up, first);
30+
bitonic_merge(up, second);
31+
}
32+
33+
#[cfg(test)]
34+
mod tests {
35+
use super::*;
36+
37+
#[test]
38+
fn test_bitonic_sort() {
39+
let mut numbers = vec![10, 30, 11, 20, 4, 330, 21, 110];
40+
bitonic_sort(true, &mut numbers);
41+
assert_eq!(numbers, vec![4, 10, 11, 20, 21, 30, 110, 330]);
42+
}
43+
44+
#[test]
45+
fn test_bitonic_sort_empty() {
46+
let mut numbers = vec![];
47+
bitonic_sort(true, &mut numbers);
48+
assert_eq!(numbers, vec![]);
49+
}
50+
51+
#[test]
52+
fn test_bitonic_sort_one_element() {
53+
let mut numbers = vec![10];
54+
bitonic_sort(true, &mut numbers);
55+
assert_eq!(numbers, vec![10]);
56+
}
57+
58+
#[test]
59+
fn test_bitonic_sort_two_elements() {
60+
let mut numbers = vec![10, 30];
61+
bitonic_sort(true, &mut numbers);
62+
assert_eq!(numbers, vec![10, 30]);
63+
}
64+
65+
#[test]
66+
fn test_error_bitonic_sort() {
67+
let mut numbers = vec![10, 30, 11, 20, 4, 330, 21, 110];
68+
bitonic_sort(true, &mut numbers);
69+
assert_ne!(numbers, vec![10, 4, 11, 20, 21, 30, 110, 330]);
70+
}
71+
72+
#[test]
73+
fn test_bitonic_merge_empty() {
74+
let mut numbers = vec![];
75+
bitonic_merge(true, &mut numbers);
76+
assert_eq!(numbers, vec![]);
77+
}
78+
79+
#[test]
80+
fn test_bitonic_merge_one_element() {
81+
let mut numbers = vec![10];
82+
bitonic_merge(true, &mut numbers);
83+
assert_eq!(numbers, vec![10]);
84+
}
85+
}

src/sorting/bogo_bogo_sort.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use rand::seq::SliceRandom;
2+
use rand::thread_rng;
3+
4+
fn is_sorted<T: Ord>(arr: &[T]) -> bool {
5+
arr.windows(2).all(|w| w[0] <= w[1])
6+
}
7+
8+
pub struct BogoBogoSort;
9+
10+
pub fn bogo_bogo_sort<T: Ord + Clone>(arr: &[T]) -> Vec<T> {
11+
if arr.len() <= 1 {
12+
return arr.to_vec();
13+
}
14+
15+
let mut rng = thread_rng();
16+
let mut sorted_subarray = bogo_bogo_sort(&arr[..arr.len() - 1]);
17+
18+
let mut extended_array = sorted_subarray.clone();
19+
extended_array.push(arr[arr.len() - 1].clone());
20+
21+
while !is_sorted(&extended_array)
22+
|| extended_array[arr.len() - 1] < *sorted_subarray.iter().max().unwrap()
23+
{
24+
extended_array.shuffle(&mut rng);
25+
sorted_subarray = bogo_bogo_sort(&extended_array[..arr.len() - 1]);
26+
extended_array = sorted_subarray.clone();
27+
extended_array.push(arr[arr.len() - 1].clone());
28+
}
29+
30+
extended_array
31+
}
32+
33+
#[cfg(test)]
34+
mod tests {
35+
use super::*;
36+
use crate::sorting::BogoSort;
37+
38+
#[test]
39+
fn test_sorted_array() {
40+
let arr = vec![1, 2, 3, 4, 5];
41+
assert!(is_sorted(&bogo_bogo_sort(&arr)));
42+
}
43+
44+
#[test]
45+
fn test_reverse_sorted_array() {
46+
let arr = vec![5, 4, 3, 2, 1];
47+
assert!(is_sorted(&bogo_bogo_sort(&arr)));
48+
}
49+
50+
#[test]
51+
fn test_unsorted_array() {
52+
let arr = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
53+
assert!(is_sorted(&bogo_bogo_sort(&arr)));
54+
}
55+
56+
#[test]
57+
fn test_empty_array() {
58+
let arr: Vec<i32> = vec![];
59+
assert!(is_sorted(&bogo_bogo_sort(&arr)));
60+
}
61+
}

src/sorting/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ where
2121
}
2222

2323
mod bingo_sort;
24+
mod bitonic_sort;
25+
mod bogo_bogo_sort;
2426
mod bogo_sort;
2527
mod bubble_sort;
2628
mod bucket_sort;
@@ -35,18 +37,23 @@ mod insertion_sort;
3537
mod merge_sort;
3638
mod odd_even_sort;
3739
mod pancake_sort;
40+
mod pigeonhole_sort;
3841
mod quick_sort;
3942
mod radix_sort;
4043
mod selection_sort;
4144
mod shell_sort;
4245
mod sleep_sort;
4346
mod stooge_sort;
47+
mod strand_sort;
4448
mod tim_sort;
4549
mod traits;
50+
mod tree_sort;
4651

4752
use std::fmt;
4853

4954
pub use self::bingo_sort::bingo_sort;
55+
pub use self::bitonic_sort::bitonic_sort;
56+
pub use self::bogo_bogo_sort::BogoBogoSort;
5057
pub use self::bogo_sort::BogoSort;
5158
pub use self::bubble_sort::BubbleSort;
5259
pub use self::bucket_sort::BucketSort;
@@ -61,13 +68,16 @@ pub use self::insertion_sort::InsertionSort;
6168
pub use self::merge_sort::MergeSort;
6269
pub use self::odd_even_sort::OddEvenSort;
6370
pub use self::pancake_sort::PancakeSort;
71+
pub use self::pigeonhole_sort::pigeonhole_sort;
6472
pub use self::quick_sort::QuickSort;
6573
pub use self::radix_sort::RadixSort;
6674
pub use self::selection_sort::SelectionSort;
6775
pub use self::shell_sort::ShellSort;
6876
pub use self::sleep_sort::sleep_sort;
6977
pub use self::stooge_sort::StoogeSort;
78+
pub use self::strand_sort::strand_sort;
7079
pub use self::tim_sort::TimSort;
80+
pub use self::tree_sort::TreeSort;
7181

7282
#[cfg(test)]
7383
mod tests {

0 commit comments

Comments
 (0)