Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strand sort #666

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions src/math/derrivative_method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
pub fn derivative_method<F>(x: f64, y: f64, f: F) -> f64
where
F: Fn(f64, f64) -> f64,
{
let h = 0.0001;
(f(x + h, y) - f(x, y)) / h
}

fn test_function(x: f64, y: f64) -> f64 {
x.powi(2) + y.powi(2)
}

#[allow(dead_code)]
fn main() {
let x = 1.0;
let y = 2.0;
let f = test_function;
let df_dx = derivative_method(x, y, f);
let df_dy = derivative_method(y, x, f);
println!("df/dx = {}", df_dx);
println!("df/dy = {}", df_dy);
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_derivative() {
let x = 1.0;
let y = 2.0;
let f = test_function;
let df_dx = derivative_method(x, y, f);
let df_dy = derivative_method(y, x, f);
assert_eq!(df_dx, 2.000100000003613);
assert_eq!(df_dy, 4.0001000000078335);
}

#[test]
fn test_error() {
let x = 1.0;
let y = 2.0;
let f = test_function;
let df_dx = derivative_method(x, y, f);
let df_dy = derivative_method(y, x, f);
assert_ne!(df_dx, 2.0);
assert_ne!(df_dy, 4.0);
}

#[test]
fn test_nan() {
let x = 1.0;
let y = 2.0;
let f = test_function;
let df_dx = derivative_method(x, y, f);
let df_dy = derivative_method(y, x, f);
assert!(!df_dx.is_nan());
assert!(!df_dy.is_nan());
}

#[test]
fn test_inf() {
let x = 1.0;
let y = 2.0;
let f = test_function;
let df_dx = derivative_method(x, y, f);
let df_dy = derivative_method(y, x, f);
assert!(!df_dx.is_infinite());
assert!(!df_dy.is_infinite());
}

#[test]
fn test_zero() {
let x = 1.0;
let y = 2.0;
let f = test_function;
let df_dx = derivative_method(x, y, f);
let df_dy = derivative_method(y, x, f);
assert_ne!(df_dx, 0.0);
assert_ne!(df_dy, 0.0);
}

#[test]
fn test_subnormal() {
let x = 1.0;
let y = 2.0;
let f = test_function;
let df_dx = derivative_method(x, y, f);
let df_dy = derivative_method(y, x, f);
assert!(!df_dx.is_subnormal());
assert!(!df_dy.is_subnormal());
}
}
2 changes: 2 additions & 0 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod collatz_sequence;
mod combinations;
mod cross_entropy_loss;
mod decimal_to_fraction;
mod derrivative_method;
mod doomsday;
mod elliptic_curve;
mod euclidean_distance;
Expand Down Expand Up @@ -98,6 +99,7 @@ pub use self::collatz_sequence::sequence;
pub use self::combinations::combinations;
pub use self::cross_entropy_loss::cross_entropy_loss;
pub use self::decimal_to_fraction::decimal_to_fraction;
pub use self::derrivative_method::derivative_method;
pub use self::doomsday::get_week_day;
pub use self::elliptic_curve::EllipticCurve;
pub use self::euclidean_distance::euclidean_distance;
Expand Down
27 changes: 26 additions & 1 deletion src/sorting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ __Properties__
* Best case performance O(n)
* Average case performance O((n+1)!)

### [Bogo-Bogo-sort](./bogo_bogo_sort.rs)
From [leonardini.dev][bogo-bogo-doc]: BogoBogo Sort is a humorously inefficient sorting
algorithm inspired by the original Bogosort. It adds a layer of complexity by recursively
sorting the first n-1 elements before placing the nth element. This process is repeated until
the array is sorted. The algorithm's performance is exceptionally poor, making it impractical
for sorting but a useful tool for educational purposes, especially in understanding
algorithm efficiency and recursive functions.

__Properties__
* Worst case performance (unbounded, extremely poor)
* Best case performance O(n!)
* Average case performance (unpredictable and impractical)

### [Bubble](./bubble_sort.rs)
![alt text][bubble-image]
Expand Down Expand Up @@ -203,7 +215,20 @@ This card game is turned into a two-phase sorting algorithm, as follows. Given a

__Properties__
* Worst case performance O(n log n)
* Best case performance O(n)
* Best case performance O(n)\
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Best case performance O(n)\
* Best case performance O(n)


### [Strand Sort](./strand_sort.rs)

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
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.


* Simplicity: The algorithm is straightforward and easy to implement, making it a good choice for introductory sorting algorithm education.
* Adaptive: Strand sort performs well on lists that are already partially sorted, as it can quickly identify and extract these ordered sublists.
* 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.

__Properties__
* Not-in-place Sorting: Typically, strand sort requires additional space for the strands, though in-place variants exist.
* Time Complexity: The average and worst-case time complexity of strand sort can vary greatly depending on the input but typically is O(n²).
* Stability: The algorithm is stable, maintaining the relative order of equal elements.

[bogo-wiki]: https://en.wikipedia.org/wiki/Bogosort
[bogo-image]: https://upload.wikimedia.org/wikipedia/commons/7/7b/Bogo_sort_animation.gif
Expand Down
58 changes: 58 additions & 0 deletions src/sorting/bogo_bogo_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use rand::seq::SliceRandom;
use rand::thread_rng;

fn is_sorted<T: Ord>(arr: &[T]) -> bool {
arr.windows(2).all(|w| w[0] <= w[1])
}

pub fn bogo_bogo_sort<T: Ord + Clone>(arr: &[T]) -> Vec<T> {
if arr.len() <= 1 {
return arr.to_vec();
}

let mut rng = thread_rng();
let mut sorted_subarray = bogo_bogo_sort(&arr[..arr.len() - 1]);

let mut extended_array = sorted_subarray.clone();
extended_array.push(arr[arr.len() - 1].clone());

while !is_sorted(&extended_array)
|| extended_array[arr.len() - 1] < *sorted_subarray.iter().max().unwrap()
{
extended_array.shuffle(&mut rng);
sorted_subarray = bogo_bogo_sort(&extended_array[..arr.len() - 1]);
extended_array = sorted_subarray.clone();
extended_array.push(arr[arr.len() - 1].clone());
}

extended_array
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_sorted_array() {
let arr = vec![1, 2, 3, 4, 5];
assert!(is_sorted(&bogo_bogo_sort(&arr)));
}

#[test]
fn test_reverse_sorted_array() {
let arr = vec![5, 4, 3, 2, 1];
assert!(is_sorted(&bogo_bogo_sort(&arr)));
}

#[test]
fn test_unsorted_array() {
let arr = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
assert!(is_sorted(&bogo_bogo_sort(&arr)));
}

#[test]
fn test_empty_array() {
let arr: Vec<i32> = vec![];
assert!(is_sorted(&bogo_bogo_sort(&arr)));
}
}
2 changes: 2 additions & 0 deletions src/sorting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mod sleep_sort;
#[cfg(test)]
mod sort_utils;
mod stooge_sort;
mod strand_sort;
mod tim_sort;
mod tree_sort;
mod wave_sort;
Expand Down Expand Up @@ -65,6 +66,7 @@ pub use self::selection_sort::selection_sort;
pub use self::shell_sort::shell_sort;
pub use self::sleep_sort::sleep_sort;
pub use self::stooge_sort::stooge_sort;
pub use self::strand_sort::strand_sort;
pub use self::tim_sort::tim_sort;
pub use self::tree_sort::tree_sort;
pub use self::wave_sort::wave_sort;
Expand Down
124 changes: 124 additions & 0 deletions src/sorting/strand_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use std::collections::LinkedList;

pub fn strand_sort(ip: &mut LinkedList<i32>, op: &mut LinkedList<i32>) {
if ip.is_empty() {
return;
}

let mut sublist = LinkedList::new();
sublist.push_back(ip.pop_front().unwrap());

let mut iter = ip.split_off(0);
while let Some(val) = iter.pop_front() {
if val > *sublist.back().unwrap() {
sublist.push_back(val);
} else {
ip.push_back(val);
}
}

// Merge current sublist into output
let mut merged = LinkedList::new();
while !op.is_empty() || !sublist.is_empty() {
match (op.front(), sublist.front()) {
(Some(&op_val), Some(&sub_val)) if op_val <= sub_val => {
merged.push_back(op.pop_front().unwrap());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is not covered by any test.

}
(_, Some(_)) => {
merged.push_back(sublist.pop_front().unwrap());
}
(Some(_), _) => {
merged.push_back(op.pop_front().unwrap());
}
(None, None) => break,
}
}

*op = merged;
strand_sort(ip, op);
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_strand_sort() {
let mut ip: LinkedList<i32> = LinkedList::from([10, 5, 30, 40, 2, 4, 9]);
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_eq!(op, LinkedList::from([2, 4, 5, 9, 10, 30, 40]));
}

#[test]
fn test_strand_sort_empty() {
let mut ip: LinkedList<i32> = LinkedList::new();
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_eq!(op, LinkedList::new());
}

#[test]
fn test_strand_sort_single() {
let mut ip: LinkedList<i32> = LinkedList::from([1]);
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_eq!(op, LinkedList::from([1]));
}

#[test]
fn test_strand_sort_negative() {
let mut ip: LinkedList<i32> = LinkedList::from([-1, -2, -3, -4, -5]);
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_eq!(op, LinkedList::from([-5, -4, -3, -2, -1]));
}

#[test]
fn test_strand_sort_duplicates() {
let mut ip: LinkedList<i32> = LinkedList::from([1, 1, 1, 1, 1]);
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_eq!(op, LinkedList::from([1, 1, 1, 1, 1]));
}

#[test]
fn test_strand_sort_error() {
let mut ip: LinkedList<i32> = LinkedList::from([1, 2, 3, 4, 5]);
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_ne!(op, LinkedList::from([2, 1, 3, 4, 5]));
}

#[test]
fn test_strand_sort_big() {
let mut ip: LinkedList<i32> = LinkedList::from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_eq!(op, LinkedList::from([1, 2, 3, 4, 5, 6, 7, 8, 9]));
}

#[test]
fn test_strand_sort_big_reverse() {
let mut ip: LinkedList<i32> = LinkedList::from([9, 8, 7, 6, 5, 4, 3, 2, 1]);
let mut op: LinkedList<i32> = LinkedList::new();

strand_sort(&mut ip, &mut op);

assert_eq!(op, LinkedList::from([1, 2, 3, 4, 5, 6, 7, 8, 9]));
}
}