Пошаговые инструкции, которые превращают хаос данных в порядок. Разбираемся с нуля — с примерами, кодом и без заумных формул.
Это просто набор инструкций для решения задачи. Ты уже составлял алгоритмы — каждый раз, когда следовал рецепту или собирал мебель из ИКЕИ.
Рецепт яичницы — это алгоритм: 1) Разбить яйца. 2) Взболтать. 3) Вылить на сковородку. 4) Жарить 2 минуты. Компьютер делает то же самое, только с цифрами и в миллиарды раз быстрее.
Допустим, нужно найти слово в словаре. Не листаешь его с первой страницы — открываешь примерно посередине и сужаешь область поиска. Это уже алгоритм, и он называется двоичный поиск.
Хороший алгоритм решает задачу за минимум шагов. Двоичный поиск на 1 млн элементов — всего 20 шагов.
Алгоритм должен давать верный результат всегда. Не «иногда», не «в целом» — каждый раз.
Другой программист должен разобраться в твоём алгоритме без словаря. Читаемый код — добрый код.
Самый простой алгоритм сортировки. На каждом шаге ищем минимальный элемент и ставим его на своё место.
Представь стопку книг разной высоты. Ты проходишь по стопке, находишь самую короткую книгу и ставишь её в начало. Потом повторяешь со оставшимися.
Сравниваем соседние элементы и меняем их местами, если левый больше правого. «Тяжёлые» элементы всплывают в конец, как пузыри.
Проходим по массиву и сравниваем каждую пару соседей. Если левый больше правого — меняем местами. За один проход самый большой элемент «всплывёт» в конец.
Улучшение: Если за проход не было ни одной замены — массив уже отсортирован. Добавь флаг swapped и выйди раньше.
Выбираем опорный элемент и делим массив на две части: меньше опорного и больше. Затем сортируем каждую часть рекурсивно.
Берём число — это опора (pivot). Всё, что ≤ опоры — уходит влево. Всё, что > — вправо. Повторяем для каждой половины.
Почему быстрее? Каждый раз делим пополам. log₂(n) уровней × n сравнений = n·log(n). Для 1 млн элементов: ~20 млн операций вместо ~1 трлн.
Линейный — проверяем каждый по очереди. Двоичный — делим пополам и сужаем область. Второй экспоненциально быстрее, но требует отсортированных данных.
Как ищешь ключ в куче вещей — смотришь на каждую вещь по очереди. Просто, но медленно при большом количестве.
Как ищешь слово в словаре: открываешь посередине, смотришь, нужная буква раньше или позже — и перелистываешь нужную половину.
Красота логарифма: В массиве из 1 000 000 элементов двоичный поиск найдёт за 20 шагов. Линейному нужно до 1 000 000.
Рекурсия — это когда функция внутри себя вызывает саму себя. Как матрёшка: внутри каждой куклы — такая же, только поменьше. И так, пока не дойдёшь до самой маленькой.
Факториал числа n! — это произведение всех чисел от 1 до n. Пример: 4! = 4 × 3 × 2 × 1 = 24.
Каждое число — сумма двух предыдущих: 0, 1, 1, 2, 3, 5, 8, 13… Это природа: спираль раковины, расположение листьев.
Внимание: Рекурсивная версия вычисляет fib(40) за несколько секунд, а fib(50) — зависает. В реальных задачах используют итеративный подход или мемоизацию.
Big-O показывает, как растёт время работы программы, когда данных становится больше. Не количество секунд — а скорость роста.
| Нотация | Что значит | 10 элементов | 1 000 элементов | Пример |
|---|---|---|---|---|
| O(1) | Постоянное время | 1 | 1 | Обращение по индексу |
| O(log n) | Каждый шаг — вдвое быстрее | 3 | 10 | Двоичный поиск |
| O(n) | Пропорционально данным | 10 | 1 000 | Линейный поиск |
| O(n log n) | Чуть медленнее n | 33 | 10 000 | Быстрая сортировка |
| O(n²) | Квадрат роста | 100 | 1 000 000 | Пузырьковая сортировка |
| O(2ⁿ) | Экспоненциальный рост | 1 024 | ∞ (зависает) | Перебор подмножеств |
Алгоритмы работают с данными. Чтобы выбирать правильный алгоритм, нужно понимать, как организованы данные.
Просто список элементов подряд. Доступ по индексу — мгновенный. А вот вставить в середину — дорого, потому что нужно сдвинуть остальные.
Как стопка тарелок: кладёшь сверху, берёшь сверху. Принцип LIFO — Last In, First Out. Идеально для рекурсии и отмены действий.
Как очередь в магазине: встаёшь в конец, выходишь из начала. Принцип FIFO — First In, First Out. Используется в BFS.