Работа с BigO нотацией. Пишем высокопроизводительный код
Расскажу просто о сложном. Погнали.
Big O — это способ описать, насколько быстро растёт время работы алгоритма по мере увеличения размера входных данных. Другими словами: насколько «дорого» становится задача для компьютера, когда данных всё больше и больше.
Основные идеи на пальцах
- Big O показывает, что происходит с временем работы, когда данных становится по-настоящему много.
- Не считаем точное время в секундах, интересуют только масштабы.
Как пошагово считать BigO?
- Убери константы и незначительные части. Останется «основа» — с ней и будем работать.
- Определи, сколько раз будет выполнена главная операция алгоритма.
- Оцени, как это число растёт при увеличении данных (B O(n) "n" — количество данных).
Как формально записывать
Не зависит от размера входных данных.
Операции: доступ к элементу по индексу, пуш в Vec, чтение значения HashMap.
fn main() {
let vec = vec![10, 20, 30];
println!("{}", vec[1]); // доступ по индексу — O(1)
}Время выполнения растёт линейно от объёма данных.
Обычно это один цикл.
fn main() {
let books = vec!["A", "B", "C"];
for book in books {
println!("{}", book); // каждую книгу — один раз
}
}Вложенные циклы. Количество операций растёт как n * n.
fn main() {
let items = vec![1, 2, 3];
for a in &items {
for b in &items {
println!("{} + {} = {}", a, b, a + b);
}
}
}Уменьшение задачи пополам на каждом шаге.
Бинарный поиск в отсортированном массиве — классика.
fn binary_search(arr: &[i32], target: i32) -> Option<usize> {
let mut left = 0;
let mut right = arr.len(); while left < right {
let mid = (left + right) / 2;
if arr[mid] == target {
return Some(mid);
} else if arr[mid] < target {
left = mid + 1;
} else {
right = mid;
}
} None
}fn main() {
let sorted = vec![1, 3, 5, 7, 9];
println!("{:?}", binary_search(&sorted, 5));
}- Бинарный поиск (Vec, slice)
- BTreeMap, BTreeSet (в Rust — хранятся как сбалансированные деревья)
- Деление диапазонов, рекурсия с делением
Очень дорогие по времени алгоритмы. Используются в переборе всех комбинаций, например: задача коммивояжёра, все перестановки, brute force.
fn permutations(prefix: String, rest: String) {
if rest.is_empty() {
println!("{}", prefix);
} else {
for i in 0..rest.len() {
let mut new_prefix = prefix.clone();
new_prefix.push(rest.chars().nth(i).unwrap()); let mut new_rest = rest.clone();
new_rest.remove(i); permutations(new_prefix, new_rest);
}
}
}fn main() {
permutations("".to_string(), "abc".to_string());
}- Полный перебор (backtracking, brute force)
- Задачи из комбинаторики
- Рекурсии без оптимизаций (без кэша, без DP)
За сохранение ваших нервных клеток (и для их дальнейшего сохранения) можно подписаться на мой GitHub.
https://github.com/MarieRomanovich
Регулярно пощу репы, общаюсь, кидаю пулл реквесты)).
Welcome to CombatDevZone