#[inline]
pub fn sparse_intersection_count(a: &[u32], b: &[u32]) -> usize {
if a.is_empty() || b.is_empty() {
return 0;
}
let (small, large) = if a.len() <= b.len() { (a, b) } else { (b, a) };
if small.len() * 8 < large.len() {
galloping_intersection_count(small, large)
} else {
merge_intersection_count(small, large)
}
}
#[inline]
fn merge_intersection_count(a: &[u32], b: &[u32]) -> usize {
let mut count = 0;
let mut i = 0;
let mut j = 0;
while i < a.len() && j < b.len() {
match a[i].cmp(&b[j]) {
std::cmp::Ordering::Less => i += 1,
std::cmp::Ordering::Greater => j += 1,
std::cmp::Ordering::Equal => {
count += 1;
i += 1;
j += 1;
}
}
}
count
}
#[inline]
fn galloping_intersection_count(small: &[u32], large: &[u32]) -> usize {
let mut count = 0;
let mut lo = 0; for &val in small {
let mut step = 1;
while lo + step < large.len() && large[lo + step] < val {
step *= 2;
}
let hi = (lo + step).min(large.len());
lo = binary_search_left(&large[lo..hi], val) + lo;
if lo < large.len() && large[lo] == val {
count += 1;
lo += 1; }
}
count
}
#[inline]
fn binary_search_left(slice: &[u32], target: u32) -> usize {
let mut lo = 0;
let mut hi = slice.len();
while lo < hi {
let mid = lo + (hi - lo) / 2;
if slice[mid] < target {
lo = mid + 1;
} else {
hi = mid;
}
}
lo
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sparse_intersection() {
let a = vec![1, 3, 5, 7, 9];
let b = vec![2, 3, 6, 7, 10];
assert_eq!(sparse_intersection_count(&a, &b), 2);
}
#[test]
fn test_sparse_intersection_empty() {
let a: Vec<u32> = vec![];
let b = vec![1, 2, 3];
assert_eq!(sparse_intersection_count(&a, &b), 0);
}
#[test]
fn test_galloping_skewed() {
let small = vec![5, 50, 500];
let large: Vec<u32> = (0..1000).collect();
assert_eq!(sparse_intersection_count(&small, &large), 3);
}
#[test]
fn test_galloping_no_overlap() {
let small = vec![1001, 1002, 1003];
let large: Vec<u32> = (0..1000).collect();
assert_eq!(sparse_intersection_count(&small, &large), 0);
}
#[test]
fn test_galloping_all_overlap() {
let small = vec![0, 1, 2, 3, 4];
let large: Vec<u32> = (0..1000).collect();
assert_eq!(sparse_intersection_count(&small, &large), 5);
}
#[test]
fn test_merge_balanced() {
let a: Vec<u32> = (0..100).step_by(2).collect(); let b: Vec<u32> = (0..100).step_by(3).collect(); let expected = (0..100u32).filter(|x| x % 2 == 0 && x % 3 == 0).count();
assert_eq!(sparse_intersection_count(&a, &b), expected);
}
#[test]
fn test_identical() {
let a: Vec<u32> = (0..50).collect();
assert_eq!(sparse_intersection_count(&a, &a), 50);
}
#[test]
fn test_reversed_args() {
let a = vec![1, 5, 10];
let b: Vec<u32> = (0..1000).collect();
assert_eq!(
sparse_intersection_count(&a, &b),
sparse_intersection_count(&b, &a)
);
}
}