Что именно означает O (log n)?

Я изучаю время работы Big O Notation и время амортизации. Я понимаю понятие линейного времени O (n), что означает, что размер входных данных влияет на рост алгоритма пропорционально ... и то же самое, например, касается квадратичного времени O (n 2) и т. Д. Даже алгоритмов, таких как генераторы перестановок, с O (n!) раз, которые растут на факториалы.

Например, следующая функция - O (n), потому что алгоритм растет пропорционально входному значению n:

f(int n) {
  int i;
  for (i = 0; i < n; ++i)
    printf("%d", i);
}

Точно так же, если бы был вложенный цикл, время было бы O (n 2).

Но что такое O (log n)? Например, что значит сказать, что высота полного двоичного дерева равна O (log n)?

Я знаю (возможно, не очень подробно), что такое логарифм в том смысле, что: log 10 100 = 2, но я не могу понять, как идентифицировать функцию с логарифмическим временем.


person Andreas Grech    schedule 21.02.2010    source источник
comment
Бинарное дерево с 1 узлом имеет высоту log2 (1) +1 = 1, дерево с 2 узлами имеет высоту log2 (2) +1 = 2, дерево с 4 узлами имеет высоту log2 (4) +1 = 3 и скоро. Дерево с n узлами имеет высоту log2 (n) +1, поэтому добавление узлов к дереву приводит к логарифмическому увеличению его средней высоты.   -  person David R Tribble    schedule 22.02.2010
comment
Одна вещь, которую я вижу в большинстве ответов, заключается в том, что они по существу описывают O (что-то) означает, что время работы алгоритма растет пропорционально чему-то. Учитывая, что вы спрашивали точное значение O (log n), это неправда. Это интуитивное описание нотации Big-Theta, а не Big-O. O (log n) интуитивно означает, что время выполнения увеличивается не более пропорционально log n: stackoverflow.com/questions/471199/   -  person mmx    schedule 22.02.2010
comment
Связанное stackoverflow.com/questions / 487258 /   -  person cletus    schedule 23.02.2010
comment
Я всегда вспоминаю «разделяй и властвуй» как пример для O (log n)   -  person RichardOD    schedule 23.02.2010
comment
Хитрость в отношении вашей функции: она линейна относительно ЗНАЧЕНИЯ ввода, однако - если мы думаем о n как о векторе битов (как мы представляем ввод) - на самом деле это O (2 ^ n) с точки зрения РАЗМЕРА вход (т.е. для представления n требуется lg (n) бит, поэтому, если n имеет длину k бит, цикл повторяется до 2 ^ k раз). Поэтому я бы сказал, что цикл экспоненциальный, а не линейный.   -  person mindvirus    schedule 27.05.2013
comment
Важно понимать, что его лог-база 2 (не 10). Это связано с тем, что на каждом этапе алгоритма вы удаляете половину оставшихся вариантов. В информатике мы почти всегда имеем дело с логической базой 2, потому что мы можем игнорировать константы. Однако есть некоторые исключения (например, время выполнения Quad Tree - это база данных 4).   -  person Ethan    schedule 27.05.2013
comment
@Ethan: Не имеет значения, на какой базе вы находитесь, поскольку базовое преобразование - это просто постоянное умножение. Формула: log_b (x) = log_d (x) / log_d (b). Log_d (b) будет просто константой.   -  person mindvirus    schedule 27.05.2013
comment
Немного основной информации о логарифмах! 1. Демистификация натурального логарифма 2. Использование логарифмов в реальном мире   -  person RP.    schedule 27.05.2013
comment
@mdkess Да, я знаю, что это постоянный фактор, я даже сказал об этом в своем комментарии. Я указывал, что логарифмическое время выполнения часто подразумевает деление вашего выбора пополам, в отличие от времени выполнения с логарифмической базой 10, которое предполагает удаление 9/10 вашего выбора на каждом шаге. Итак, я указывал OP, что мы часто делили свой выбор пополам на каждом шаге какого-либо алгоритма, что приводит к времени выполнения с логической базой 2, а не с логической базой 10. Понимание того, что это полезно для возможности смотреть на код. и сказать О, это О (вход). На самом деле я ничего не говорил о реальном времени выполнения.   -  person Ethan    schedule 28.05.2013
comment
@Ethan: Вы все еще неправы. Если что-то равно O (log_b (n)), b ›1, это O (log_c (n)) для любого c› 1. Таким образом, разделив ваш выбор пополам, вы получите время O (log_2 (n)) И O (log_10 (n)) время И O (log_12838 (n)) время выполнения. Это не имеет значения. Преобразование логарифма по основанию - это постоянное умножение, в котором преобладает функция логарифма, т.е. O (c * f (n)) равно O (f (n)), если c - константа.   -  person mindvirus    schedule 28.05.2013
comment
@mdkess Я не собираюсь придерживаться алгоритмической строгости. Я просто пытаюсь создать мысленное отображение между чем-то в коде и тем, что является O (logn). Конечно, к настоящему времени любая попытка того, чтобы это произошло, пресечена. Большой. И для записи я не ошибаюсь, потому что я сказал, что время выполнения было 10, я не имел в виду нотацию большой буквы О. Итак, если вы хотите быть полностью формальным, тогда это будет T (логарифм с основанием 10 (n)). Теперь, если вы хотите прекратить спорить о семантике, это было бы здорово.   -  person Ethan    schedule 01.06.2013
comment
@Ethan: Предполагая, что под T вы имеете в виду big-Theta, тогда вы правы, но это также T (логарифмическая база 43 (n)) и T (логическая база 378 (n)) по определению.   -  person mindvirus    schedule 01.06.2013
comment
@mdkess Я не имел в виду большую Тету. T_n - это функция, которая является точным временем выполнения кода. Например: T_n = 5 + 8n + n ^ 2. Большое O из T_n равно O (n ^ 2)   -  person Ethan    schedule 01.06.2013
comment
Может кто-нибудь сказать, где стоит буква O? Выход?   -  person clankill3r    schedule 18.03.2015
comment
@ clankill3r programmers.stackexchange.com/a/107977/8613   -  person Andreas Grech    schedule 19.01.2016
comment
Недавно я посмотрел видео, которое прекрасно описывает журнал N. Это абсолютно необходимо посмотреть. youtube.com/watch?v=kjDR1NBB9MU   -  person Daniel Eagle    schedule 26.02.2016
comment
Может быть, было бы полезно svitlanamoiseyenko.com/ 30.08.2016 / olog-n-and-how-fast-it-is   -  person Svitlana    schedule 30.08.2016


Ответы (32)


O(log N) в основном означает, что время растет линейно, а n растет экспоненциально. Таким образом, если для вычисления 10 элементов требуется 1 секунды, потребуется 2 секунд для вычисления 100 элементов, 3 секунд для вычисления 1000 элементов и так далее.

Это O(log n), когда мы действительно разделяем и властвуем типами алгоритмов, например, бинарным поиском. Другой пример - быстрая сортировка, когда мы каждый раз делим массив на две части и каждый раз требуется O(N) времени, чтобы найти сводный элемент. Следовательно, N O(log N)

person fastcodejava    schedule 21.02.2010
comment
Три мудрых строчки, превосходящие все остальные ответы на эссе ... :) На случай, если кому-то это не хватает, в контексте программирования база журнала равна 2 (а не 10), поэтому O (log n) масштабируется как 1 секунда на 10 элементов, 2 секунды для 20, 3 для 40 и т. д. - person nawfal; 23.05.2014
comment
Согласовано, кратко и ясно, хотя конечный вопрос из OP заключался в том, как определить логарифмическую функцию, а не совсем в том, что это такое. - person Adam; 31.07.2014
comment
да, логарифмическая функция обратна экспоненциальной функции. ((log x) base a) обратен (a power x). Качественный анализ этих функций с помощью графиков дал бы больше интуиции. - person overexchange; 16.10.2014
comment
Мне потребовалось около 3 чтений, чтобы понять, что это не так. Время растет линейно, а количество элементов - экспоненциально. Это означает больше элементов за меньшее время. Это утомительно для тех, кто представляет log как знакомую кривую логарифма на графике. - person Qix - MONICA WAS MISTREATED; 15.02.2017
comment
Я думаю, что это очень хороший ответ, за исключением той части, где утверждается, что двоичный поиск - это алгоритм разделения и владения. Это не так. - person code_dredd; 26.09.2017
comment
@ray Почему бинарный поиск - это не алгоритм разделения и владения? - person javaguy; 27.09.2017
comment
@javaguy Ссылка в моей пред. комментарий идет в этот ответ, где я объясняю, почему это не так. Если у вас есть дополнительные вопросы, пожалуйста, оставьте комментарии под моим ответом в этом конкретном сообщении. - person code_dredd; 27.09.2017
comment
Отличный ответ! Очень просто, но очень точно - person Marwan; 01.08.2018
comment
время растет линейно, в то время как n растет экспоненциально. Прекрасно сказано. Спасибо! - person JackOfAll; 31.12.2018
comment
@nawfal Это не совсем так. Когда вы используете обозначение O (log n), основание журнала не имеет значения, потому что все функции журнала пропорциональны друг другу. Вот почему вы опускаете основание, чего нельзя сказать о экспонентах (например, O (2 ^ n) не то же самое, что O (10 ^ n)). Таким образом, даже в контексте base-2 описанное вами поведение масштабирования в целом неверно - оно зависит от постоянного коэффициента. - person Mo B.; 29.09.2020
comment
@fastcodejava, когда вы сказали «разделяй и властвуй», мы предполагаем, что x ни один из разных потоков не будет обрабатывать куски? - person Arko; 19.06.2021

На этот вопрос уже было опубликовано много хороших ответов, но я считаю, что нам действительно не хватает одного важного, а именно иллюстрированного ответа.

Что значит сказать, что высота полного двоичного дерева равна O (log n)?

На следующем рисунке изображено двоичное дерево. Обратите внимание на то, что каждый уровень содержит удвоенное количество узлов по сравнению с уровнем выше (отсюда двоичный):

Двоичное дерево

Двоичный поиск - это пример сложности O(log n). Предположим, что узлы нижнего уровня дерева на рисунке 1 представляют элементы в некоторой отсортированной коллекции. Двоичный поиск - это алгоритм «разделяй и властвуй», и на рисунке показано, как нам потребуется (максимум) 4 сравнения, чтобы найти запись, которую мы ищем в этом наборе данных из 16 элементов.

Предположим, у нас есть набор данных из 32 элементов. Продолжая рисовать выше, мы обнаружим, что теперь нам потребуется 5 сравнений, чтобы найти то, что мы ищем, поскольку дерево выросло только на один уровень глубже, когда мы умножили количество данных. В результате сложность алгоритма можно описать как логарифмический порядок.

Нанесение log(n) на простой лист бумаги приведет к графику, на котором подъем кривой замедляется по мере увеличения n:

O (log n)

person Jørn Schou-Rode    schedule 21.02.2010
comment
Обратите внимание, что каждый уровень содержит удвоенное количество узлов по сравнению с уровнем выше (следовательно, двоичным). Это неверно. Вы описываете сбалансированное двоичное дерево. Бинарное дерево означает, что у каждого узла не более двух дочерних элементов. - person Oenotria; 27.05.2013
comment
Фактически, это очень особенное сбалансированное двоичное дерево, называемое полным двоичным деревом. Я отредактировал ответ, но мне нужно, чтобы кто-то его одобрил. - person user21820; 14.12.2013
comment
Полное двоичное дерево не обязательно должно иметь последний уровень для полного заполнения. Я бы сказал, что более подходящим является «полное двоичное дерево». - person Mr. AJ; 29.07.2014
comment
Ваш ответ пытается более конкретно отреагировать на исходную проблему OP, поэтому он лучше, чем текущий принятый ответ (IMO), но он все еще очень неполный: вы просто даете половину примера и 2 изображения ... - person nbro; 12.08.2015
comment
В этом дереве 31 элемент, а не 16. Почему оно называется набором данных из 16 элементов? Каждый узел на нем представляет собой число, иначе это было бы неэффективное двоичное дерево: P - person Perry Monschau; 24.11.2016
comment
Я помню, как работал с b-деревьями на уроках программирования в колледже как средство для реализации пузырьковой / быстрой сортировки. Я был поражен блеском и элегантностью решения. Мне еще предстоит найти более быстрый алгоритм сортировки, - person J Weezy; 16.05.2018
comment
Бинарный поиск - это алгоритм «разделяй и властвуй». Это не так просто. Я бы сказал, что это неправда. Но посмотрите здесь и убедитесь, что вы думаете сами: stackoverflow.com/questions/8850447/ - person m4110c; 22.08.2020

В приведенном ниже объяснении используется случай полностью сбалансированного двоичного дерева, чтобы помочь вам понять, как мы получаем логарифмическую временную сложность.

Двоичное дерево - это случай, когда проблема размера n разделяется на подзадачу размера n / 2, пока не будет достигнута проблема размера 1:

высота двоичного файла  дерево

И вот как вы получаете O (log n), который представляет собой объем работы, который необходимо выполнить в приведенном выше дереве, чтобы достичь решения.

Распространенным алгоритмом с временной сложностью O (log n) является двоичный поиск, рекурсивное отношение которого равно T (n / 2) + O (1), то есть на каждом последующем уровне дерева вы делите задачу пополам и выполняете постоянный объем дополнительной работы.

person 2cupsOfTech    schedule 26.10.2012
comment
новичок здесь. Итак, можно ли сказать, что высота дерева - это скорость деления путем рекурсии для достижения размера n = 1? - person Cody; 12.11.2013
comment
@Cody, да, по большей части ваши наблюдения верны. Этот пример иллюстрирует / использует log_2. Ваше наблюдение будет превышать log_2 и будет точным для любого log_x, где x > 1. Выполнение прямого деления может не привести к точному результату 1, поэтому вы можете использовать рекурсивное деление до тех пор, пока Ceiling() последнего деления не станет равным 1, или что-то подобное. - person James Oravec; 09.11.2018

Обзор

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

Во-первых, вам нужно иметь общее представление о логарифме, которое вы можете получить из https://en.wikipedia.org/wiki/Logarithm. Естествознание использует e и натуральный журнал. Инженеры будут использовать log_10 (логическая база 10), а компьютерные ученые будут часто использовать log_2 (логическая база 2), поскольку компьютеры основаны на двоичном коде. Иногда вы увидите аббревиатуры естественного журнала как ln(), инженеры обычно оставляют _10 выключенным и просто используют log(), а log_2 сокращается как lg(). Все типы логарифмов растут одинаково, поэтому они имеют одну и ту же категорию log(n).

Когда вы смотрите на примеры кода ниже, я рекомендую смотреть на O (1), затем на O (n), затем на O (n ^ 2). После того, как вы освоитесь с ними, посмотрите на другие. Я включил чистые примеры, а также варианты, чтобы продемонстрировать, как тонкие изменения могут по-прежнему приводить к той же категоризации.

Вы можете думать о O (1), O (n), O (logn) и т. Д. Как о классах или категориях роста. Для выполнения некоторых категорий потребуется больше времени, чем для других. Эти категории помогают нам упорядочить производительность алгоритма. Некоторые из них росли быстрее по мере роста ввода n. Следующая таблица демонстрирует указанный рост численно. В приведенной ниже таблице подумайте о log (n) как о потолке log_2.

введите здесь описание изображения

Примеры простого кода для различных категорий большого O:

O (1) - Примеры постоянного времени:

  • Алгоритм 1:

Алгоритм 1 выводит приветствие один раз, и он не зависит от n, поэтому он всегда будет выполняться в постоянное время, поэтому это O(1).

print "hello";
  • Алгоритм 2:

Алгоритм 2 выводит приветствие 3 раза, однако это не зависит от размера ввода. Даже если n растет, этот алгоритм всегда будет печатать приветствие только 3 раза. При этом 3 - это константа, поэтому этот алгоритм также O(1).

print "hello";
print "hello";
print "hello";

O (log (n)) - логарифмические примеры:

  • Алгоритм 3 - действует как log_2

Алгоритм 3 демонстрирует алгоритм, который работает в log_2 (n). Обратите внимание, что пост-операция цикла for умножает текущее значение i на 2, поэтому i изменяется от 1 до 2 до 4 до 8 до 16 до 32 ...

for(int i = 1; i <= n; i = i * 2)
  print "hello";
  • Алгоритм 4 - действует как log_3

Алгоритм 4 демонстрирует log_3. Уведомление i идет от 1 до 3 до 9 до 27 ...

for(int i = 1; i <= n; i = i * 3)
  print "hello";
  • Алгоритм 5 - действует как log_1.02

Алгоритм 5 важен, поскольку он помогает показать, что до тех пор, пока число больше 1 и результат многократно умножается на себя, вы смотрите на логарифмический алгоритм.

for(double i = 1; i < n; i = i * 1.02)
  print "hello";

O (n) - Примеры линейного времени:

  • Алгоритм 6

Это простой алгоритм, который печатает "привет" n раз.

for(int i = 0; i < n; i++)
  print "hello";
  • Алгоритм 7

Этот алгоритм показывает вариант, при котором он будет печатать привет n / 2 раз. п / 2 = 1/2 * п. Мы игнорируем константу 1/2 и видим, что этот алгоритм O (n).

for(int i = 0; i < n; i = i + 2)
  print "hello";

O (n * log (n)) - nlog (n) Примеры:

  • Алгоритм 8

Думайте об этом как о комбинации O(log(n)) и O(n). Вложение циклов for помогает нам получить O(n*log(n))

for(int i = 0; i < n; i++)
  for(int j = 1; j < n; j = j * 2)
    print "hello";
  • Алгоритм 9

Алгоритм 9 похож на алгоритм 8, но в каждом из циклов допускаются вариации, которые по-прежнему приводят к конечному результату O(n*log(n))

for(int i = 0; i < n; i = i + 2)
  for(int j = 1; j < n; j = j * 3)
    print "hello";

O (n ^ 2) - n в квадрате Примеры:

  • Алгоритм 10

O(n^2) легко получается стандартным вложением петель.

for(int i = 0; i < n; i++)
  for(int j = 0; j < n; j++)
    print "hello";
  • Алгоритм 11

Аналогичен алгоритму 10, но с некоторыми вариациями.

for(int i = 0; i < n; i++)
  for(int j = 0; j < n; j = j + 2)
    print "hello";

O (n ^ 3) - n в кубе. Примеры:

  • Алгоритм 12

Это похоже на алгоритм 10, но с 3 циклами вместо 2.

for(int i = 0; i < n; i++)
  for(int j = 0; j < n; j++)
    for(int k = 0; k < n; k++)
      print "hello";
  • Алгоритм 13

Подобен алгоритму 12, но с некоторыми вариациями, которые по-прежнему дают O(n^3).

for(int i = 0; i < n; i++)
  for(int j = 0; j < n + 5; j = j + 2)
    for(int k = 0; k < n; k = k + 3)
      print "hello";

Резюме

Выше приведены несколько простых примеров и вариаций, которые помогут продемонстрировать, какие тонкие изменения могут быть внесены, которые на самом деле не меняют анализ. Надеюсь, это даст вам достаточно информации.

person James Oravec    schedule 26.04.2016
comment
Потрясающие. Лучшее объяснение для меня, которое я когда-либо видел. Было бы лучше, если бы O(n^2) был отмечен как комбинация O(n) и O(n), поэтому O(n) * O(n) = O(n * n) = O(n^2). Это похоже на прыжок без этого уравнения. Это повторение предыдущего объяснения, но я думаю, что это повторение может дать читателям больше уверенности в понимании. - person eonil; 02.07.2016
comment
Это просто лучшее объяснение. - person Edgar Kiljak; 03.06.2018
comment
Прекрасные примеры! Могу я спросить, почему константы не учитываются в нотациях с большими буквами O? Например. почему O (n / 2) просто берется как O (n)? Не потому ли, что при n - ›бесконечность константа тоже становится несущественной? - person IceTea; 27.08.2018
comment
@IceTea - O в нотации большого O обозначает порядок величины. Другими словами, с какой скоростью увеличивается время по мере увеличения количества элементов. Уменьшение n вдвое не меняет скорости увеличения n. hth - person Shai Cohen; 09.09.2018
comment
@IceTea, чтобы дать вам понимание / интуицию по вашему вопросу. Если вы построите график n по сравнению с n/2, вы увидите, что они оба составляют прямую линию. Это ставит их в один класс, так как у них схожие темпы роста (воспринимайте это как форму диаграммы). Точно так же, если вы наметили log_2 в сравнении с log_3, вы увидите, что они оба принимают одинаковые формы или одинаковые темпы роста. - person James Oravec; 09.11.2018
comment
Спасибо за обратную связь, но, по крайней мере, исходя из того, что я узнал до сих пор, правильный ответ на мой предыдущий вопрос заключается в том, что большие временные сложности O представляют собой асимптотические временные сложности, поэтому действительно, когда n - ›бесконечность, константа становится незначительный. - person IceTea; 11.11.2018
comment
@IceTea, объяснение, данное @Shai и @James, является более точным, n/2 or 2n or n+2 or n будет иметь разные-разные линии на графике, но у них будет одинаковый темп роста, что означает, что все они будут следовать линейному росту. - person Naresh Joshi; 23.12.2018
comment
Новенький тут. Может ли кто-нибудь объяснить мне, почему алгоритм 3 отличается от алгоритма 7? Все они выполняются менее n раз. - person SuShiS; 26.11.2019
comment
Как насчет случая, когда у нас есть два вложенных цикла, но второй итератор зависит от первого, влияет ли эта зависимость на временную сложность? - person Bionix1441; 18.12.2019
comment
@ Bionix1441 вы можете привести пример? например следующее, как и то, о чем вы говорите: for(i=0; i<n; i++){ for(j=i; j<n; j++) { print "foo";}} если да, то да, в этом примере это было бы эквивалентом суммирования от 1 до n отпечатков (подумайте о форме треугольника, которую он создает, если вы печатаете каждое значение построчно ), что равно (n*(n+1))/2, что равно O(n^2). - person James Oravec; 02.05.2020
comment
@SuShiS, Alg_3 увеличивается умножением, а Alg_7 увеличивается сложением. Для небольших чисел это может быть не так очевидно, но посмотрите на это, когда у вас есть значение, которое больше (скажем, септиллион, 10 ^ 24), это поможет сделать вещи более ясными. Alg_7 - это только половина значения n, где Alg_3 будет больше журнала n. Чем большее значение для n вы выберете, тем яснее оно станет. :) - person James Oravec; 02.05.2020
comment
Этот ответ был для меня самым полезным. Не могли бы вы объяснить, почему варианты вроде for(int j = 0; j < n; j = j + 2) остаются такими же, как и все, за чем они следуют? В примере, который я использовал, почему это все еще O(n^2), если приращение счетчика цикла означает, что итераций будет меньше? - person berimbolo; 03.11.2020

Если у вас есть функция, которая принимает:

1 millisecond to complete if you have 2 elements.
2 milliseconds to complete if you have 4 elements.
3 milliseconds to complete if you have 8 elements.
4 milliseconds to complete if you have 16 elements.
...
n milliseconds to complete if you have 2^n elements.

Затем требуется log 2 (n) времени. нотация Big O, грубо говоря, означает, что отношение должно быть истинным только для больших n, и что постоянные множители и меньшие члены можно игнорировать.

person Mark Byers    schedule 21.02.2010
comment
log2 (n) то же самое, что o (log n)? - person Sven van den Boogaart; 23.10.2017
comment
Да, см. Комментарий nawfal для другого ответа здесь: (копирование-вставка) - в контексте программирования база журнала равна 2 (а не 10), поэтому O (log n) масштабируется как 1 секунда для 10 элементов, 2 секунды для 20 , 3 по 40 и т. Д. - person Andrejs; 06.03.2018
comment
@SvenvandenBoogaart, пример в этом решении иллюстрирует log_2, который находится в классе O(log(n)). Есть много других в том же классе O(log(n)), т.е. log_x, где x > 1 - person James Oravec; 09.11.2018
comment
@Andrejs, ваш комментарий so O(log n) scales like 1 sec for 10 elements, 2 sec for 20, 3 for 40 etc неточный. Этот шаблон / класс будет соответствовать / совпадать с O(n), а не с O(log(n)). Если кого-то интересовал log_10, то эквивалентным примером будет 1 секунда для 10 элементов, 2 секунды для 100, 3 для 1000 и т. Д. - person James Oravec; 09.11.2018

Логарифм

Хорошо, давайте попробуем полностью понять, что такое логарифм.

Представьте, что у нас есть веревка, и мы привязали ее к лошади. Если веревка привязана непосредственно к лошади, сила, с которой лошадь должна оторваться (скажем, от человека), равна 1.

Теперь представьте, что веревка обвивается вокруг шеста. Лошади, чтобы уйти, теперь придется тянуть во много раз сильнее. Количество раз будет зависеть от шероховатости веревки и размера шеста, но предположим, что это умножит силу на 10 (когда веревка сделает полный оборот).

Теперь, если веревка замкнута один раз, лошади нужно будет тянуть в 10 раз сильнее. Если человек решит усложнить задачу лошади, он может снова обмотать веревку вокруг шеста, увеличив ее силу еще в 10 раз. Третья петля снова увеличит силу еще в 10 раз.

введите описание изображения здесь

Мы можем видеть, что для каждого цикла значение увеличивается на 10. Количество оборотов, необходимое для получения любого числа, называется логарифмом числа, т.е. нам нужно 3 поста, чтобы умножить вашу силу в 1000 раз, 6 постов, чтобы умножить вашу силу на 1,000,000.

3 - логарифм 1000, а 6 - логарифм 1000000 (основание 10).

Итак, что на самом деле означает O (log n)?

В нашем примере выше наша «скорость роста» равна O (log n). На каждую дополнительную петлю сила, которую может выдержать наша веревка, в 10 раз больше:

Turns | Max Force
  0   |   1
  1   |   10
  2   |   100
  3   |   1000
  4   |   10000
  n   |   10^n

В приведенном выше примере использовалась база 10, но, к счастью, база журнала не имеет значения, когда мы говорим о нотации большого числа.

Теперь представим, что вы пытаетесь угадать число от 1 до 100.

Your Friend: Guess my number between 1-100! 
Your Guess: 50
Your Friend: Lower!
Your Guess: 25
Your Friend: Lower!
Your Guess: 13
Your Friend: Higher!
Your Guess: 19
Your Friend: Higher!
Your Friend: 22
Your Guess: Lower!
Your Guess: 20
Your Friend: Higher!
Your Guess: 21
Your Friend: YOU GOT IT!  

Теперь вам потребовалось 7 догадок, чтобы понять это правильно. Но какие здесь отношения? Какое наибольшее количество элементов можно угадать при каждом дополнительном предположении?

Guesses | Items
  1     |   2
  2     |   4
  3     |   8
  4     |   16
  5     |   32
  6     |   64
  7     |   128
  10    |   1024

Используя график, мы видим, что если мы используем двоичный поиск, чтобы угадать число от 1 до 100, нам потребуется максимум 7 попыток. Если бы у нас было 128 чисел, мы также могли бы угадать число за 7 попыток, но 129 чисел потребуют максимум 8 попыток (в отношении логарифмов здесь нам понадобилось бы 7 попыток для диапазона 128 значений, 10 предположений для диапазона значений 1024. 7 - логарифм 128, 10 - логарифм 1024 (основание 2)).

Обратите внимание, что я выделил «самое большее» жирным шрифтом. Обозначение Big-O всегда относится к худшему случаю. Если вам повезет, вы сможете угадать число за одну попытку, и поэтому в лучшем случае будет O (1), но это уже другая история.

Мы видим, что при каждом предположении наш набор данных сокращается. Хорошее практическое правило для определения того, имеет ли алгоритм логарифмическое время, - это посмотреть, сжимается ли набор данных в определенном порядке после каждой итерации.

А как насчет O (n log n)?

В конечном итоге вы столкнетесь с линейным алгоритмом O (n log (n)). Эмпирическое правило, приведенное выше, применяется снова, но на этот раз логарифмическая функция должна выполняться n раз, например. уменьшение размера списка в n раз, что происходит в таких алгоритмах, как сортировка слиянием.

Вы можете легко определить, равно ли алгоритмическое время n log n. Ищите внешний цикл, который выполняет итерацию по списку (O (n)). Затем посмотрите, есть ли внутренний цикл. Если внутренний цикл вырезание / уменьшение набора данных на каждой итерации, этот цикл равен (O (log n)), и поэтому общий алгоритм будет = O (n log n) < / сильный>.

Отказ от ответственности: пример логарифма веревки был взят из превосходного Книга" Mathematician's Delight "У. Сойера.

person benscabbia    schedule 08.10.2016
comment
In our example above, our 'growth rate' is O(log n). For every additional loop, the force our rope can handle is 10 times more, поддерживается диаграммой, которая показывает n == количество петель и our 'growth rate' = ›10 ^ n, что НЕ является log n. Пример можно исправить, сделав n=# horses, что требует ограничения log n циклов. Плохие педагогические примеры производят студентов, которые только верят, что понимают. - person psimpson; 21.10.2019

Логарифмическое время выполнения (O(log n)) по существу означает, что время выполнения растет пропорционально логарифму размера ввода - например, если 10 элементов занимают самое большее некоторое количество времени x, а 100 элементов - максимум, скажем, 2x, а 10 000 элементов занимают самое большее 4x, тогда это выглядит как O(log n) временная сложность.

person Anon.    schedule 21.02.2010
comment
+1, но вы действительно должны указать, что это log2, а не log10. - person Adriano Varoli Piazza; 21.02.2010
comment
log2 или log10 не имеет значения. Они различаются только масштабным коэффициентом, что делает их одного порядка, то есть они по-прежнему растут с одинаковой скоростью. - person Noldorin; 21.02.2010
comment
Самое интересное в логарифмах заключается в том, что при сравнении относительных высот точное основание, которое вы используете, не имеет значения. log 10,000 / log 100 равно 2 независимо от того, какую базу вы используете. - person Anon.; 21.02.2010
comment
Чтобы быть придирчивым, O (lg n) означает, что время выполнения не более пропорционально lg n. То, что вы описываете, - это Тета (LG N). - person ; 21.02.2010
comment
@rgrig: Это правда. Я отредактировал самое большее несколько, чтобы указать на верхнюю границу природы большого О. - person Anon.; 21.02.2010
comment
@rgrig он описал как O, так и theta: Theta (lg n) подразумевает O (lg n) - person klochner; 21.02.2010
comment
@klochner: что такое четное число? 1 + 1 - четное число, вы описали число 2 нет, он описал как четные числа, так и число 2, потому что число 2 подразумевает четность. Что ты думаешь? - person ; 22.02.2010
comment
@rgrig - я прочитал ваш комментарий как относящийся к примеру, а не к определению. Если мы придираемся к мелочам, он определил Theta (в общих чертах) и описал функцию, которая одновременно является O и Theta. - person klochner; 22.02.2010
comment
@klochner: Ты выигрываешь игру в придирки :) Я должен был сказать, определись. - person ; 22.02.2010
comment
Но в информатике мы считаем O (log n) равным O (log2 n), но это не имеет значения для O (). - person ChuckCottrill; 19.10.2013

Сначала рекомендую вам прочитать следующую книгу;

Алгоритмы (4-е издание)

Вот некоторые функции и их ожидаемые сложности. Цифры указывают частоту выполнения операторов.

Вот некоторые функции и их ожидаемые сложности

Следующая Таблица сложности Big-O также взята из bigocheatsheet  Таблица сложности Big-O < / а>

Наконец, очень простая витрина показывает, как она рассчитывается;

Анатомия частот выполнения операторов программы.

Анализ времени работы программы (пример).

«Анализ

person Teoman shipahi    schedule 02.07.2017
comment
Я бы не стал класть O (n log n) в корзину плохих. Он принадлежит к ярмарке. - person André Werlang; 02.12.2017
comment
При просмотре диаграммы сложности big-O (выше) вы должны помнить, что O (n) - это фактическая линейная точка, а не розовая / оранжевая граница. @Andre Вот почему O (n log n) правильно помечен в скобке «плохая» производительность, это худшая производительность, чем линейная. - person JavaBeast; 08.03.2018
comment
@JavaBeast правильно, хотя производительность O (n log n) технически хуже, чем O (n), обратитесь к таблице выше, в которой представлено их хорошее сравнение (см. Рост этих двух). В противном случае диаграмма из другого источника противоречива, потому что она помещает O (1) и O (log n) в одно и то же хорошее / отличное. их относительный порядок роста сравним с O (n) и O (n log n). tl; dr; O (n log n) не отлично, но далеко не плохо. - person André Werlang; 09.03.2018
comment
Я согласен с @ AndréWerlang здесь. Например, Quicksort считается довольно эффективным алгоритмом сортировки, а его средняя сложность составляет O (n log n), и он определенно не заслуживает того, чтобы его помещали в корзину. - person Teoman shipahi; 09.03.2018
comment
Это неверный ответ! Предполагается, что N = N * N. На самом деле N = N! Ваш пример на самом деле N в кубе. Вы делаете то же самое в своем графике. Ваш O (n) на самом деле должен разделять ужасное и плохое. Математическое доказательство: вы говорите, что цикл for постоянен с O (1). Это то, что на самом деле означает 1, не зависит от N. Это просто означает не переменную. Но это переменная величина, поскольку она зависит от N. Дважды N и в половине случаев. Следовательно, это недействительно. Если это из той книги, не покупайте! Графический код, который вы показали, ненастоящий, это шутка, послушайте, Круто, это означает, что три человека занимаются сексом одновременно! мой Бог - person jgmjgm; 08.01.2019
comment
Разве O (n) не должно быть по диагонали? - person gyosifov; 22.09.2019
comment
@csguy о чем ты говоришь? - person Teoman shipahi; 02.01.2020
comment
посмотри, что сказал @jgmjgm (я тоже согласен) - person csguy; 02.01.2020
comment
Что не так с последней картинкой? Это довольно точно, показывает частоту выполнения. График - еще один предмет для обсуждения, я воспринял его как приблизительный ориентир. Первый рисунок, просто показывает одну математику для разных исполнений алгоритма. Этот ответ не является академической справкой. - person Teoman shipahi; 02.01.2020
comment
Проверьте это = ›algs4.cs.princeton.edu/14analysis/ThreeSum.java .html в этом примере четко указано «Программа с кубическим временем выполнения». Пример, который я привел просто для демонстрации расчетов. - person Teoman shipahi; 03.01.2020
comment
Если вы сделаете стрелки понятными, это сделает его менее похожим на первый цикл log (1). Используйте плоттер вместо показанной там диаграммы. График очень мало значит. Это искажение, которое можно ввести в заблуждение. n log n по-прежнему попадает в категорию плохих для масштабирования, поскольку становится непропорционально хуже, чем больше нужно обработать. O (n) означает, что работа пропорциональна количеству предметов. Субъективная шкала требует объяснения. У вас есть таблица, которая пытается показать точные значения (но n log n равно n log 10), тогда вы переходите к самоуверенной диаграмме, которая не та таблица. - person jgmjgm; 06.01.2020

Вы можете думать об O (log N) интуитивно, говоря, что время пропорционально количеству цифр в N.

Если операция выполняет работу с постоянным временем для каждой цифры или бита ввода, вся операция займет время, пропорциональное количеству цифр или битов на входе, а не величине ввода; таким образом, O (log N), а не O (N).

Если операция принимает серию решений с постоянным временем, каждое из которых уменьшает вдвое (уменьшает в 3, 4, 5 ...) размер входных данных, которые необходимо учитывать, для всего потребуется время, пропорциональное логарифмической базе 2 (основание 3 , основание 4, основание 5 ...) размера N ввода, а не O (N).

И так далее.

person moonshadow    schedule 21.02.2010
comment
Я считаю, что это достаточно точно и легче понять, чем большинство объяснений. - person T .; 21.02.2010
comment
это объяснение log<sub>10</sub> N, не так ли? - person LiuYan 刘研; 14.04.2011
comment
@LiuYan 刘 研 они не сказали, в какой базе было число цифр. В любом случае, log₂ (n) = log₁₀ (n) / log₁₀ (2) и 1 / log₁₀ (2), следовательно, является постоянным множителем, с тем же принципом, применимым ко всем другим базам. Это показывает две вещи. Во-первых, принцип лунной тени применяется к любой базе (хотя чем ниже база, тем меньше зазубрин в оценке), а также то, что O (log n) равно O (log n), независимо от того, на какой основе расчет, который привел вас к такому выводу. - person Jon Hanna; 03.09.2012
comment
пропорциональные ... каждая из которых половинки размера входа ?????? - person csguy; 02.01.2020

Лучший способ, которым мне всегда приходилось мысленно визуализировать алгоритм, работающий за O (log n), выглядит следующим образом:

Если вы увеличиваете размер задачи на мультипликативную величину (т.е. умножаете ее размер на 10), работа увеличивается только на аддитивную величину.

Примените это к вашему вопросу о двоичном дереве, чтобы у вас было хорошее приложение: если вы удвоите количество узлов в двоичном дереве, высота увеличится только на 1 (аддитивная величина). Если вы удвоите его снова, он все равно увеличится только на 1. (Очевидно, я предполагаю, что он останется сбалансированным и тому подобное). Таким образом, вместо того, чтобы удваивать объем работы при умножении размера проблемы, вы выполняете лишь немного больше работы. Вот почему алгоритмы O (log n) великолепны.

person DivineWolfwood    schedule 22.02.2010
comment
Поскольку 2 ^ x является обратным логарифму, то будет ли верно следующее? Если вы увеличиваете размер задачи на [аддитивную величину], то работа увеличивается на мультипликативную величину. - person Strawberry; 01.05.2021

Что такое log b (n)?

Это количество раз, когда вы можете несколько раз разрезать бревно длины n на b равных частей, прежде чем достигнете секции размером 1.

person Chad Brewbaker    schedule 19.03.2010
comment
Отличный комментарий! Это краткий и точный ответ, который мне нужен. - person DennisL; 06.02.2018

Алгоритмы «разделяй и властвуй» обычно имеют logn компонент времени выполнения. Это происходит из-за многократного уменьшения вдвое входных данных.

В случае бинарного поиска на каждой итерации вы выбрасываете половину ввода. Следует отметить, что в нотации Big-O лог - это лог-база 2.

Изменить: как уже отмечалось, база журнала не имеет значения, но при вычислении производительности алгоритма Big-O коэффициент журнала будет зависеть от уменьшения вдвое, поэтому я считаю его базой 2.

person David Kanarek    schedule 21.02.2010
comment
Почему это лог-база 2? В рандомизированной быстрой сортировке, например, я не думаю, что это база 2. Насколько я знаю, база не имеет значения, поскольку логарифмическая база a (n) = log2 (n) / log2 (a), поэтому каждый логарифм отличается от другого константой, а константы игнорируются в нотации большого числа. На самом деле, запись основания журнала в нотации большого числа, на мой взгляд, является ошибкой, поскольку вы пишете константу. - person IVlad; 21.02.2010
comment
Re log - это база журнала 2: stackoverflow.com/questions/1569702/is-big-ologn-log-base-e/ - person user200783; 21.02.2010
comment
Совершенно верно, что его можно преобразовать в любую базу, и это не имеет значения, но если вы пытаетесь получить производительность Big-O и видите постоянное уменьшение вдвое, это помогает понять, что вы не увидите отражения базы 10 журнала в коде. - person David Kanarek; 21.02.2010
comment
В стороне: в таких вещах, как B-деревья, где узлы имеют разветвление более чем на 2 (т. Е. Шире, чем двоичное дерево), вы все равно увидите рост O (logn), потому что он по-прежнему разделяет и властвует. , но основание журнала будет связано с разветвлением. - person Roger Lipscombe; 22.02.2010
comment
На самом деле, отступление от журнала 2 оказалось весьма полезным. - person Dan Rosenstark; 05.02.2019

Но что такое O (log n)? Например, что значит сказать, что высота> полного двоичного дерева равна O (log n)?

Я бы перефразировал это как «высота полного двоичного дерева равна log n». Расчет высоты полного двоичного дерева был бы O (log n), если бы вы двигались вниз шаг за шагом.

Я не могу понять, как определить функцию с логарифмическим временем.

Логарифм - это, по сути, обратное возведение в степень. Итак, если каждый «шаг» вашей функции исключает фактор элементов из исходного набора элементов, это алгоритм логарифмического времени.

В примере с деревом вы легко можете увидеть, что понижение уровня узлов сокращает экспоненциальное количество элементов по мере того, как вы продолжаете обход. Популярный пример просмотра телефонной книги с сортировкой по именам, по сути, эквивалентен просмотру двоичного дерева поиска (средняя страница является корневым элементом, и вы можете на каждом шаге сделать вывод, идти влево или вправо).

person user2421873    schedule 26.05.2013
comment
+1 за упоминание логарифма - это, по сути, обратное возведение в степень. - person talonx; 16.11.2013

O (log n) немного вводит в заблуждение, точнее, это O (log 2 n), то есть (логарифм с основанием 2).

Высота сбалансированного двоичного дерева равна O (log 2 n), поскольку каждый узел имеет два (обратите внимание на «два», как в log 2 n) дочерних узла. Итак, дерево с n узлами имеет высоту log 2 n.

Другой пример - двоичный поиск, время выполнения которого равно O (log 2 n), потому что на каждом шаге вы делите пространство поиска на 2.

person stmax    schedule 21.02.2010
comment
O (log n) имеет тот же порядок, что и O (ld n) или O (LN n). Они пропорциональны. Я понимаю, что в учебных целях проще использовать ld. - person helios; 21.02.2010
comment
точнее это O (ld n) - Нет, это не так: все журналы имеют один и тот же порядок (каждый отличается от других только некоторым постоянным коэффициентом масштабирования, который игнорируется / игнорируется). - person ChrisW; 21.02.2010
comment
ты прав, Крис, очень плохая формулировка. должен был сказать это, как это сделал helios. это помогает для изучения / понимания, но, наконец, все журналы в том же порядке. - person stmax; 23.02.2010

Эти 2 случая займут время O (log n)

case 1: f(int n) {
      int i;
      for (i = 1; i < n; i=i*2)
        printf("%d", i);
    }


 case 2  : f(int n) {
      int i;
      for (i = n; i>=1 ; i=i/2)
        printf("%d", i);
    }
person Ravi Bisla    schedule 05.07.2013
comment
Я уверен, что что-то упускаю, но разве я не всегда буду нулем, а циклы будут работать вечно в обоих случаях, поскольку 0 * 2 = 0 и 0/2 = 0? - person dj_segfault; 29.09.2013
comment
@dj_segfault, это была моя ошибка. Думаю, теперь это имеет смысл .. :) - person Ravi Bisla; 30.09.2013
comment
@RaviBisla В других ответах указано, что ввод 10 займет 1 раз до 10 циклов, а ввод 100 займет в 3 раза больше времени ввода, чем 1, что определенно не относится к этим примерам. stackoverflow.com/a/2307330/1667868 - person Sven van den Boogaart; 23.10.2017

Это просто означает, что время, необходимое для этой задачи, растет с log (n) (пример: 2 секунды для n = 10, 4 секунды для n = 100, ...). Прочтите статьи Википедии о алгоритме двоичного поиска и Big O Notation для большей точности.

person Valentin Rocher    schedule 21.02.2010

O(log n) относится к функции (или алгоритму, или шагу в алгоритме), работающей в течение периода времени, пропорционального логарифму (обычно по основанию 2 в большинстве случаев, но не всегда, и в любом случае это несущественно для обозначения большого O * ) размера входа.

Логарифмическая функция является обратной по отношению к экспоненциальной функции. Другими словами, если ваш ввод растет экспоненциально (а не линейно, как вы обычно это считаете), ваша функция растет линейно.

O(log n) Время работы очень распространено в любом виде приложения «разделяй и властвуй», потому что вы (в идеале) каждый раз сокращаете работу вдвое. Если на каждом этапе деления или завоевания вы выполняете работу с постоянным временем (или работу, которая не является постоянной по времени, а время растет медленнее, чем O(log n)), тогда вся ваша функция равна O(log n). Довольно часто каждый шаг требует на входе линейного времени; это составит общую временную сложность O(n log n).

Сложность выполнения двоичного поиска является примером O(log n). Это связано с тем, что при двоичном поиске вы всегда игнорируете половину своего ввода на каждом последующем шаге, разделяя массив пополам и сосредотачиваясь только на одной половине на каждом шаге. Каждый шаг является постоянным по времени, потому что в двоичном поиске вам нужно сравнить только один элемент с вашим ключом, чтобы понять, что делать дальше, независимо от того, насколько велик рассматриваемый вами массив в любой момент. Таким образом, вы выполняете приблизительно log (n) / log (2) шагов.

Сложность выполнения сортировки слиянием является примером O(n log n). Это связано с тем, что вы делите массив пополам на каждом шаге, в результате чего получается примерно log (n) / log (2) шагов. Однако на каждом этапе вам необходимо выполнять операции слияния для всех элементов (будь то одна операция слияния для двух подсписок из n / 2 элементов или две операции слияния для четырех подсписок из n / 4 элементов, это не имеет значения, потому что это добавляет к необходимости проделайте это для n элементов на каждом шаге). Таким образом, общая сложность составляет O(n log n).

* Помните, что в нотации большого О, по определению, константы не имеют значения. Кроме того, изменение базового правила для логарифмов, единственная разница между логарифмами разных оснований заключается в постоянный коэффициент.

person Platinum Azure    schedule 21.02.2010
comment
Последнее * примечание решило мою путаницу с логарифмами, основанными на 2 или 10 :) Большое спасибо. - person yahya; 18.09.2015

Проще говоря: на каждом этапе вашего алгоритма вы можете сократить работу вдвое. (Асимптотически эквивалентно третьему, четвертому, ...)

person Brian R. Bondy    schedule 22.02.2010
comment
Это очень неточный ответ. Прежде всего, вы можете подумать о сокращении работы пополам только в случае логарифма в основании 2. Это действительно невероятно, как этот ответ (и большинство ответов на исходный вопрос) получил столько голосов «за». (Асимптотически эквивалентно третьему, четвертому, ...)? Зачем отвечать на вопрос, если нет времени? - person nbro; 20.02.2016

Если вы построите логарифмическую функцию на графическом калькуляторе или чем-то подобном, вы увидите, что она растет очень медленно - даже медленнее, чем линейная функция.

Вот почему так востребованы алгоритмы с логарифмической временной сложностью: даже для действительно больших n (скажем, n = 10 ^ 8, например) они работают более чем приемлемо.

person Hadewijch Debaillie    schedule 21.02.2010

Но что такое O (log n)

Это означает, что «поскольку n стремится к infinity, time стремится к a*log(n), где a - постоянный коэффициент масштабирования».

Или на самом деле это не совсем так; скорее это означает что-то вроде «time, разделенное на a*log(n), имеет тенденцию к 1».

«Тенденция к» имеет обычное математическое значение от «анализа»: например, что «если вы выберете любую произвольно малую ненулевую константу k, то я смогу найти соответствующее значение X, такое, что ((time/(a*log(n))) - 1) будет меньше k для всех значений n больше X ".


Проще говоря, это означает, что уравнение времени может иметь некоторые другие компоненты: например, у него может быть постоянное время запуска; но эти другие компоненты бледнеют в сторону незначительности для больших значений n, а a * log (n) является доминирующим термином для больших n.

Обратите внимание, что если бы уравнение было, например ...

время (n) = a + b log (n) + c n + d n n

... тогда это будет O (n в квадрате), потому что независимо от того, какие значения констант a, b, c и ненулевые d, член d*n*n всегда будет преобладать над другими для любого достаточно большого значения n .

Это то, что означает бит O: он означает «каков порядок доминирующего члена для любого достаточно большого n».

person ChrisW    schedule 21.02.2010
comment
Это не правильно. en.wikipedia.org/wiki/ - person Michael Graczyk; 16.07.2012

Могу добавить кое-что интересное, что давно прочитал в книге Кормена и др. Теперь представьте себе проблему, в которой мы должны найти решение в проблемном пространстве. Это проблемное пространство должно быть ограниченным.

Теперь, если вы можете доказать, что на каждой итерации вашего алгоритма вы отрезаете часть этого пространства, то есть не меньше некоторого предела, это означает, что ваш алгоритм работает за время O (logN).

Я должен отметить, что мы говорим здесь об относительном пределе дроби, а не об абсолютном. Бинарный поиск - классический пример. На каждом шаге мы выбрасываем половину проблемного места. Но бинарный поиск - не единственный такой пример. Предположим, вы каким-то образом доказали, что на каждом шаге выбрасываете не менее 1/128 проблемного пространства. Это означает, что ваша программа по-прежнему выполняется за время O (logN), хотя и значительно медленнее, чем бинарный поиск. Это очень хороший совет при анализе рекурсивных алгоритмов. Часто можно доказать, что на каждом шаге рекурсия не будет использовать несколько вариантов, и это приводит к отсечению некоторой доли в проблемном пространстве.

person SPIRiT_1984    schedule 04.02.2014

Каждый раз, когда мы пишем алгоритм или код, мы пытаемся проанализировать его асимптотическую сложность. Он отличается от своей временной сложности.

Асимптотическая сложность - это поведение времени выполнения алгоритма, в то время как временная сложность - это фактическое время выполнения. Но некоторые люди используют эти термины как синонимы.

Поскольку временная сложность зависит от различных параметров, а именно.
1. Физическая система
2. Язык программирования
3. Стиль кодирования
4. И многое другое ......

Фактическое время выполнения не является хорошим показателем для анализа.


Вместо этого мы принимаем размер ввода в качестве параметра, потому что независимо от кода, ввод одинаковый. Таким образом, время выполнения является функцией размера ввода.

Ниже приведен пример алгоритма линейного времени.


Линейный поиск
Учитывая n входных элементов, для поиска элемента в массиве вам нужно не более 'n' сравнений. Другими словами, независимо от того, какой язык программирования вы используете, какой стиль кодирования вы предпочитаете, в какой системе вы его выполняете. В худшем случае требуется всего n сравнений. Время выполнения линейно пропорционально размеру ввода.

И это не просто поиск, какой бы ни была работа (приращение, сравнение или любая операция), это функция размера ввода.

Поэтому, когда вы говорите, что любой алгоритм - это O (log n), это означает, что время выполнения равно log, умноженному на размер ввода n.

По мере увеличения размера входных данных выполняемая работа (здесь время выполнения) увеличивается (отсюда пропорциональность).

      n      Work
      2     1 units of work
      4     2 units of work
      8     3 units of work

Посмотрите, как увеличился размер ввода, увеличилась и проделанная работа, и она не зависит от какой-либо машины. И если вы попытаетесь узнать стоимость единиц работы, она фактически зависит от указанных выше параметров. Она будет меняться в зависимости от системы и всего остального.

person Sanjay Kumar    schedule 09.02.2018

Я могу привести пример для цикла for и, возможно, однажды поймете концепцию, может быть, ее будет проще понять в разных контекстах.

Это означает, что в цикле шаг растет экспоненциально. Например.

for (i=1; i<=n; i=i*2) {;}

Сложность в O-нотации этой программы составляет O (log (n)). Давайте попробуем пропустить его вручную (n где-то между 512 и 1023 (исключая 1024):

step: 1   2   3   4   5    6    7    8     9     10
   i: 1   2   4   8   16   32   64   128   256   512

Хотя n находится где-то между 512 и 1023, выполняется всего 10 итераций. Это связано с тем, что шаг в цикле растет экспоненциально и, таким образом, для достижения завершения требуется всего 10 итераций.

Логарифм x (по основанию a) является обратной функцией a ^ x.

Это все равно, что сказать, что логарифм - это величина, обратная экспоненте.

Теперь попробуйте увидеть это так: если экспонента растет очень быстро, то логарифм растет (обратно) очень медленно.

Разница между O (n) и O (log (n)) огромна, как и разница между O (n) и O (a ^ n) (a - константа).

person Ely    schedule 16.05.2015

Фактически, если у вас есть список из n элементов, и вы создаете бинарное дерево из этого списка (как в алгоритме «разделяй и властвуй»), вы будете продолжать делить на 2, пока не дойдете до списков размером 1 (листья).

На первом этапе вы делите на 2. Затем у вас есть 2 списка (2 ^ 1), вы делите каждый на 2, так что у вас есть 4 списка (2 ^ 2), вы снова делите, у вас есть 8 списков (2 ^ 3 ) и так далее, пока размер вашего списка не станет равным 1

Это дает вам уравнение:

n/(2^steps)=1 <=> n=2^steps <=> lg(n)=steps

(вы берете lg с каждой стороны, lg - основание журнала 2)

person Dinaiz    schedule 25.11.2016
comment
Пока какое-то вредоносное ПО не начнет вставлять новый список с длиной x на два уровня перед выходными узлами. Тогда это будет казаться бесконечным циклом ... - person Francis Cugler; 19.02.2017
comment
Я не получил вашего комментария. Мое объяснение неверно? - person Dinaiz; 28.02.2017
comment
Я всего лишь гипотетически пошутил. Я на самом деле ничего не имел в виду. - person Francis Cugler; 26.03.2017

Полный двоичный пример - O (ln n), потому что поиск выглядит так:

1 2 3 4 5 6 7 8 9 10 11 12

Поиск 4 дает 3 совпадения: 6, 3, затем 4. И log2 12 = 3, что является хорошим приближением к количеству совпадений, где необходимо.

person Amirshk    schedule 21.02.2010
comment
спасибо за пример. Здесь ясно сказано, как наш алгоритм может использовать логарифмическое время в методе «разделяй и властвуй». - person Abc; 08.08.2016
comment
Итак, если это цикл n / 2, он всегда log (n)? - person Gil Beyruth; 10.12.2016

Дерево

log x to base b = y является инверсией b^y = x

Если у вас есть M-арное дерево глубины d и размера n, то:

  • обход всего дерева ~ O (M ^ d) = O (n)

  • Прохождение единственного пути в дереве ~ O (d) = O (войдите в базу M)

person Khaled.K    schedule 28.05.2013

В информационных технологиях это означает, что:

  f(n)=O(g(n)) If there is suitable constant C and N0 independent on N, 
  such that
  for all N>N0  "C*g(n) > f(n) > 0" is true.

Кажется, что эти обозначения в основном заимствованы из математики.

В этой статье есть цитата: Д.Э. Кнут, "БОЛЬШОЙ ОМИКРОН, БОЛЬШАЯ ОМЕГА И БОЛЬШАЯ ТЕТА", 1976:

На основе обсуждаемых здесь вопросов я предлагаю членам SIGACT и редакторам журналов по информатике и математике использовать обозначения, как определено выше, если лучшая альтернатива не будет найдена достаточно скоро.

Сегодня 2016 год, но мы используем его до сих пор.


В математическом анализе это означает, что:

  lim (f(n)/g(n))=Constant; where n goes to +infinity

Но даже в математическом анализе иногда этот символ использовался в значении «C * g (n)> f (n)> 0».

Насколько я знаю из университета, символ был введен немецким математиком Ландау (1877-1938).

person bruziuz    schedule 02.04.2014

Если вы ищете ответ, основанный на интуиции, я хотел бы предложить вам две интерпретации.

  1. Представьте себе очень высокий холм с очень широким основанием. Добраться до вершины холма можно двумя способами: один - это выделенная тропа, идущая по спирали вокруг холма, достигающая вершины, другой: небольшая терраса, похожая на резные фигурки, вырезанные для создания лестницы. Теперь, если первый способ достигает за линейное время O (n), второй - O (log n).

  2. Представьте себе алгоритм, который принимает целое число n в качестве входных данных и завершается за время, пропорциональное n, тогда это O (n) или theta (n), но если он выполняется во времени, пропорциональном number of digits or the number of bits in the binary representation on number, то алгоритм выполняется за O (log n ) или тета (log n) времени.

person mickeymoon    schedule 26.05.2013
comment
пожалуйста, отредактируйте. имеет O (n) или theta (n) в обоих сценариях ...? Кроме того, я много слышал об этом, размер против # цифр. Мы говорим, что размер === 128 для n = 10000000 и цифр === 8 для n = 10000000? Пожалуйста, поясните. - person Cody; 12.11.2013

O (logn) - это одна из полиномиальных временных сложностей для измерения производительности любого кода во время выполнения.

Надеюсь, вы уже слышали об алгоритме двоичного поиска.

Предположим, вам нужно найти элемент в массиве размера N.

По сути, выполнение кода похоже на N N / 2 N / 4 N / 8 .... и т. Д.

Если вы просуммируете всю работу, проделанную на каждом уровне, вы получите n (1 + 1/2 + 1/4 ....), что равно O (logn)

person Hakit01    schedule 30.05.2019

Алгоритмы в парадигме Divide and Conquer имеют сложность O (logn). Вот один пример: вычислите свою собственную степенную функцию,

int power(int x, unsigned int y)
{
    int temp;
    if( y == 0)
        return 1;
    temp = power(x, y/2);
    if (y%2 == 0)
        return temp*temp;
    else
        return x*temp*temp;
}

из http://www.geeksforgeeks.org/write-ac-program-to-calculate-powxn/

person kiriloff    schedule 27.06.2015

Я хотел бы добавить, что высота дерева - это длина самого длинного пути от корня до листа, а высота узла - это длина самого длинного пути от этого узла до листа. Путь означает количество узлов, с которыми мы сталкиваемся при обходе дерева между двумя узлами. Чтобы достичь временной сложности O (log n), дерево должно быть сбалансировано, что означает, что разница в высоте между дочерними элементами любого узла должна быть меньше или равна 1. Следовательно, деревья не всегда гарантируют временную сложность. O (log n), если они не сбалансированы. Фактически в некоторых случаях временная сложность поиска в дереве может быть O (n) в худшем случае.

Вы можете взглянуть на деревья баланса, такие как AVL tree. Он работает над балансировкой дерева при вставке данных, чтобы сохранить временную сложность (log n) при поиске в дереве.

person Traveling Salesman    schedule 01.12.2013

person    schedule
comment
@ Дэвид Торнли »Ах, попался. Я думал, что сделал это очевидным, сказав, что у каждого жителя или компании есть телефонная книга, но я отредактирую, чтобы выделить это. - person John Feminella; 22.02.2010
comment
@cletus: Боюсь, что случайно. Я выбрал его, потому что в телефонных книгах есть большая буква N, люди понимают, что они из себя представляют и чем занимаются, а также потому, что это универсальный пример. К тому же в своем объяснении я использовал роботов! Победное многоборье. (Кроме того, похоже, что ваш ответ был сделан еще до того, как я стал участником StackOverflow с самого начала!) - person John Feminella; 23.02.2010
comment
@ Джон: не беспокойтесь. Было просто любопытно. :) - person cletus; 23.02.2010
comment
В офисе произошла ошибка, и каждая запись в каждой телефонной книге имеет дополнительный 0 в конце телефонного номера. Возьмите немного белого цвета и удалите каждый ноль. ‹- это не квадрат порядка N. N определяется как размер ввода. Размер ввода - это количество телефонных номеров, то есть количество номеров в книге, умноженное на количество книг. Это все еще операция с линейным временем. - person Billy ONeal; 10.04.2010
comment
@Billy: В этом примере N - это количество людей в одной книге. Поскольку каждый человек в телефонной книге также получает свою собственную копию книги, есть N идентичные телефонные книги, в каждой из которых N человека, что составляет O (N ^ 2). - person John Feminella; 10.04.2010
comment
@John Feminella: N, что касается Big Oh, это всегда размер входного набора. Если вы определяете N как что-то еще, это нормально, но вы не сделали этого выше .... - person Billy ONeal; 10.04.2010
comment
Бого-сортировка - это самый глупый алгоритм, который я когда-либо видел в своей жизни. В основном while (!isInOrder(deck)) { shuffle(deck); } - person ; 16.07.2011
comment
Это глупый алгоритм, но это не самый глупый алгоритм, который вы могли бы написать. :) - person John Feminella; 16.07.2011
comment
@JohnFeminella Я понимаю, к чему вы идете с примером перетасованных страниц, но описание исправления похоже на сортировку вставкой, а не, скажем, сортировку слиянием или быструю сортировку. - person Greg Bacon; 21.04.2012
comment
На самом деле алгоритм, который люди используют для поиска имен в телефонных книгах, не является бинарным поиском. Это интерполяционный поиск, который в среднем составляет O (log log n)! - person user541686; 26.05.2013
comment
Разве O (1) не лучший случай, а не худший, как это странно выделено? - person Svip; 26.05.2013
comment
Разве не возьмите белый цвет и не удалите каждый ноль O (n · m), где n - количество записей, а m - количество напечатанных телефонных книг? - person Ben Hodgson; 26.05.2013
comment
@BenHodgson Вы в целом правы. Однако в этом случае, поскольку список клиентов, получающих копии телефонной книги, определяется как каждое лицо или предприятие в телефонной книге, n == m. - person Ken Bellows; 26.05.2013
comment
@Svip Я считаю, что причина, по которой он был выделен как наихудший случай, заключается в том, что существует наивный постоянный процесс поиска заданной записи на странице, который включает сканирование каждой записи по порядку, пока не будет найдена целевая запись. Если на странице 50 записей, наихудший случай - 50 операций, что составляет O (1). Потенциально вы могли бы добиться большего, например, если бы цель была 5-й на странице. В этом случае время, чтобы добиться большего, варьируется и неизвестно, поскольку есть 49 лучших случаев, но наихудший случай - это всегда постоянное количество операций. - person Ken Bellows; 26.05.2013
comment
@KenB Я думал, что O (1) означает постоянное время, т.е. количество операций не зависит от ввода. 50 записей, требующих 50 операций, будут O (n). en.wikipedia.org/wiki/Big_O_notation#Orders_of_common_functions - person Svip; 30.05.2013
comment
@Svip O (n) подразумевает изменчивость. 50 операций - фиксированное число, если вы рассматриваете только наихудший случай, поскольку наихудший случай всегда составляет ровно 50 записей. Честно говоря, это немного влезает в семантику. - person Ken Bellows; 03.06.2013
comment
Отличная иллюстрация большой буквы O! Один комментарий к случаю O (1): у вас есть заявление об отказе от ответственности, в котором говорится, что переход к заданному номеру страницы - это постоянное время, однако я думаю, что это больше похоже на log (n). Лучшим примером для O (1) был бы выбор случайного телефонного номера путем переворота случайной страницы в телефонной книге и выбора случайного числа на этой странице. У этого есть постоянное время работы, независимо от количества записей в телефонной книге, и никаких заявлений об отказе от ответственности не требуется. - person Jo Hund; 05.06.2013
comment
Быстрый вопрос по делу: в офисе типографии произошла путаница, и в нашу телефонную книгу были вставлены все страницы в произвольном порядке. Исправьте порядок, чтобы он был правильным, просматривая имя на каждой странице, а затем помещая эту страницу в соответствующее место в новой пустой телефонной книге. Не должно быть сложности, это должно быть O (n!), А не O (n log n) - person Balkrishan Nagpal; 13.03.2014
comment
@Bagira: Нет; подумайте о колоде карт. Есть n! способы перетасовать карты, но их сортировка не занимает n! времени. - person John Feminella; 13.03.2014
comment
Извините, но я смог понять и на примере карточек. Меня беспокоит, что при случайном порядке вы не можете выбрать подмножество, которое вам нужно посетить. Поскольку элементы не упорядочены, в худшем случае вы можете двигаться в неправильном направлении, и вам придется пересекать и другое подмножество, и каждый раз, когда размер списка уменьшается на единицу, поэтому я сказал n !. Если вы уберете слово Random из предложения, это станет для меня смыслом. Спасибо - person Balkrishan Nagpal; 18.03.2014
comment
Сбивает с толку то, что вы говорите, что этот список отсортирован от лучшего к худшему, но затем начинайте список с худшего случая. - person Adam; 31.07.2014
comment
@Adam: O (1) наихудший случай означает, что худшее, что могло быть, - это O (1), который является лучшим из всех возможных миров. Если вы сказали, что худшая оценка за тест в классе была 100%, это очень хорошо, а не плохо! - person John Feminella; 31.07.2014
comment
какова будет временная сложность этой функции log (n!) - person Walter; 30.10.2014
comment
@Walter O (log n!) Эквивалентен O (n log n). - person John Feminella; 30.10.2014
comment
Насколько невероятно, что этот ответ был принят на исходный вопрос? Этот ответ, на мой взгляд, не объясняет, что такое время O (log n) на самом деле: вы приводите только много примеров (в том числе вещей, которые почти не имеют отношения к вопросу), не объясняя точно (всегда), почему сложность этих операции действительно правильные. Невероятный! - person nbro; 12.08.2015
comment
@iAteABug_And_iLiked_it Я дал очень простой ответ для понимания O (log n) - person 2cupsOfTech; 12.01.2016
comment
Почему удаление последней цифры каждого числа имеет сложность O (n2)? Я предполагал, что это будет O (n). - person Ricky; 15.03.2016
comment
Ребята, я нашел решение для этой ссылки лучше, чем заданный вопрос: stackoverflow.com/questions/9152890/ - person Raghu; 01.07.2016
comment
Алгоритм O (n * n!) На самом деле неограничен - рандомизированный богосорт неограничен (детерминированный богосорт нет) - нет гарантии, что робот когда-либо закончит. - person Bernhard Barker; 24.06.2017
comment
Алгоритм O (n ^ n) должен быть более конкретным, я думаю, O (n ^ 2 * 2 ^ n) (потому что это n*n+2n*n+4n*n+...+n*n*2^n, если я правильно понимаю, то есть: мы печатаем n книг размера n на первом этапе, а затем перепечатка оригиналов и репринтов). Также можно было бы использовать краткое объяснение. - person Bernhard Barker; 24.06.2017
comment
Я просто оставлю комментарий, чтобы отметить, что двоичный поиск не является алгоритмом «разделяй и властвуй». - person code_dredd; 26.09.2017
comment
Парень по имени Джон вошел и ударил. - person Tushar Pandey; 19.02.2019
comment
что означает элементы, над которыми выполняется действие, обозначают цифры n - person csguy; 01.01.2020
comment
O (n · n!): Мы готовы загрузить ... Кажется, это должно быть O (n * (n-1)!) - person Nahrae; 08.04.2020
comment
@csguy - ознакомьтесь с ответом moonshadow в этом посте, и вы его поймете. В основном это означает, что если у вас есть номер, например 12000, вы не выполните операцию 12000 раз, а скорее 5 раз (потому что она состоит из 5 цифр). Увеличение числа также увеличит сложность, но только пропорционально, поэтому, если вы увеличите число до 112000, сложность вырастет только на 1 (потому что теперь у вас 6 цифр), а не на фактическое приращение, которое составляет 100000). - person BornToCode; 03.06.2020