-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathkth_smallest.rs
95 lines (80 loc) · 2.3 KB
/
kth_smallest.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::cmp::{Ordering, PartialOrd};
pub fn partition<T: PartialOrd>(arr: &mut [T], lo: isize, hi: isize) -> isize {
let pivot = hi as usize;
let mut i = lo - 1;
let mut j = hi;
loop {
i += 1;
while arr[i as usize] < arr[pivot] {
i += 1;
}
j -= 1;
while j >= 0 && arr[j as usize] > arr[pivot] {
j -= 1;
}
if i >= j {
break;
} else {
arr.swap(i as usize, j as usize);
}
}
arr.swap(i as usize, pivot);
i
}
/// Returns k-th smallest element of an array, i.e. its order statistics.
/// Time complexity is O(n^2) in the worst case, but only O(n) on average.
/// It mutates the input, and therefore does not require additional space.
pub fn kth_smallest<T>(input: &mut [T], k: usize) -> Option<T>
where
T: PartialOrd + Copy,
{
if input.is_empty() {
return None;
}
let kth = _kth_smallest(input, k, 0, input.len() - 1);
Some(kth)
}
fn _kth_smallest<T>(input: &mut [T], k: usize, lo: usize, hi: usize) -> T
where
T: PartialOrd + Copy,
{
if lo == hi {
return input[lo];
}
let pivot = partition(input, lo as isize, hi as isize) as usize;
let i = pivot - lo + 1;
match k.cmp(&i) {
Ordering::Equal => input[pivot],
Ordering::Less => _kth_smallest(input, k, lo, pivot - 1),
Ordering::Greater => _kth_smallest(input, k - i, pivot + 1, hi),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty() {
let mut zero: [u8; 0] = [];
let first = kth_smallest(&mut zero, 1);
assert_eq!(None, first);
}
#[test]
fn one_element() {
let mut one = [1];
let first = kth_smallest(&mut one, 1);
assert_eq!(1, first.unwrap());
}
#[test]
fn many_elements() {
// 0 1 3 4 5 7 8 9 9 10 12 13 16 17
let mut many = [9, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0];
let first = kth_smallest(&mut many, 1);
let third = kth_smallest(&mut many, 3);
let sixth = kth_smallest(&mut many, 6);
let fourteenth = kth_smallest(&mut many, 14);
assert_eq!(0, first.unwrap());
assert_eq!(3, third.unwrap());
assert_eq!(7, sixth.unwrap());
assert_eq!(17, fourteenth.unwrap());
}
}