mirror of
https://gitlab.com/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort.git
synced 2025-07-27 08:41:23 +00:00
finished rust impl
This commit is contained in:
@@ -9,5 +9,3 @@ edition = "2021"
|
|||||||
rayon = "1.5.1"
|
rayon = "1.5.1"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
quickcheck = "0.8.0"
|
|
138
rust/src/main.rs
138
rust/src/main.rs
@@ -1,18 +1,134 @@
|
|||||||
use std::fs;
|
#![feature(test)]
|
||||||
|
|
||||||
fn main() {
|
use rayon::join;
|
||||||
let input = fs::read_to_string("../data/perm50e6.txt")
|
|
||||||
.expect("Could not read file")
|
|
||||||
.lines()
|
|
||||||
.map(|s| s.parse::<u64>().unwrap())
|
|
||||||
.collect::<Vec<u64>>();
|
|
||||||
|
|
||||||
// println!("{}", input.len());
|
fn choose_pivot<T: Ord>(slice: &[T]) -> usize {
|
||||||
// let input = vec![100, 32, 57, 10];
|
// if slice.len() <= 2 {return slice.len() - 1;};
|
||||||
|
let (mut ismall, imid, mut ibig) = (0, slice.len() / 2, slice.len() - 1);
|
||||||
|
if slice[ibig] < slice[ismall] {
|
||||||
|
std::mem::swap(&mut ibig, &mut ismall);
|
||||||
|
}
|
||||||
|
if slice[imid] <= slice[ismall] {
|
||||||
|
ismall
|
||||||
|
} else if slice[ibig] <= slice[imid] {
|
||||||
|
ibig
|
||||||
|
} else {
|
||||||
|
imid
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Cqsort<T>(s: &Vec<T>) {
|
/// choose a pivot, then reorder so that everything to the left of the pivot is smaller, and
|
||||||
if s.len() <= 1 {
|
/// everything to the right is greater
|
||||||
|
/// Assumes slice.len() > 2
|
||||||
|
fn partition<T: Ord>(slice: &mut [T], pivot: usize) -> usize {
|
||||||
|
let mxix = slice.len() - 1;
|
||||||
|
slice.swap(pivot, mxix);
|
||||||
|
let (mut left, mut right) = (0, mxix - 1);
|
||||||
|
|
||||||
|
while left < right {
|
||||||
|
if slice[left] <= slice[mxix] {
|
||||||
|
left += 1;
|
||||||
|
} else if slice[right] >= slice[mxix] {
|
||||||
|
right -= 1;
|
||||||
|
} else {
|
||||||
|
slice.swap(left, right);
|
||||||
|
left += 1;
|
||||||
|
right -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if left > right {
|
||||||
|
// We just swapped the final two.
|
||||||
|
slice.swap(left, mxix);
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left and right met.
|
||||||
|
if slice[left] >= slice[mxix] {
|
||||||
|
slice.swap(left, mxix);
|
||||||
|
return left;
|
||||||
|
} else if slice[left] <= slice[mxix] {
|
||||||
|
slice.swap(left + 1, mxix);
|
||||||
|
return left + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!(
|
||||||
|
"This should be unreachable. Indices: {}, {} / {}",
|
||||||
|
left, right, mxix
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quicksort<T: Ord + std::marker::Send>(slice: &mut [T]) {
|
||||||
|
if slice.len() <= 1 {
|
||||||
|
return;
|
||||||
|
} else if slice.len() == 2 {
|
||||||
|
if slice[0] >= slice[1] {
|
||||||
|
slice.swap(0, 1);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pivot = choose_pivot(slice);
|
||||||
|
let pivot = partition(slice, pivot);
|
||||||
|
let (left_slice, right_slice) = slice.split_at_mut(pivot);
|
||||||
|
|
||||||
|
let right_slice = &mut right_slice[1..];
|
||||||
|
|
||||||
|
quicksort(left_slice);
|
||||||
|
quicksort(right_slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn par_quicksort<T: Ord + std::marker::Send>(slice: &mut [T]) {
|
||||||
|
if slice.len() <= 1 {
|
||||||
|
return;
|
||||||
|
} else if slice.len() == 2 {
|
||||||
|
if slice[0] >= slice[1] {
|
||||||
|
slice.swap(0, 1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pivot = choose_pivot(slice);
|
||||||
|
let pivot = partition(slice, pivot);
|
||||||
|
let (left_slice, right_slice) = slice.split_at_mut(pivot);
|
||||||
|
// left_slice is [0 - pivot-1], right_slice is [pivot, end]. We don't want to include the
|
||||||
|
// pivot, so reassign right_slice
|
||||||
|
let right_slice = &mut right_slice[1..];
|
||||||
|
|
||||||
|
join(|| quicksort(left_slice), || quicksort(right_slice));
|
||||||
|
}
|
||||||
|
|
||||||
|
use rand::distributions::{Distribution, Uniform};
|
||||||
|
use rand::thread_rng;
|
||||||
|
fn main() {
|
||||||
|
let mut s: Vec<i32> = Uniform::from(0..1_000_000_000)
|
||||||
|
.sample_iter(&mut thread_rng())
|
||||||
|
.take(100_000)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
quicksort(&mut s);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern crate test;
|
||||||
|
use test::Bencher;
|
||||||
|
fn get_bench_vec() -> Vec<i32> {
|
||||||
|
let s = Uniform::from(0..1_000_000_000)
|
||||||
|
.sample_iter(&mut thread_rng())
|
||||||
|
.take(500_000)
|
||||||
|
.collect();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn par_qs(b: &mut Bencher) {
|
||||||
|
let mut test_vec = get_bench_vec();
|
||||||
|
|
||||||
|
b.iter(|| par_quicksort(&mut test_vec))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn qs(b: &mut Bencher) {
|
||||||
|
let mut test_vec = get_bench_vec();
|
||||||
|
|
||||||
|
b.iter(|| quicksort(&mut test_vec))
|
||||||
}
|
}
|
||||||
|
@@ -1,156 +0,0 @@
|
|||||||
use rayon::join;
|
|
||||||
|
|
||||||
fn partition<T, F>(d: &mut [T], is_less: &F) -> usize
|
|
||||||
where
|
|
||||||
F: Fn(&T, &T) -> bool,
|
|
||||||
{
|
|
||||||
d.swap(0, d.len() / 2);
|
|
||||||
let mut mid = 0;
|
|
||||||
for i in 1..d.len() {
|
|
||||||
if is_less(&d[i], &d[0]) {
|
|
||||||
mid += 1;
|
|
||||||
d.swap(i, mid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.swap(0, mid);
|
|
||||||
mid
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_sort<T, F>(d: &mut [T], is_less: &F)
|
|
||||||
where
|
|
||||||
F: Fn(&T, &T) -> bool,
|
|
||||||
{
|
|
||||||
for i in 1..d.len() {
|
|
||||||
let mut n = i;
|
|
||||||
while n > 0 && is_less(&d[n], &d[n - 1]) {
|
|
||||||
d.swap(n, n - 1);
|
|
||||||
n -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn quick_sort<T, F>(d: &mut [T], is_less: &F)
|
|
||||||
where
|
|
||||||
F: Fn(&T, &T) -> bool,
|
|
||||||
{
|
|
||||||
if d.len() > 30 {
|
|
||||||
let mut mid = partition(d, is_less);
|
|
||||||
if mid < d.len() / 2 {
|
|
||||||
mid += 1;
|
|
||||||
}
|
|
||||||
let (left, right) = d.split_at_mut(mid);
|
|
||||||
quick_sort(left, is_less);
|
|
||||||
quick_sort(right, is_less);
|
|
||||||
} else {
|
|
||||||
insert_sort(d, is_less);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn par_quick_sort<T, F>(d: &mut [T], is_less: &F)
|
|
||||||
where
|
|
||||||
F: Fn(&T, &T) -> bool + Send + Sync,
|
|
||||||
T: Send,
|
|
||||||
{
|
|
||||||
if d.len() > 30 {
|
|
||||||
let mut mid = partition(d, is_less);
|
|
||||||
if mid < d.len() / 2 {
|
|
||||||
mid += 1;
|
|
||||||
}
|
|
||||||
let (left, right) = d.split_at_mut(mid);
|
|
||||||
|
|
||||||
if right.len() > 100_000 {
|
|
||||||
join(
|
|
||||||
|| par_quick_sort(left, is_less),
|
|
||||||
|| par_quick_sort(right, is_less),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
quick_sort(left, is_less);
|
|
||||||
quick_sort(right, is_less);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
insert_sort(d, is_less);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait QSort<T> {
|
|
||||||
fn qsort(&mut self);
|
|
||||||
|
|
||||||
fn is_sorted(&self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> QSort<T> for [T]
|
|
||||||
where
|
|
||||||
T: Ord,
|
|
||||||
{
|
|
||||||
fn qsort(&mut self) {
|
|
||||||
quick_sort(self, &|a: &T, b: &T| a.lt(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_sorted(&self) -> bool {
|
|
||||||
self.windows(2).all(|w| w[0] <= w[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ParQSort<T> {
|
|
||||||
fn par_qsort(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ParQSort<T> for [T]
|
|
||||||
where
|
|
||||||
T: Ord + Send,
|
|
||||||
{
|
|
||||||
fn par_qsort(&mut self) {
|
|
||||||
par_quick_sort(self, &|a: &T, b: &T| a.lt(b));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use rand::distributions::{Distribution, Uniform};
|
|
||||||
use rand::thread_rng;
|
|
||||||
use rayon::prelude::*;
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let len = 50_000_000;
|
|
||||||
let orig: Vec<i32> = Uniform::from(0..1_000_000_000)
|
|
||||||
.sample_iter(&mut thread_rng())
|
|
||||||
.take(len)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
macro_rules! test_sort {
|
|
||||||
($name:expr, $sort:ident) => {
|
|
||||||
println!(
|
|
||||||
"Sorting {} million numbers with {} in Rust ...",
|
|
||||||
len / 1_000_000,
|
|
||||||
$name
|
|
||||||
);
|
|
||||||
let mut data = orig.clone();
|
|
||||||
let start = Instant::now();
|
|
||||||
data.$sort();
|
|
||||||
println!("Time: {:.2?}", start.elapsed());
|
|
||||||
assert!(data.is_sorted());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test_sort!("naive quicksort", qsort);
|
|
||||||
test_sort!("stdlib quicksort", sort_unstable);
|
|
||||||
test_sort!("naive parallel quicksort", par_qsort);
|
|
||||||
test_sort!("Rayon quicksort", par_sort_unstable);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use quickcheck::quickcheck;
|
|
||||||
|
|
||||||
quickcheck! {
|
|
||||||
fn test_all(d: Vec<i32>) -> bool {
|
|
||||||
let mut d = d;
|
|
||||||
|
|
||||||
let mut expected = d.clone();
|
|
||||||
expected.sort_unstable();
|
|
||||||
d.par_qsort();
|
|
||||||
|
|
||||||
expected == d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,8 +0,0 @@
|
|||||||
(define mycount
|
|
||||||
(lambda (x lst)
|
|
||||||
(cond ((null? lst) 0)
|
|
||||||
((= x (car lst)) (+ 1 (mycount x (cdr lst))))
|
|
||||||
(else (mycount x (cdr lst))))))
|
|
||||||
|
|
||||||
;(mycount 5 '((5 2) (2 (4 2) 6) 2))
|
|
||||||
(mycount 3 '(1 2 3 4 3 2 3))
|
|
Reference in New Issue
Block a user