Мне нужно выяснить, сколько целых чисел присутствует в обоих заданных наборах, быстро.Наборы записываются только один раз, но эта операция будет выполняться много раз с разными парами наборов.Наборы содержат 5-30 целых чисел, и наибольшее из этих целых чисел составляет 840000.
Сначала я попытался выполнить итерацию для одного Vec
и для каждого элемента проверить, присутствует ли он в другом Vec
.Затем я решил использовать BTreeSet
вместо этого, поскольку он должен быть значительно быстрее при проверке наличия целого числа в наборе, но, похоже, это не так.Реализация Vec
занимает ~ 72 мс, а BTreeSet ~ 96 мс при вызове на нескольких тысячах наборов в режиме выпуска в стабильном Rust 1.34 с той же производительностью при использовании ночью.
Это реализация Vec
:
use std::cmp;
fn main() {
let mut sets = Vec::with_capacity(1000);
for i in 1..1000 {
let mut set = Vec::new();
for j in 1..i % 30 {
set.push(i * j % 50000);
}
sets.push(set);
}
for left_set in sets.iter() {
for right_set in sets.iter() {
calculate_waste(left_set, right_set);
}
}
}
fn calculate_waste(left_nums: &Vec<usize>, right_nums: &Vec<usize>) -> usize {
let common_nums = left_nums.iter().fold(0, |intersection_count, num| {
intersection_count + right_nums.contains(num) as usize
});
let left_side = left_nums.len() - common_nums;
let right_side = right_nums.len() - common_nums;
let score = cmp::min(common_nums, cmp::min(left_side, right_side));
left_side - score + right_side - score + common_nums - score
}
И это реализация BTreeSet
:
use std::cmp;
use std::collections::BTreeSet;
fn main() {
let mut sets = Vec::with_capacity(1000);
for i in 1..1000 {
let mut set = BTreeSet::new();
for j in 1..i % 30 {
set.insert(i * j % 50000);
}
sets.push(set);
}
for left_set in sets.iter() {
for right_set in sets.iter() {
calculate_waste(left_set, right_set);
}
}
}
fn calculate_waste(left_nums: &BTreeSet<usize>, right_nums: &BTreeSet<usize>) -> usize {
let common_nums = left_nums.intersection(&right_nums).count();
let left_side = left_nums.len() - common_nums;
let right_side = right_nums.len() - common_nums;
let score = cmp::min(common_nums, cmp::min(left_side, right_side));
left_side - score + right_side - score + common_nums - score
}
Он был запущен командой (-w 50
игнорирует первые 50 запусков):
hyperfine "cargo run --release" -w 50 -m 100
Полный код программы доступен здесь .
Является ли реализация BTreeSet
более медленной, потому что в наборе слишком мало целых чисел, чтобы позволить его времени доступа O (log n) ксияние?Если да, могу ли я еще что-нибудь сделать, чтобы ускорить эту функцию?