2

Obviously, the std library implementation is always going to be far faster than mine, but this takes 3 minutes or so to complete for a 773 x 1031 image on a fast computer. Using the same comparator, the standard library takes 4 seconds to sort the entire image. Any ideas why my code is so slow?

fn partial_quick_sort(img: &mut Bitmap, cmp: &BoxedPixelComparator) {
    // buffer is a Vec of Pixel structs - Pixel { r: u8, g: u8, b: u8, a: u8 }
    let max_depth = img.buffer.len()/200;
    println!("{}", max_depth); // For the input image I'm testing with, this prints 3984

    let mut queue = VecDeque::new();
    queue.push_back(img.buffer.as_mut_slice());

    let mut depth = 0;
    loop {
        let buffer_opt = queue.pop_front();
        if buffer_opt.is_none() {
            break;
        }
        let buffer = buffer_opt.unwrap();
        if depth >= max_depth || buffer.len() <= 1 {
            continue;
        }
        let pivot_idx = buffer.len() - 1;

        // cmp is a comparator function, which just compares the sums of two pixels
        let (left, _pivot, right) = buffer.partition_at_index_by(pivot_idx, cmp);
        queue.push_back(left);
        queue.push_back(right);
        depth +=1;
    }

}
ToxicTeacakes
  • 1,124
  • 1
  • 10
  • 19

1 Answers1

4

The biggest problem with the algorithm is this line:

let pivot_idx = buffer.len() - 1;

Quicksort needs a well-chosen pivot to be efficient: ideally, the pivot should divide the array to be sorted in half. Because you picked a pivot index of n - 1, you're partitioning each slice into an unsorted prefix of length n - 1 and a single "sorted" element at the end of the slice (and an empty suffix). The implementation of partition_at_index* actually special cases the n - 1 case, so this algorithm is basically a selection sort, which is O(n²) (see, for example, quicksort worst case condition).

The documentation for partition_at_index_by is a little ambiguous, which may have led you to this error:

Reorder the slice with a comparator function such that the element at index is at its final sorted position.

By "the element at index" it means the element that ends up at index, not the one that starts there.

To fix this issue, change the line above to read buffer.len() / 2.

trent
  • 25,033
  • 7
  • 51
  • 90