Skip to content

Commit

Permalink
Add more sorting algorithms (#4)
Browse files Browse the repository at this point in the history
* add algorithms

* adjust operation indexes
  • Loading branch information
semihbkgr authored Feb 10, 2024
1 parent fccf389 commit cd4c439
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 15 deletions.
30 changes: 15 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,18 @@ impl AlgorithmUI {
result.push('\n');
}
let mut text = Text::raw(result);
match operation {
match operation.adjusted() {
Operation::Compare(a, b) => {
for line in text.lines.iter_mut() {
let line_content = line.spans[0].content.clone();
let line_chars = line_content.chars().into_iter().collect::<Vec<char>>();
let pre = Span::raw(line_chars[..*a].iter().collect::<String>());
let a_span = Span::raw(line_chars[*a..*a + 1].iter().collect::<String>())
let pre = Span::raw(line_chars[..a].iter().collect::<String>());
let a_span = Span::raw(line_chars[a..a + 1].iter().collect::<String>())
.fg(Color::LightCyan);
let mid = Span::raw(line_chars[*a + 1..*b].iter().collect::<String>());
let b_span = Span::raw(line_chars[*b..*b + 1].iter().collect::<String>())
let mid = Span::raw(line_chars[a + 1..b].iter().collect::<String>());
let b_span = Span::raw(line_chars[b..b + 1].iter().collect::<String>())
.fg(Color::LightCyan);
let last = Span::raw(line_chars[*b + 1..].iter().collect::<String>());
let last = Span::raw(line_chars[b + 1..].iter().collect::<String>());

line.spans = vec![pre, a_span, mid, b_span, last];
}
Expand All @@ -156,13 +156,13 @@ impl AlgorithmUI {
for line in text.lines.iter_mut() {
let line_content = line.spans[0].content.clone();
let line_chars = line_content.chars().into_iter().collect::<Vec<char>>();
let pre = Span::raw(line_chars[..*a].iter().collect::<String>());
let a_span = Span::raw(line_chars[*a..*a + 1].iter().collect::<String>())
let pre = Span::raw(line_chars[..a].iter().collect::<String>());
let a_span = Span::raw(line_chars[a..a + 1].iter().collect::<String>())
.fg(Color::LightGreen);
let mid = Span::raw(line_chars[*a + 1..*b].iter().collect::<String>());
let b_span = Span::raw(line_chars[*b..*b + 1].iter().collect::<String>())
let mid = Span::raw(line_chars[a + 1..b].iter().collect::<String>());
let b_span = Span::raw(line_chars[b..b + 1].iter().collect::<String>())
.fg(Color::LightGreen);
let last = Span::raw(line_chars[*b + 1..].iter().collect::<String>());
let last = Span::raw(line_chars[b + 1..].iter().collect::<String>());

line.spans = vec![pre, a_span, mid, b_span, last];
}
Expand All @@ -171,10 +171,10 @@ impl AlgorithmUI {
for line in text.lines.iter_mut() {
let line_content = line.spans[0].content.clone();
let line_chars = line_content.chars().into_iter().collect::<Vec<char>>();
let pre = Span::raw(line_chars[..*i].iter().collect::<String>());
let span = Span::raw(line_chars[*i..*i + 1].iter().collect::<String>())
let pre = Span::raw(line_chars[..i].iter().collect::<String>());
let span = Span::raw(line_chars[i..i + 1].iter().collect::<String>())
.fg(Color::LightYellow);
let last = Span::raw(line_chars[*i + 1..].iter().collect::<String>());
let last = Span::raw(line_chars[i + 1..].iter().collect::<String>());

line.spans = vec![pre, span, last];
}
Expand Down Expand Up @@ -378,7 +378,7 @@ fn ui(frame: &mut Frame, app: &mut App) {

if !algorithm.auto_next {
let (step, operation) = algorithm.status.step_info();
let info = format!("step: {}\n{}", step, operation);
let info = format!("step: {}\n{}", step, operation.adjusted());
let text_info = Text::from(info);
let paragraph_info = Paragraph::new(text_info).alignment(Alignment::Left);
let next_area = next_area_vertical(area, 2, 1);
Expand Down
5 changes: 5 additions & 0 deletions src/sorting/bubble_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ pub const NAME: &str = "bubble sort";
pub fn sort(nums: &mut [i32], ctx: &dyn AlgorithmContext) {
let len = nums.len();
for i in 0..len {
let mut swapped = false;
for j in 0..len - i - 1 {
ctx.next(Compare(j, j + 1), nums.to_vec());
if nums[j] > nums[j + 1] {
nums.swap(j, j + 1);
ctx.next(Swap(j, j + 1), nums.to_vec());
swapped = true;
}
}
if !swapped {
break;
}
}
ctx.next(Noop(), nums.to_vec());
}
Expand Down
51 changes: 51 additions & 0 deletions src/sorting/comb_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use super::{
AlgorithmContext,
Operation::{Compare, Noop, Swap},
};

pub const NAME: &str = "comb sort";

pub fn sort(nums: &mut [i32], ctx: &dyn AlgorithmContext) {
let n = nums.len();
let mut gap = n;
let shrink_factor = 1.3;
let mut swapped = true;

while gap > 1 || swapped {
gap = (gap as f64 / shrink_factor).floor() as usize;
if gap < 1 {
gap = 1;
}

swapped = false;

for i in 0..n - gap {
let j = i + gap;
ctx.next(Compare(i, j), nums.to_vec());
if nums[i] > nums[j] {
nums.swap(i, j);
ctx.next(Swap(i, j), nums.to_vec());
swapped = true;
}
}
}

ctx.next(Noop(), nums.to_vec());
}

#[cfg(test)]
mod tests {
use crate::sorting::has_nums;
use crate::sorting::is_sorted;
use crate::sorting::NoopContext;

use super::*;

#[test]
fn test_sort() {
let nums = &mut [3, 5, 2, 8, 6, 9, 0, 1, 4, 7];
sort(nums, &NoopContext);
assert!(is_sorted(nums));
assert!(has_nums(nums));
}
}
62 changes: 62 additions & 0 deletions src/sorting/heap_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use super::{
AlgorithmContext,
Operation::{Compare, Noop, Swap},
};

pub const NAME: &str = "heap sort";

pub fn sort(nums: &mut [i32], ctx: &dyn AlgorithmContext) {
let n = nums.len();
for i in (0..n / 2).rev() {
heapify(nums, n, i, ctx);
}
for i in (1..n).rev() {
nums.swap(0, i);
ctx.next(Swap(0, i), nums.to_vec());
heapify(nums, i, 0, ctx);
}
ctx.next(Noop(), nums.to_vec());
}

fn heapify(nums: &mut [i32], n: usize, i: usize, ctx: &dyn AlgorithmContext) {
let mut largest = i;
let left = 2 * i + 1;
let right = 2 * i + 2;

if left < n {
ctx.next(Compare(left, largest), nums.to_vec());
if nums[left] > nums[largest] {
largest = left;
}
}

if right < n {
ctx.next(Compare(right, largest), nums.to_vec());
if nums[right] > nums[largest] {
largest = right;
}
}

if largest != i {
nums.swap(i, largest);
ctx.next(Swap(i, largest), nums.to_vec());
heapify(nums, n, largest, ctx);
}
}

#[cfg(test)]
mod tests {
use crate::sorting::has_nums;
use crate::sorting::is_sorted;
use crate::sorting::NoopContext;

use super::*;

#[test]
fn test_sort() {
let nums = &mut [3, 5, 2, 8, 6, 9, 0, 1, 4, 7];
sort(nums, &NoopContext);
assert!(is_sorted(nums));
assert!(has_nums(nums));
}
}
35 changes: 35 additions & 0 deletions src/sorting/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::fmt::Display;

pub mod bubble_sort;
pub mod comb_sort;
pub mod heap_sort;
pub mod insertion_sort;
pub mod merge_sort;
pub mod quick_sort;
pub mod selection_sort;
pub mod shell_sort;

pub trait AlgorithmContext {
fn next(&self, operation: Operation, nums: Vec<i32>);
Expand All @@ -17,6 +21,29 @@ pub enum Operation {
Insert(usize),
}

impl Operation {
pub fn adjusted(&self) -> Self {
return match *self {
Self::Compare(a, b) => {
if a > b {
Self::Compare(b, a)
} else {
Self::Compare(a, b)
}
}
Self::Swap(a, b) => {
if a > b {
Self::Swap(b, a)
} else {
Self::Swap(a, b)
}
}
Self::Insert(i) => return Self::Insert(i),
Self::Noop() => return Self::Noop(),
};
}
}

impl Display for Operation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand All @@ -40,6 +67,10 @@ pub fn get_algorithms() -> Vec<&'static str> {
selection_sort::NAME,
insertion_sort::NAME,
merge_sort::NAME,
shell_sort::NAME,
heap_sort::NAME,
quick_sort::NAME,
comb_sort::NAME,
];
}

Expand All @@ -49,6 +80,10 @@ pub fn get_algorithm_func<'a>(s: &str) -> impl FnOnce(&mut [i32], &dyn Algorithm
selection_sort::NAME => selection_sort::sort,
insertion_sort::NAME => insertion_sort::sort,
merge_sort::NAME => merge_sort::sort,
shell_sort::NAME => shell_sort::sort,
heap_sort::NAME => heap_sort::sort,
quick_sort::NAME => quick_sort::sort,
comb_sort::NAME => comb_sort::sort,
_ => panic!("algorithm not found"),
}
}
Expand Down
63 changes: 63 additions & 0 deletions src/sorting/quick_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use super::{
AlgorithmContext,
Operation::{Compare, Noop, Swap},
};

pub const NAME: &str = "quick sort";

pub fn sort(nums: &mut [i32], ctx: &dyn AlgorithmContext) {
quick_sort_recursive(nums, 0, nums.len() - 1, ctx);
ctx.next(Noop(), nums.to_vec());
}

fn quick_sort_recursive(nums: &mut [i32], low: usize, high: usize, ctx: &dyn AlgorithmContext) {
if low < high {
let pivot_index = partition(nums, low, high, ctx);

if pivot_index > 0 {
quick_sort_recursive(nums, low, pivot_index - 1, ctx);
}

quick_sort_recursive(nums, pivot_index + 1, high, ctx);
}
}

fn partition(nums: &mut [i32], low: usize, high: usize, ctx: &dyn AlgorithmContext) -> usize {
let pivot = nums[high];
let mut i = low;

for j in low..high {
ctx.next(Compare(j, high), nums.to_vec());
if nums[j] <= pivot {
if i != j {
nums.swap(i, j);
ctx.next(Swap(i, j), nums.to_vec());
}
i += 1;
}
}

if i != high {
nums.swap(i, high);
ctx.next(Swap(i, high), nums.to_vec());
}

return i;
}

#[cfg(test)]
mod tests {
use crate::sorting::has_nums;
use crate::sorting::is_sorted;
use crate::sorting::NoopContext;

use super::*;

#[test]
fn test_sort() {
let nums = &mut [3, 5, 2, 8, 6, 9, 0, 1, 4, 7];
sort(nums, &NoopContext);
assert!(is_sorted(nums));
assert!(has_nums(nums));
}
}
45 changes: 45 additions & 0 deletions src/sorting/shell_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use super::{
AlgorithmContext,
Operation::{Compare, Noop, Swap},
};

pub const NAME: &str = "shell sort";

pub fn sort(nums: &mut [i32], ctx: &dyn AlgorithmContext) {
let n = nums.len();
let mut gap = n / 2;
while gap > 0 {
for i in gap..n {
let mut j = i;
while j >= gap {
ctx.next(Compare(j - gap, j), nums.to_vec());
if nums[j - gap] > nums[j] {
nums.swap(j - gap, j);
ctx.next(Swap(j - gap, j), nums.to_vec());
j -= gap;
} else {
break;
}
}
}
gap /= 2;
}
ctx.next(Noop(), nums.to_vec());
}

#[cfg(test)]
mod tests {
use crate::sorting::has_nums;
use crate::sorting::is_sorted;
use crate::sorting::NoopContext;

use super::*;

#[test]
fn test_sort() {
let nums = &mut [3, 5, 2, 8, 6, 9, 0, 1, 4, 7];
sort(nums, &NoopContext);
assert!(is_sorted(nums));
assert!(has_nums(nums));
}
}

0 comments on commit cd4c439

Please sign in to comment.