Я слышал несколько раз, что при достаточно малых значениях n O (n) можно рассматривать / обрабатывать так, как будто это O (1).
Пример :
Мотивация для этого основана на неверной идее, что O (1) всегда лучше, чем O (lg n), всегда лучше, чем O (n). Асимптотический порядок операции имеет значение только в том случае, если в реальных условиях размер проблемы действительно становится большим. Если n остается маленьким, то каждая проблема - O (1)!
Что достаточно мало? 10? 100? 1000? В какой момент вы говорите: «мы больше не можем рассматривать это как бесплатную операцию»? Есть ли эмпирическое правило?
Похоже, что это может быть в зависимости от домена или конкретного случая, но есть ли общие правила о том, как думать об этом?
asymptotics
rianjs
источник
источник
O(1)
за бесплатно . Причина первых нескольких предложений заключается в том, чтоO(1)
это константа , которая иногда может быть безумно медленной. Расчет, который занимает тысячу миллиардов лет независимо от ввода, являетсяO(1)
расчетом.Ответы:
Все порядки величины включают в себя постоянную , несколько из них на самом деле. Когда количество элементов достаточно велико, эта константа не имеет значения. Вопрос в том, достаточно ли мало элементов, чтобы эта константа доминировала.C
Вот визуальный способ думать об этом.
У всех есть постоянная запуска, которая определяет их начальную точку на оси Y. У каждого также есть критическая постоянная определяющая, насколько быстро они будут увеличиваться.C
Чтобы определить, какой алгоритм вы должны использовать, вам нужно оценить место пересечения времени выполнения. Например, решение с высоким временем запуска или высоким C будет проигрывать решению O ( n ) с низким временем запуска и низким C при довольно большом количестве элементов.O(1) C O(n) C
Вот пример из реального мира. Вы должны переместить кучу кирпичей через двор. Вы можете перемещать их по несколько раз своими руками или получить огромный медленный экскаватор, чтобы поднять и перевезти их за одну поездку. Каков ваш ответ, если есть три кирпича? Каков ваш ответ, если их три тысячи?
Вот пример CS. Допустим, вам нужен список, который всегда сортируется. Вы можете использовать дерево, которое будет держать себя в порядке для . Или вы можете использовать несортированный список и выполнять повторную сортировку после каждой вставки или удаления в O ( n log n ) . Поскольку операции с деревьями сложны (у них высокая константа), а сортировка очень проста (низкая константа), список, скорее всего, выиграет сотни или тысячи элементов.O(logn) O(nlogn)
Вы можете наблюдать подобные вещи, но, в конце концов, это поможет сравнительный анализ. Вы также должны следить за тем, сколько предметов у вас обычно есть, и снизить риск получения большего количества предметов. Вы также захотите документировать свое предположение, например, «производительность будет быстро снижаться по сравнению с элементами » или «мы принимаем максимальный размер набора X ».X X
Поскольку эти требования могут быть изменены, важно, чтобы такие решения принимались за интерфейс. В приведенном выше примере дерева / списка не показывайте дерево или список. Таким образом, если ваши предположения окажутся неверными или вы найдете лучший алгоритм, вы можете изменить свое решение. Вы даже можете сделать гибрид и динамически переключать алгоритмы по мере роста количества элементов.
источник
Это в значительной степени основано на ответах, уже опубликованных, но может предложить другую точку зрения.
Показательно, что в этом вопросе обсуждаются «достаточно малые значения n ». Весь смысл Big-O состоит в том, чтобы описать, как обработка растет в зависимости от того, что обрабатывается. Если обрабатываемые данные остаются небольшими, обсуждать Big-O не имеет значения, потому что вас не интересует рост (чего не происходит).
Иными словами, если вы идете на очень короткое расстояние по улице, может быть одинаково быстро ходить, пользоваться велосипедом или водить машину. Ходить может даже быстрее, если потребуется время, чтобы найти ключи от машины, или если вашему автомобилю нужен бензин и т. Д.
Для малых n используйте все, что вам удобно.
Если вы отправляетесь в поездку по пересеченной местности, вам нужно найти способы оптимизировать свое вождение, пробег и т. Д.
источник
n < infinity
.Цитата довольно расплывчатая и неточная. Есть как минимум три взаимосвязанных способа интерпретации.
Буквально математический момент позади этого состоит в том, что, если вас интересуют только случаи размером до некоторого предела, то существует только конечное число возможных экземпляров. Например, существует только конечное число графов до ста вершин. Если существует только конечное число экземпляров, вы, в принципе, можете решить проблему, просто составив справочную таблицу со всеми ответами на все возможные экземпляры. Теперь вы можете найти ответ, сначала проверив, что вход не слишком большой (что занимает постоянное время: если вход длиннее, чемК , это неверно), а затем ищите ответ в таблице (что занимает постоянное время: в таблице есть фиксированное количество записей). Обратите внимание, что фактический размер таблицы, вероятно, невероятно велик. Я сказал, что на сто вершин есть только конечное число графов, и это правда. Просто конечное число больше, чем количество атомов в наблюдаемой вселенной.
Более практичное дело, что, когда мы говорим , что время работы алгоритма является , это означает только то , что она асимптотически с п 2 шага, для некоторой константы C . То есть существует некоторая константа n 0 такая, что для всех n ≥ n 0 алгоритм выполняет примерно c n 2 шагов. Но возможноΘ ( н2) с п2 С N0 n ≥ n0 с п2 N0= 100 , 000 , 000 и вы заинтересованы только в случаях размера гораздо меньше, чем это. Асимптотическая квадратичная граница может даже не относиться к вашим маленьким экземплярам. Вам может повезти, и это может быть быстрее на небольших входах (или вам может не повезти, и это будет медленнее). Например, для малых , n 2 < 1000 n, поэтому вам лучше запустить квадратичный алгоритм с хорошими константами, чем линейный алгоритм с плохими константами. Реальный пример этого - асимптотически наиболее эффективные алгоритмы умножения матриц (варианты Копперсмита-Винограда , работающие во времени O (N N2< 1000 н ) редко используются на практике, потомучто O ШтрассенаO ( n2,3729) алгоритм работает быстрее, если ваши матрицы не очень большие.O ( n2,8074)
Третий момент заключается в том, что, если мало, n 2 и даже n 3 малы. Например, если вам нужно отсортировать несколько тысяч элементов данных, и вам нужно отсортировать их только один раз, любой алгоритм сортировки достаточно хорош:N N2 N3 Θ ( н2) Алгоритму все еще потребуется несколько десятков миллионов инструкций для сортировки ваших данных, что совсем немного времени на процессоре, который может выполнять миллиарды инструкций в секунду. Хорошо, есть и доступ к памяти, но даже медленный алгоритм займет меньше секунды, поэтому, вероятно, лучше использовать простой, медленный алгоритм и понять его правильно, чем использовать сложный, быстрый алгоритм и обнаружить, что он молниеносный но глючит и не сортирует данные должным образом.
источник
Нотация Big-O действительно только говорит о поведении для произвольного большого n. Например, означает, что существует константа c> 0 и целое число n 0, такое что f ( n ) < c n 2 для каждого n >е( n ) = O ( n2) N0 е( н ) < c n2 .N > n0
Во многих случаях вы можете найти константу c и сказать: «Для каждого n> 0 f (n) приблизительно равно ». Какая полезная информация иметь. Но в некоторых случаях это не так. Если f (n) = n 2 + 10 18 , то это полностью вводит в заблуждение. Так что если что-то есть O (n ^ 2), это не значит, что вы можете отключить свой мозг и игнорировать реальную функцию.с п2 N2+ 1018
С другой стороны, если вы когда-либо сталкиваетесь только со значениями n = 1, 2 и 3, то на практике это не имеет значения, что делает f (n) при n ≥ 4, так что вы могли бы также подумать, что f ( n) = O (1), с c = max (f (1), f (2), f (3)). И это то, что достаточно мало означает: если утверждение, что f (n) = O (1) не вводит вас в заблуждение, если единственные значения f (n), с которыми вы сталкиваетесь, «достаточно малы».
источник
Если это не растет, это O (1)
Заявление автора несколько аксиоматично.
Порядок роста описывает то, что происходит с объемом работы, которую вы должны выполнять по мере
N
увеличения. Если вы знаете, чтоN
это не увеличивается, ваша проблема эффективноO(1)
.Помните, что
O(1)
это не значит «быстро». Алгоритм , который всегда требует 1 триллион шагов к полон,O(1)
. Алгоритм, который занимает от 1 до 200 шагов, но никогда большеO(1)
. [1]Если ваш алгоритм выполняет в точности
N ^ 3
шаги, и вы знаете, что онN
не может быть больше 5, он никогда не может делать более 125 шагов, поэтому он эффективноO(1)
.Но опять же,
O(1)
не обязательно означает «достаточно быстро». Это отдельный вопрос, который зависит от вашего контекста. Если на завершение чего-то уходит неделя, вам, вероятно, все равно, технически ли этоO(1)
.[1] Например, поиск в хэше есть
O(1)
, хотя коллизии хэшей означают, что вам, возможно, придется просматривать несколько элементов в одном ведре, если существует жесткое ограничение на количество элементов в этом ведре.источник
g(n) = min(f(2^15), f(n))
- что в O (1). При этом константы на практике имеют большое значение, и ясно, что n может стать достаточно большим, чтобы был полезен асимптотический анализ.Практически, это тот момент, когда создание хеш-таблицы занимает больше, чем вы получаете выгоду от улучшенного поиска. Это будет сильно зависеть от того, как часто вы выполняете поиск по сравнению с тем, как часто вы делаете другие вещи. O (1) против O (10) не имеет большого значения, если вы сделаете это один раз. Если вы делаете это тысячи раз в секунду, даже это имеет значение (хотя, по крайней мере, это имеет значение с линейно возрастающей скоростью).
источник
Хотя цитата верна (но неопределенна), есть и опасности для нее. Имо, вы должны смотреть на сложность на любом этапе вашего приложения.
Слишком легко сказать: эй, у меня есть только небольшой список, если я хочу проверить, есть ли элемент А в списке, я просто напишу простой цикл, чтобы пройти по списку и сравнить элементы.
Затем ваш собеседник должен использовать список, видит вашу функцию и выглядит так: эй, я не хочу дубликатов в списке, поэтому он использует функцию для каждого элемента, добавленного в список.
(обратите внимание, это все еще небольшой сценарий списка.)
Спустя 3 года я пришел, и мой босс только что сделал большие продажи: наше программное обеспечение будет использоваться крупным национальным ритейлером. Раньше мы обслуживали только небольшие магазины. И теперь мой начальник ругается и ругается, почему программное обеспечение, которое всегда "работало нормально", теперь так ужасно медленно.
Оказывается, этот список был списком клиентов, и у наших клиентов было около 100 клиентов, поэтому никто не заметил. Операция заполнения списка была в основном операцией O (1), потому что она занимала менее миллисекунды. Ну, не так много, когда к нему нужно добавить 10.000 клиентов.
И спустя годы после первоначального плохого решения O (1), компания почти потеряла крупного клиента. Все из-за одной маленькой ошибки дизайна / предположения за годы до этого.
источник
Если у меня есть два алгоритма с этими временами:
Тогда существует некоторая точка, где они пересекаются. При
n
меньших значениях «линейный» алгоритм работает быстрее, а приn
больших - «логарифмический» алгоритм работает быстрее. Многие люди ошибаются, полагая, что логарифмический алгоритм работает быстрее, но для маленькихn
это не так.Я предполагаю, что здесь подразумевается, что если
n
ограничено, то каждая проблема - это O (1). Например, если мы сортируем целые числа, мы можем выбрать быструю сортировку.O(n*log(n))
очевидно. Но если мы решим, что не может быть больше2^64=1.8446744e+19
целых чисел, то мы знаем, чтоn*log(n)
<=1.8446744e+19*log(1.8446744e+19)
<=1.1805916e+21
. Поэтому алгоритм всегда будет занимать меньше1.1805916e+21
«единиц времени». Поскольку это постоянное время, мы можем сказать, что алгоритм всегда можно выполнить в это постоянное время ->O(1)
. (Обратите внимание, что даже если эти единицы времени являются наносекундами, это в общей сложности более 37411 лет). Но все жеO(1)
.источник
Я подозреваю, что во многих из этих ответов отсутствует фундаментальная концепция. O (1): O (n) - это не то же самое, что f (1): f (n), где f - та же самая функция, потому что O не представляет единственную функцию. Даже хороший график Шверна недействителен, потому что он имеет одинаковую ось Y для всех линий. Чтобы все использовать одну и ту же ось, линии должны были быть fn1, fn2 и fn3, где каждая из них была функцией, производительность которой можно было напрямую сравнить с другими.
Хорошо, если n = 1, они точно такие же? Нет. Функция, допускающая переменное число итераций, не имеет ничего общего с той, которая этого не делает, нотации big-O это не важно, и мы не должны.
Нотация Big-O просто предназначена для выражения того, что происходит, когда у нас есть итеративный процесс, и как производительность (время или ресурсы) будет ухудшаться по мере увеличения n.
Итак, чтобы ответить на реальный вопрос ... Я бы сказал, что те, кто делают это утверждение, не понимают нотацию Big-O должным образом, потому что это нелогичное сравнение.
Вот аналогичный вопрос: если я перебираю последовательность символов и знаю, что в общем случае мои строки будут содержать менее 10 символов, могу ли я сказать, что это эквивалент O (1), но если мои строки были длиннее, то я сказал бы, что это был O (n)?
Нет, потому что строка из 10 символов занимает в 10 раз больше строки из 1 символа, но в 100 раз меньше, чем строка из 1000 символов! Это O (n).
источник
Я считаю, что текст, который вы цитировали, довольно неточен (использование слова «лучше» обычно бессмысленно, если вы не предоставите контекст: с точки зрения времени, пространства и т. Д.) В любом случае, я считаю, что самым простым объяснением было бы:
Теперь давайте возьмем сравнительно небольшой набор из 10 элементов и несколько алгоритмов для его сортировки (просто пример). Давайте предположим, что мы сохраняем элементы в структуре, которая также предоставляет нам алгоритм, способный сортировать элементы за постоянное время. Допустим, наши алгоритмы сортировки могут иметь следующие сложности (с обозначением big-O):
Теперь давайте «раскроем» истинные сложности упомянутых выше алгоритмов сортировки (где «истина» означает не скрывать константу), представленную количеством шагов, необходимых для завершения (и предположим, что все шаги занимают одинаковое количество времени):
Если наш вход имеет размер 10, то это точное количество шагов для каждого алгоритма, упомянутого выше:
источник