查找第K小的元素

  1. use crate::sorting::partition;
  2. use std::cmp::{Ordering, PartialOrd};
  3. /// Returns k-th smallest element of an array, i.e. its order statistics.
  4. /// Time complexity is O(n^2) in the worst case, but only O(n) on average.
  5. /// It mutates the input, and therefore does not require additional space.
  6. pub fn kth_smallest<T>(input: &mut [T], k: usize) -> Option<T>
  7. where
  8. T: PartialOrd + Copy,
  9. {
  10. if input.is_empty() {
  11. return None;
  12. }
  13. let kth = _kth_smallest(input, k, 0, input.len() - 1);
  14. Some(kth)
  15. }
  16. fn _kth_smallest<T>(input: &mut [T], k: usize, lo: usize, hi: usize) -> T
  17. where
  18. T: PartialOrd + Copy,
  19. {
  20. if lo == hi {
  21. return input[lo];
  22. }
  23. let pivot = partition(input, lo as isize, hi as isize) as usize;
  24. let i = pivot - lo + 1;
  25. match k.cmp(&i) {
  26. Ordering::Equal => input[pivot],
  27. Ordering::Less => _kth_smallest(input, k, lo, pivot - 1),
  28. Ordering::Greater => _kth_smallest(input, k - i, pivot + 1, hi),
  29. }
  30. }
  31. #[cfg(test)]
  32. mod tests {
  33. use super::*;
  34. #[test]
  35. fn empty() {
  36. let mut zero: [u8; 0] = [];
  37. let first = kth_smallest(&mut zero, 1);
  38. assert_eq!(None, first);
  39. }
  40. #[test]
  41. fn one_element() {
  42. let mut one = [1];
  43. let first = kth_smallest(&mut one, 1);
  44. assert_eq!(1, first.unwrap());
  45. }
  46. #[test]
  47. fn many_elements() {
  48. // 0 1 3 4 5 7 8 9 9 10 12 13 16 17
  49. let mut many = [9, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0];
  50. let first = kth_smallest(&mut many, 1);
  51. let third = kth_smallest(&mut many, 3);
  52. let sixth = kth_smallest(&mut many, 6);
  53. let fourteenth = kth_smallest(&mut many, 14);
  54. assert_eq!(0, first.unwrap());
  55. assert_eq!(3, third.unwrap());
  56. assert_eq!(7, sixth.unwrap());
  57. assert_eq!(17, fourteenth.unwrap());
  58. }
  59. }