Skip to content

Commit e53a891

Browse files
committed
Added dual quicksort, edited docs
1 parent 34db0c5 commit e53a891

File tree

6 files changed

+120
-26
lines changed

6 files changed

+120
-26
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sorting_rs"
3-
version = "1.2.3"
3+
version = "1.2.4"
44
authors = ["flakusha <[email protected]>"]
55
edition = "2018"
66
repository = "https://github.com/flakusha/rust_sorting"

README.md

+11-9
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,20 @@ Sorting algorithms implemented in Rust
33
## Usage
44
1. Add this dependency and please consider it's version into your Cargo.toml:
55
```toml
6-
...
76
[dependencies]
87
sorting_rs = "1.2.0"
9-
...
108
```
119
2. Use available sorting algorithms in your Rust code:
1210
```rust
1311
use sorting_rs::*;
14-
...
1512
```
1613
3. For more information about origin of algorithms and implementation details,
17-
please read modules documentation
14+
please read modules documentation.
15+
[wikipedia](https://en.wikipedia.org/wiki/Sorting_algorithm) is nice starting
16+
point too
17+
4. For API
1818

1919
## This library contains following sorting algorithms:
20-
New algorithms implementations are planned
2120

2221
| Sorting algorithm | Features and downsides | Worst-case performance O(): comparisons; swaps | Best-case performance O(): comparisons; swaps | Space complexity O() |
2322
| -------------- | -------------------------------- | -------- | -------- | ------------- |
@@ -27,16 +26,19 @@ New algorithms implementations are planned
2726
| Gnome | simple and slow, works with one item at a time | `n`<sup>`2`</sup> | `n` | `1` |
2827
| Heap | independent of data distribution | `nlogn` | `nlogn` or `n` | `n` or `1` |
2928
| Weak Heap | independent of data distribution, decreased amount of comparisons | `nlogn` | `nlogn` or `n` | `n` or `1` |
30-
| N-Heap | independent of data distribution | `nlogn` | `nlogn` or `n` | `n` or `1` |
29+
| N-Heap | independent of data distribution, should be faster than default heap. n = 3 | `nlogn` | `nlogn` or `n` | `n` or `1` |
3130
| Bottom-up Heap | upgraded version of heapsort with decreased number of comparisons | `nlogn` | `nlogn` or `n` | `n` or `1` |
3231
| Insertion | simple, but less effective than quicksort, heapsort or merge sort | `n`<sup>`2`</sup>; `n`<sup>`2`</sup> | `n`; `1` | `n` or `1` |
33-
| Merge | independent of data distribution | `nlogn` | `nlogn` or `n` | `n` |
32+
| Merge | independent of data distribution | `nlogn` | `nlogn` | `n` |
3433
| Odd-even | presented to be effective on processors with local interconnections | `n`<sup>`2`</sup> | `n` | `1` |
3534
| Odd-even (Batcher) | more efficient version of odd-even sort | `log`<sup>`2`</sup>`n` | `log`<sup>`2`</sup>`n` | `log`<sup>`2`</sup>`n` |
3635
| Quick | bad for sorted or reversed input | `n`<sup>`2`</sup> | `nlog`<sub>2</sub>`n` | `n` or `logn` |
36+
| Quick dual | enchanced version of quicksort | `n`<sup>`2`</sup> | `2nlnn` | `n` or `logn` |
3737
| Ksort | modified version of quicksort, faster than heap at less than 7 million elements | `n`<sup>`2`</sup> | `nlog`<sub>2</sub>`n` | `n` or `logn` |
3838
| Selection | the least number of swaps among all the algorithms | `n`<sup>`2`</sup>; `n` | `n`<sup>`2`</sup>; `1` | `1` |
39-
| Shell | it is optimization of insertion sort | `n`<sup>`2`</sup> or `nlog`<sup>`2`</sup>`n` | `nlogn` or `nlog`<sup>`2`</sup>`n` | `n` |
39+
| Shellsort | it is optimization of insertion sort | `n`<sup>`3/2`</sup> or `nlog`<sup>`2`</sup>`n` | `nlogn` | `1` |
4040
| Slow | it's slow, who would ever need it? | | | |
4141
| Smooth | variant of heapsort, good for nearly sorted data | `nlogn` | `n` | `n` or `1` |
42-
| Stooge | it's a bit faster than slow sort | `n`<sup>`2.7095`</sup> | | `n` |
42+
| Stooge | it's a bit faster than slow sort | `n`<sup>`2.7095`</sup> | | `n` |
43+
44+
New algorithms implementations are planned

benches/sort_benchmark.rs

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ fn bench(c: &mut Criterion) {
4848
nheap_sort,
4949
oddeven_sort,
5050
quick_sort,
51+
quick_dual_sort,
5152
selection_sort,
5253
shell_sort,
5354
smooth_sort

src/bin/leonardo_numbers.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
/// Additional private binary to print Leonardo and Fibonnaci numbers
2-
/// Leonardo numbers are then used in smoothsort algorithm
3-
/// This one can be useful in case you need to modify algorithm to use with
4-
/// 32-, 64-, 128-bit and other systems
5-
/// This addition uses usize in case there is mainstream 64-bit system
6-
/// # Usage:
7-
/// ```ignore
8-
/// cargo run leonardo_numbers
9-
/// ```
1+
//! Additional private binary to print Leonardo and Fibonnaci numbers.
2+
//! Leonardo numbers are used in smoothsort algorithm as constant.
3+
//! This one can be useful in case you need to modify algorithm to use with
4+
//! 32-, 64-, 128-bit and other systems.
5+
//! This addition uses usize in case there is mainstream 64-bit system
6+
//! # Usage:
7+
//! ```ignore
8+
//! cargo run leonardo_numbers
9+
//! ```
1010
use std::io;
1111

1212
fn leonardo_generate(mut n0: usize, mut n1: usize, add: usize) ->

src/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88
//! | Gnome | simple and slow, works with one item at a time | `n`<sup>`2`</sup> | `n` | `1` |
99
//! | Heap | independent of data distribution | `nlogn` | `nlogn` or `n` | `n` or `1` |
1010
//! | Weak Heap | independent of data distribution, decreased amount of comparisons | `nlogn` | `nlogn` or `n` | `n` or `1` |
11-
//! | N-Heap | independent of data distribution | `nlogn` | `nlogn` or `n` | `n` or `1` |
11+
//! | N-Heap | independent of data distribution, should be faster than default heap. n = 3 | `nlogn` | `nlogn` or `n` | `n` or `1` |
1212
//! | Bottom-up Heap | upgraded version of heapsort with decreased number of comparisons | `nlogn` | `nlogn` or `n` | `n` or `1` |
1313
//! | Insertion | simple, but less effective than quicksort, heapsort or merge sort | `n`<sup>`2`</sup>; `n`<sup>`2`</sup> | `n`; `1` | `n` or `1` |
14-
//! | Merge | independent of data distribution | `nlogn` | `nlogn` or `n` | `n` |
14+
//! | Merge | independent of data distribution | `nlogn` | `nlogn` | `n` |
1515
//! | Odd-even | presented to be effective on processors with local interconnections | `n`<sup>`2`</sup> | `n` | `1` |
1616
//! | Odd-even (Batcher) | more efficient version of odd-even sort | `log`<sup>`2`</sup>`n` | `log`<sup>`2`</sup>`n` | `log`<sup>`2`</sup>`n` |
1717
//! | Quick | bad for sorted or reversed input | `n`<sup>`2`</sup> | `nlog`<sub>2</sub>`n` | `n` or `logn` |
18+
//! | Quick dual | enchanced version of quicksort | `n`<sup>`2`</sup> | `2nlnn` | `n` or `logn` |
1819
//! | Ksort | modified version of quicksort, faster than heap at less than 7 million elements | `n`<sup>`2`</sup> | `nlog`<sub>2</sub>`n` | `n` or `logn` |
1920
//! | Selection | the least number of swaps among all the algorithms | `n`<sup>`2`</sup>; `n` | `n`<sup>`2`</sup>; `1` | `1` |
20-
//! | Shell | it is optimization of insertion sort | `n`<sup>`2`</sup> or `nlog`<sup>`2`</sup>`n` | `nlogn` or `nlog`<sup>`2`</sup>`n` | `n` |
21+
//! | Shellsort | it is optimization of insertion sort | `n`<sup>`3/2`</sup> or `nlog`<sup>`2`</sup>`n` | `nlogn` | `1` |
2122
//! | Slow | it's slow, who would ever need it? | | | |
2223
//! | Smooth | variant of heapsort, good for nearly sorted data | `nlogn` | `n` | `n` or `1` |
2324
//! | Stooge | it's a bit faster than slow sort | `n`<sup>`2.7095`</sup> | | `n` |
@@ -49,7 +50,7 @@ pub use self::insertion_sort::insertion_sort;
4950
pub use self::ksort::ksort;
5051
pub use self::merge_sort::merge_sort;
5152
pub use self::oddeven_sort::{oddeven_sort, oddeven_batcher_sort};
52-
pub use self::quick_sort::quick_sort;
53+
pub use self::quick_sort::{quick_sort, quick_dual_sort};
5354
pub use self::selection_sort::selection_sort;
5455
pub use self::shell_sort::shell_sort;
5556
pub use self::slow_sort::slow_sort;

src/quick_sort.rs

+93-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/// Sorts a slice in-place using
2-
/// [Quick sort](https://en.wikipedia.org/wiki/Quicksort).
2+
/// [Quick sort](https://en.wikipedia.org/wiki/Quicksort),
3+
/// [Dual-Pivot Quicksort](https://www.researchgate.net/publication/259264490_Dual_pivot_Quicksort)
34
/// All kinds of slices can be sorted as long as they implement
45
/// [`PartialOrd`](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html).
6+
/// Dual pivot quicksort additionally needs [`Copy`](https://doc.rust-lang.org/std/marker/trait.Copy.html)
57
///
68
/// Quicksort can be compared to merge sort as it also is a divide-and-conquer
79
/// algorithm. However, quicksort does all the heavy work before the recursive
@@ -19,6 +21,16 @@
1921
/// sorting_rs::quick_sort(&mut strings);
2022
/// assert_eq!(strings, &["cargo", "rustc", "rustup"]);
2123
/// ```
24+
/// ```rust
25+
/// let mut vec = vec![0, -1, -2, -3,];
26+
/// sorting_rs::quick_dual_sort(&mut vec);
27+
/// assert_eq!(vec, &[-3, -2, -1, 0]);
28+
/// ```
29+
/// ```rust
30+
/// let mut strings = vec!["rustc", "cargo", "rustup"];
31+
/// sorting_rs::quick_dual_sort(&mut strings);
32+
/// assert_eq!(strings, &["cargo", "rustc", "rustup"]);
33+
/// ```
2234
2335
pub fn quick_sort<T: PartialOrd>(input: &mut [T]) {
2436
if input.len() > 1 {
@@ -28,8 +40,8 @@ pub fn quick_sort<T: PartialOrd>(input: &mut [T]) {
2840
}
2941
}
3042

31-
/// Partitions a slice according to the Lomuta partition scheme.
32-
pub fn lomuto_partition<T: PartialOrd>(input: &mut [T]) -> usize {
43+
/// Partitions a slice according to the Lomuto partition scheme.
44+
fn lomuto_partition<T: PartialOrd>(input: &mut [T]) -> usize {
3345
let pivot = input.len() - 1;
3446
let mut swap = 0;
3547
for i in 0..pivot {
@@ -47,6 +59,54 @@ pub fn lomuto_partition<T: PartialOrd>(input: &mut [T]) -> usize {
4759
swap
4860
}
4961

62+
pub fn quick_dual_sort<T: PartialOrd + Copy>(input: &mut [T]) {
63+
if input.len() < 2 {return;}
64+
dual_pivot(input, 0, input.len() - 1);
65+
}
66+
67+
fn dual_pivot<T: PartialOrd + Copy>(input: &mut [T], start: usize,
68+
end: usize) {
69+
if start >= end {return;}
70+
if input[start] > input[end] {
71+
input.swap(start, end);
72+
}
73+
// let seventh = (input.len()) >> 3 + (input.len() >> 6) + 1;
74+
let lpivot = input[start];
75+
let rpivot = input[end];
76+
77+
let mut startm = start + 1;
78+
let mut endm = end - 1;
79+
80+
let mut point = startm;
81+
82+
while point <= endm {
83+
if input[point] < lpivot {
84+
input.swap(point, startm);
85+
startm += 1;
86+
}
87+
else if input[point] >= rpivot {
88+
while input[endm] > rpivot && point < endm {
89+
endm -= 1;
90+
}
91+
input.swap(point, endm);
92+
93+
if input[point] < lpivot {
94+
input.swap(point, startm);
95+
startm += 1;
96+
}
97+
}
98+
point += 1;
99+
}
100+
startm -= 1;
101+
endm += 1;
102+
input.swap(start, startm);
103+
input.swap(end, endm);
104+
105+
dual_pivot(input, start, startm);
106+
dual_pivot(input, startm + 1, endm);
107+
dual_pivot(input, endm, end);
108+
}
109+
50110
#[cfg(test)]
51111
mod tests {
52112
use super::*;
@@ -69,4 +129,34 @@ mod tests {
69129
quick_sort(&mut vector_in);
70130
debug_assert_eq!(vector_in, vec![1]);
71131
}
132+
#[test]
133+
fn test_quick_dual() {
134+
let mut vector_in = vec![10, 20, 11, 24];
135+
quick_dual_sort(&mut vector_in);
136+
debug_assert_eq!(vector_in, vec![10, 11, 20, 24]);
137+
}
138+
#[test]
139+
fn test_quick_two_elem() {
140+
let mut vector_in = [20, 10];
141+
quick_dual_sort(&mut vector_in);
142+
debug_assert_eq!(vector_in, [10, 20]);
143+
}
144+
#[test]
145+
fn test_quick_dual_longer() {
146+
let mut vector_in = [10, 20, 11, 24, 22, 21, 19];
147+
quick_dual_sort(&mut vector_in);
148+
debug_assert_eq!(vector_in, [10, 11, 19, 20, 21, 22, 24]);
149+
}
150+
#[test]
151+
fn test_quick_dual_empty() {
152+
let mut vector_in:Vec<i32> = vec![];
153+
quick_dual_sort(&mut vector_in);
154+
debug_assert_eq!(vector_in, &[]);
155+
}
156+
#[test]
157+
fn test_quick_dual_len1() {
158+
let mut vector_in = vec![1];
159+
quick_dual_sort(&mut vector_in);
160+
debug_assert_eq!(vector_in, vec![1]);
161+
}
72162
}

0 commit comments

Comments
 (0)