Skip to content

Commit

Permalink
Rework sorting (#297)
Browse files Browse the repository at this point in the history
## Pull Request type
Please check the type of change your PR introduces:

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [x] Refactoring (no functional changes, no API changes)
- [ ] Build-related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

Rework the sorting package to introduce a common API that all sorting
algorithm should follow from now on.
BREAKING CHANGES: API
  • Loading branch information
gaetbout authored Apr 25, 2024
1 parent d68d46c commit 22349af
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 220 deletions.
67 changes: 36 additions & 31 deletions src/sorting/src/bubble_sort.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,44 @@
/// * `array` - Array to sort
/// # Returns
/// * `Array<usize>` - Sorted array
pub fn bubble_sort_elements<T, +Copy<T>, +Drop<T>, +PartialOrd<T>, +PartialEq<T>>(
mut array: Array<T>, asc: bool
) -> Array<T> {
if array.len() <= 1 {
return array;
}
let mut idx1 = 0;
let mut idx2 = 1;
let mut sorted_iteration = 0;
let mut sorted_array = array![];
use super::Sortable;

pub impl BubbleSort of Sortable {
fn sort<T, +Copy<T>, +Drop<T>, +PartialOrd<T>>(mut array: Span<T>) -> Array<T> {
if array.len() == 0 {
return array![];
}
if array.len() == 1 {
return array![*array[0]];
}
let mut idx1 = 0;
let mut idx2 = 1;
let mut sorted_iteration = true;
let mut sorted_array = array![];

loop {
if idx2 == array.len() {
sorted_array.append(*array[idx1]);
if sorted_iteration == 0 {
break;
}
array = sorted_array;
sorted_array = array![];
idx1 = 0;
idx2 = 1;
sorted_iteration = 0;
} else {
if (*array[idx1] == *array[idx2]) || !((asc) ^ (*array[idx1] < *array[idx2])) {
loop {
if idx2 == array.len() {
sorted_array.append(*array[idx1]);
idx1 = idx2;
idx2 += 1;
if sorted_iteration {
break;
}
array = sorted_array.span();
sorted_array = array![];
idx1 = 0;
idx2 = 1;
sorted_iteration = true;
} else {
sorted_array.append(*array[idx2]);
idx2 += 1;
sorted_iteration = 1;
}
if *array[idx1] <= *array[idx2] {
sorted_array.append(*array[idx1]);
idx1 = idx2;
idx2 += 1;
} else {
sorted_array.append(*array[idx2]);
idx2 += 1;
sorted_iteration = false;
}
};
};
};
sorted_array
sorted_array
}
}
11 changes: 11 additions & 0 deletions src/sorting/src/interface.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use alexandria_data_structures::vec::{Felt252Vec, VecTrait};

pub trait Sortable {
fn sort<T, +Copy<T>, +Drop<T>, +PartialOrd<T>>(array: Span<T>) -> Array<T>;
}

pub trait SortableVec {
fn sort<T, +Copy<T>, +Drop<T>, +PartialOrd<T>, +Felt252DictValue<T>>(
array: Felt252Vec<T>
) -> Felt252Vec<T>;
}
14 changes: 7 additions & 7 deletions src/sorting/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
pub mod bubble_sort;
pub mod merge_sort;
mod bubble_sort;
pub mod interface;
mod merge_sort;
pub mod quick_sort;

#[cfg(test)]
mod tests;

use bubble_sort::bubble_sort_elements;
use merge_sort::merge;
// use quick_sort::quick_sort; // Cannot do as name collide.

pub use bubble_sort::BubbleSort;
pub use interface::{Sortable, SortableVec};
pub use merge_sort::MergeSort;
pub use quick_sort::QuickSort;

72 changes: 23 additions & 49 deletions src/sorting/src/merge_sort.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,32 @@
/// * `arr` - Array to sort
/// # Returns
/// * `Array<T>` - Sorted array
pub fn merge<T, +Copy<T>, +Drop<T>, +PartialOrd<T>>(mut arr: Array<T>) -> Array<T> {
let len = arr.len();
if len <= 1 {
return arr;
}

// Create left and right arrays
let middle = len / 2;
let (mut left_arr, mut right_arr) = split_array(ref arr, middle);
use super::Sortable;

pub impl MergeSort of Sortable {
fn sort<T, +Copy<T>, +Drop<T>, +PartialOrd<T>>(mut array: Span<T>) -> Array<T> {
let len = array.len();
if len == 0 {
return array![];
}
if len == 1 {
return array![*array[0]];
}

// Create left and right arrays
let middle = len / 2;
let left_arr = array.slice(0, middle);
let right_arr = array.slice(middle, len - middle);

// Recursively sort the left and right arrays
let sorted_left = merge(left_arr);
let sorted_right = merge(right_arr);
// Recursively sort the left and right arrays
let sorted_left = MergeSort::sort(left_arr);
let sorted_right = MergeSort::sort(right_arr);

let mut result_arr = array![];
merge_recursive(sorted_left, sorted_right, ref result_arr, 0, 0);
result_arr
let mut result_arr = array![];
merge_recursive(sorted_left, sorted_right, ref result_arr, 0, 0);
result_arr
}
}

// Merge two sorted arrays
Expand Down Expand Up @@ -62,38 +71,3 @@ fn merge_recursive<T, +Copy<T>, +Drop<T>, +PartialOrd<T>>(
merge_recursive(left_arr, right_arr, ref result_arr, left_arr_ix, right_arr_ix + 1)
}
}

// Split an array into two arrays.
/// * `arr` - The array to split.
/// * `index` - The index to split the array at.
/// # Returns
/// * `(Array<T>, Array<T>)` - The two arrays.
fn split_array<T, +Copy<T>, +Drop<T>>(ref arr: Array<T>, index: usize) -> (Array<T>, Array<T>) {
let mut arr1 = array![];
let mut arr2 = array![];
let len = arr.len();

fill_array(ref arr1, ref arr, 0_u32, index);
fill_array(ref arr2, ref arr, index, len - index);

(arr1, arr2)
}

// Fill an array with a value.
/// * `arr` - The array to fill.
/// * `fill_arr` - The array to fill with.
/// * `index` - The index to start filling at.
/// * `count` - The number of elements to fill.
/// # Returns
/// * `Array<T>` - The filled array.
fn fill_array<T, +Copy<T>, +Drop<T>>(
ref arr: Array<T>, ref fill_arr: Array<T>, index: usize, count: usize
) {
if count == 0 {
return;
}

arr.append(*fill_arr[index]);

fill_array(ref arr, ref fill_arr, index + 1, count - 1)
}
24 changes: 14 additions & 10 deletions src/sorting/src/quick_sort.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,24 @@ use alexandria_data_structures::vec::{Felt252Vec, VecTrait};
/// * `Felt252Vec<T>` - Array to sort
/// # Returns
/// * `Felt252Vec<T>` - Sorted array
pub fn quick_sort<T, +Copy<T>, +Drop<T>, +PartialOrd<T>, +PartialEq<T>, +Felt252DictValue<T>>(
mut array: Felt252Vec<T>
) -> Felt252Vec<T> {
let array_size = array.len();
if array_size <= 1 {

use super::SortableVec;

pub impl QuickSort of SortableVec {
fn sort<T, +Copy<T>, +Drop<T>, +PartialOrd<T>, +Felt252DictValue<T>>(
mut array: Felt252Vec<T>
) -> Felt252Vec<T> {
let array_size = array.len();
if array_size <= 1 {
return array;
}
quick_sort_range(ref array, 0, array_size - 1);

return array;
}
quick_sort_range(ref array, 0, array_size - 1);

return array;
}


fn quick_sort_range<T, +Copy<T>, +Drop<T>, +PartialOrd<T>, +PartialEq<T>, +Felt252DictValue<T>>(
fn quick_sort_range<T, +Copy<T>, +Drop<T>, +PartialOrd<T>, +Felt252DictValue<T>>(
ref array: Felt252Vec<T>, left: usize, right: usize
) {
if left >= right {
Expand Down
Loading

0 comments on commit 22349af

Please sign in to comment.