Skip to content

Commit

Permalink
feat: make sorting mods consistent + misc minor fixes (alexfertel#61)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexander González <[email protected]>
  • Loading branch information
CodingTil and alexfertel authored Aug 12, 2023
1 parent 69232d8 commit 75c9d83
Show file tree
Hide file tree
Showing 24 changed files with 651 additions and 564 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
paste = "1.0.12"
97 changes: 54 additions & 43 deletions src/sorting/bogo_sort.rs
Original file line number Diff line number Diff line change
@@ -1,65 +1,76 @@
use super::traits::MutableSorter;
use crate::math::PCG32;
use crate::sorting::traits::Sorter;
use std::time::{SystemTime, UNIX_EPOCH};

const DEFAULT: u64 = 4294967296;
const DEFAULT: u64 = 2 << 31; // 2^32

pub struct BogoSort;
fn is_sorted<T: Ord>(arr: &[T], len: usize) -> bool {
if len <= 1 {
return true;
}

impl BogoSort {
fn is_sorted<T: Ord>(arr: &[T], len: usize) -> bool {
for i in 0..len - 1 {
if arr[i] > arr[i + 1] {
return false;
}
for i in 0..len - 1 {
if arr[i] > arr[i + 1] {
return false;
}

true
}
#[cfg(target_pointer_width = "64")]
fn generate_index(range: usize, generator: &mut PCG32) -> usize {
generator.get_u64() as usize % range
}

#[cfg(not(target_pointer_width = "64"))]
fn generate_index(range: usize, generator: &mut PCG32) -> usize {
generator.get_u32() as usize % range
true
}
#[cfg(target_pointer_width = "64")]
fn generate_index(range: usize, generator: &mut PCG32) -> usize {
generator.get_u64() as usize % range
}

#[cfg(not(target_pointer_width = "64"))]
fn generate_index(range: usize, generator: &mut PCG32) -> usize {
generator.get_u32() as usize % range
}

/**
* Fisher–Yates shuffle for generating random permutation.
*/
fn permute_randomly<T>(arr: &mut [T], len: usize, generator: &mut PCG32) {
if len <= 1 {
return;
}

/**
* Fisher–Yates shuffle for generating random permutation.
*/
fn permute_randomly<T>(arr: &mut [T], len: usize, generator: &mut PCG32) {
for i in (1..len).rev() {
let j = BogoSort::generate_index(i + 1, generator);
arr.swap(i, j);
}
for i in (1..len).rev() {
let j = generate_index(i + 1, generator);
arr.swap(i, j);
}
}

impl<T> MutableSorter<T> for BogoSort {
fn sort(arr: &mut [T])
where
T: Ord,
{
let seed = match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(duration) => duration.as_millis() as u64,
Err(_) => DEFAULT,
};
fn bogo_sort<T: Ord>(arr: &mut [T]) {
let seed = match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(duration) => duration.as_millis() as u64,
Err(_) => DEFAULT,
};

let mut random_generator = PCG32::new_default(seed);
let mut random_generator = PCG32::new_default(seed);

let arr_length = arr.len();
while !BogoSort::is_sorted(arr, arr_length) {
BogoSort::permute_randomly(arr, arr_length, &mut random_generator);
}
let arr_length = arr.len();
while !is_sorted(arr, arr_length) {
permute_randomly(arr, arr_length, &mut random_generator);
}
}

pub struct BogoSort;

impl<T> Sorter<T> for BogoSort
where
T: Ord + Copy,
{
fn sort_inplace(arr: &mut [T]) {
bogo_sort(arr);
}
}

#[cfg(test)]
mod tests {
use super::super::traits::MutableSorter;
use super::BogoSort;
use crate::sorting::traits::Sorter;
use crate::sorting::BogoSort;

sorting_tests!(BogoSort::sort, inplace);
sorting_tests!(BogoSort::sort, bogo_sort);
sorting_tests!(BogoSort::sort_inplace, bogo_sort, inplace);
}
50 changes: 28 additions & 22 deletions src/sorting/bubble_sort.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
// It sorts the array by repeatedly comparing the
// adjacent elements and swapping them if they are
// in the wrong order.
// Time complexity is O(N^2)
// Auxiliary space is O(1)
use super::traits::MutableSorter;
use crate::sorting::traits::Sorter;

pub struct BubbleSort;

impl<T> MutableSorter<T> for BubbleSort {
fn sort(array: &mut [T])
where
T: Ord,
{
for i in 0..array.len() {
// Last i elements are already in place.
for j in 0..array.len() - 1 - i {
if array[j] > array[j + 1] {
array.swap(j, j + 1);
}
fn bubble_sort<T: Ord>(arr: &mut [T]) {
for i in 0..arr.len() {
// Last i elements are already in place.
for j in 0..arr.len() - 1 - i {
if arr[j] > arr[j + 1] {
arr.swap(j, j + 1);
}
}
}
}

/// It sorts the array by repeatedly comparing the
/// adjacent elements and swapping them if they are
/// in the wrong order.
/// Time complexity is O(N^2)
/// Auxiliary space is O(1)
pub struct BubbleSort;

impl<T> Sorter<T> for BubbleSort
where
T: Ord + Copy,
{
fn sort_inplace(array: &mut [T]) {
bubble_sort(array);
}
}

#[cfg(test)]
mod tests {
use super::super::traits::MutableSorter;
use super::BubbleSort;
sorting_tests!(BubbleSort::sort, inplace);
use crate::sorting::traits::Sorter;
use crate::sorting::BubbleSort;

sorting_tests!(BubbleSort::sort, bubble_sort);
sorting_tests!(BubbleSort::sort_inplace, bubble_sort, inplace);
}
69 changes: 31 additions & 38 deletions src/sorting/bucket_sort.rs
Original file line number Diff line number Diff line change
@@ -1,61 +1,54 @@
/// Sort a slice using bucket sort algorithm.
///
/// Time complexity is `O(n + k)` on average, where `n` is the number of elements,
/// `k` is the number of buckets used in process.
///
/// Space complexity is `O(n + k)`, as it sorts not in-place.
pub fn bucket_sort(arr: &[usize]) -> Vec<usize> {
use crate::sorting::insertion_sort::InsertionSort;
use crate::sorting::traits::Sorter;

fn bucket_sort<T: Ord + Copy + Into<usize>>(arr: &mut [T]) {
if arr.is_empty() {
return vec![];
return;
}

let max = *arr.iter().max().unwrap();
let len = arr.len();
let mut buckets = vec![vec![]; len + 1];

for x in arr {
buckets[len * *x / max].push(*x);
for x in arr.iter() {
buckets[len * (*x).into() / max.into()].push(*x);
}

for bucket in buckets.iter_mut() {
super::insertion_sort(bucket);
InsertionSort::sort_inplace(bucket);
}

let mut result = vec![];
let mut i = 0;
for bucket in buckets {
for x in bucket {
result.push(x);
arr[i] = x;
i += 1;
}
}
}

result
/// Sort a slice using bucket sort algorithm.
///
/// Time complexity is `O(n + k)` on average, where `n` is the number of elements,
/// `k` is the number of buckets used in process.
///
/// Space complexity is `O(n + k)`, as it sorts not in-place.
pub struct BucketSort;

impl<T> Sorter<T> for BucketSort
where
T: Ord + Copy + Into<usize>,
{
fn sort_inplace(arr: &mut [T]) {
bucket_sort(arr);
}
}

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

sorting_tests!(bucket_sort);
use crate::sorting::traits::Sorter;
use crate::sorting::BucketSort;

#[test]
fn empty() {
let arr: [usize; 0] = [];
let res = bucket_sort(&arr);
assert!(is_sorted(&res));
}

#[test]
fn one_element() {
let arr: [usize; 1] = [4];
let res = bucket_sort(&arr);
assert!(is_sorted(&res));
}

#[test]
fn odd_number_of_elements() {
let arr: Vec<usize> = vec![1, 21, 5, 11, 58];
let res = bucket_sort(&arr);
assert!(is_sorted(&res));
}
sorting_tests!(BucketSort::sort, bucket_sort);
sorting_tests!(BucketSort::sort_inplace, bucket_sort, inplace);
}
39 changes: 22 additions & 17 deletions src/sorting/cocktail_shaker_sort.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub fn cocktail_shaker_sort<T: Ord>(arr: &mut [T]) {
use crate::sorting::traits::Sorter;

fn cocktail_shaker_sort<T: Ord>(arr: &mut [T]) {
let len = arr.len();

if len == 0 {
Expand Down Expand Up @@ -34,23 +36,26 @@ pub fn cocktail_shaker_sort<T: Ord>(arr: &mut [T]) {
}
}

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

sorting_tests!(cocktail_shaker_sort, inplace);
pub struct CocktailShakerSort;

#[test]
fn empty() {
let mut arr = Vec::<i32>::new();
cocktail_shaker_sort(&mut arr);
assert_eq!(arr, vec![]);
impl<T> Sorter<T> for CocktailShakerSort
where
T: Ord + Copy,
{
fn sort_inplace(arr: &mut [T]) {
cocktail_shaker_sort(arr);
}
}

#[test]
fn one_element() {
let mut arr = vec![1];
cocktail_shaker_sort(&mut arr);
assert_eq!(arr, vec![1]);
}
#[cfg(test)]
mod tests {
use crate::sorting::traits::Sorter;
use crate::sorting::CocktailShakerSort;

sorting_tests!(CocktailShakerSort::sort, cocktail_shaker_sort);
sorting_tests!(
CocktailShakerSort::sort_inplace,
cocktail_shaker_sort,
inplace
);
}
Loading

0 comments on commit 75c9d83

Please sign in to comment.