Что такое алгоритмическая сложность

Ответ

Алгоритмическая сложность (O-нотация) описывает, как быстро растёт время выполнения или потребление памяти алгоритма при увеличении размера входных данных.

Основные виды сложности:

  • O(1) – константная (доступ к элементу массива).
  • O(log n) – логарифмическая (бинарный поиск).
  • O(n) – линейная (поиск в неотсортированном массиве).
  • O(n log n) – линейно-логарифмическая (быстрая сортировка).
  • O(n²) – квадратичная (пузырьковая сортировка).

Пример:

// O(n) – линейная сложность  
int SumArray(int[] arr)  
{  
    int sum = 0;  
    foreach (int num in arr)  // Проход по всем элементам  
        sum += num;  
    return sum;  
}  

Чем больше элементов в arr, тем дольше выполнение.

Ответ 18+ 🔞

Давай разжую эту тему про алгоритмическую сложность, а то некоторые думают, что это какая-то высшая математика, а на деле всё проще пареной репы, если не загоняться.

Вот смотри, представь, что у тебя есть задача и ты её решаешь. O-нотация — это, по сути, ответ на вопрос: «Ну и насколько, блядь, замедлится твой алгоритм, если данных станет в десять раз больше?». Не в секундах, а в принципе, в тенденции, понимаешь?

Основные градации, с которыми столкнёшься:

  • O(1) – Константная. Вообще похуй на объём данных. Время одно и то же. Как достать бутылку пива из холодильника — открыл дверцу, взял. Не важно, одна там бутылка или двадцать. Как доступ к элементу массива по индексу: arr[999] — машина сразу прыгает туда, ей всё равно.
  • O(log n) – Логарифмическая. Растёт оч-ч-чень медленно, почти как константа. Это как искать слово в толстом бумажном словаре. Ты открываешь посередине, смотришь — ага, нужно вперёд. Открываешь уже в этой половине посередине — нужно назад. И так пока не найдёшь. С каждым шагом ты отбрасываешь к хуям половину оставшихся страниц. Увеличишь словарь в сто раз — шагов добавится всего-ничего. Бинарный поиск — его родной дом.
  • O(n) – Линейная. Вот это прям классика. Данных стало в 10 раз больше — времени уйдёт примерно в 10 раз больше. Прямая зависимость, честная. Как если бы тебе заказали «пересчитать все стулья в этом зале». 100 стульев — 100 взглядов. 1000 стульев — 1000 взглядов, иди и считай, не ной. Поиск в неотсортированном массиве перебором — оно самое.
  • O(n log n) – Линейно-логарифмическая. Растёт чуть быстрее линейной, но ещё терпимо. Работает много где. Самые эффективные алгоритмы сортировки общего назначения (вроде быстрой или слиянием) жрут примерно столько времени. Данных в 10 раз больше — время вырастет примерно в 10 log(10) ≈ 10 3.3 = 33 раза. Не в 100, а в 33 — уже легче.
  • O(n²) – Квадратичная. А вот тут начинается пиздец. Данных в 10 раз больше — времени нужно в 100 раз больше. Это как если бы тебе надо было не просто посчитать стулья, а сравнить КАЖДЫЙ стул с КАЖДЫМ другим стулом, чтобы найти одинаковые. 100 стульев — это уже 10 000 сравнений. 1000 стульев — это, мать его, миллион операций. Пузырьковая сортировка — её царство. На больших данных просто сдохнет.

Пример, чтобы вообще всё встало на свои места:

Вот смотри на этот код. Он просто сумму всех чисел в массиве считает.

// O(n) – линейная сложность, чувак
int SumArray(int[] arr)
{
    int sum = 0;
    foreach (int num in arr)  // Вот этот цикл — он пройдёт по КАЖДОМУ элементу ровно один раз
        sum += num;
    return sum;
}

Суть в чём? Если в массиве arr будет 10 чисел — цикл сделает 10 итераций. Если 10 000 чисел — 10 000 итераций. Прямая пропорция, O(n). Быстрее не получится, ведь чтобы посчитать сумму, нужно каждое число хотя бы раз увидеть, так? Вот и вся магия.

Короче, смысл не в том, чтобы зубрить формулы, а в том, чтобы смотреть на свои циклы и вложенности и прикидывать: «А не получится ли тут, что если пользователей станет много, то всё нахуй встанет колом?». Вот для этого эта вся история и нужна.