Це технічно алгоритм O (1) для "Hello World"?


117

Чи було б це класифіковано як алгоритм O (1) для "Привіт, світ!" ??

public class Hello1
{
   public static void Main()
   {
      DateTime TwentyYearsLater = new DateTime(2035,01,01);
      while ( DateTime.Now < TwentyYearsLater )
      { 
          System.Console.WriteLine("It's still not time to print the hello ...");
      }
      System.Console.WriteLine("Hello, World!");
   }
}

Я думаю про використання

DateTime TwentyYearsLater = new DateTime(2035,01,01);
while ( DateTime.Now < TwentyYearsLater )
{ 
   // ... 
}

фрагмент коду як зайнятий цикл, який слід вводити в жарт, коли хтось запитує алгоритм певної складності. Це було б правильно?


15
Це O(N)складність неO(1)
Фабджан

19
@SubparWebDev Ні, ви не знаєте, скільки разів він пройде через цикл, навіть якщо ви знаєте точну різницю у часі між запуском програми та вказаною датою. Це залежить від того, наскільки швидко працює комп'ютер, що ще працює на ньому, як процесор планує завдання тощо.
Сервіс

131
@Fabjan Немає, від Nчого залежить алгоритм, тому ви не можете насправді сказати, що це алгоритм O (N).
Сервіс

29
Технічно немає вводу, тому Nце навіть не має сенсу. Але ви можете розглянути DateTime.Nowінформацію, яка робить це все ще залежним від результату. Якщо ви можете припустити реалістичне значення для DateTime.Now, тоді так, програма замикає постійну кількість разів.
ткнути

43
Постановка проблеми повинна визначати, що таке N.
Якуб Массад

Відповіді:


406

Позначення Big O в цьому контексті використовуються для опису залежності між розміром входу функції та кількістю операцій, які необхідно виконати для обчислення результату для цього вводу.

Ваша операція не має ніяких даних, до яких може бути пов'язаний вихід, тому використання нотації Big O є безглуздим. Час, який потребує операція, не залежить від входів операції (який ... немає). Так як немає ніякого зв'язку між входом і кількістю виконуваних операцій, ви не можете використовувати Big O , щоб описати , що неіснуючі відносини


6
Про що O(max(1, 2035 - yearTheProgramIsStarted))?
Бергі

19
@Bergi [Насправді ні [( stackoverflow.com/questions/34048740/… ), ви не можете просто описати кількість ітерацій циклу, виходячи з часу, коли ви виконуєте роботу. І, звичайно, ви поєднуєте це з тим, що системний годинник може будь-коли змінити користувач на будь-який час, який він хоче, і т. Д. І у вас все ще немає чітко сформованого вводу, який би міг бути точно пов’язаний із кількістю операції, необхідні для отримання результату. Хек, навіть сам вихід не є послідовним.
Сервіс

23
Можна стверджувати, що стан системи (що включає годинник) є частиною вхідних даних для програми. У цьому сенсі ви можете використовувати дату як вхідний параметр, хоч і не явний. Однак це дивно.
Коннор Кларк

9
Для того, щоб бути більш зрозумілим, "неявний" вхід - дельта між 1 січня 2035 року і сьогодні.
Коннор Кларк

6
@Hoten Але системний час не є фіксованим значенням. Ця функція не є такою самою, як просто прийняття DateTimeпочаткового часу як вхідного. Як я вже говорив раніше, системний годинник може змінюватися з часом . І знову ж таки, ви не можете безпосередньо зіставити вхід квазі, який ви описуєте, на фіксований вихід. Невідомо кількість операцій, виконаних за заданий час початку, або навіть для двох програм, які завжди отримують розумне значення DateTime.Now, тому ви не можете пов’язати ці дві як зміни часу, тому що ви навіть не можете пов'язати їх, коли час не змінюється.
Сервіс

88

Позначення Big-O означає приблизно "з урахуванням операції над кількістю роботи, N, скільки часу для обчислення, пропорційного N, займає алгоритм?". Наприклад, сортування масиву розміром N може приймати N ^ 2, Nlog (N) тощо.

Тут немає кількості вхідних даних, на які можна діяти. Так це не так O(anything).

Навіть гірше; технічно це не алгоритм. Алгоритм - це метод обчислення значення математичної функції - математичні функції - це відображення від одного входу до виходу. Оскільки це не бере ніяких даних і нічого не повертає, це не є функцією в математичному сенсі. З Вікіпедії:

Алгоритм - це ефективний метод, який може бути виражений у межах обмеженого простору та часу та чітко визначеною формальною мовою для обчислення функції. Починаючи з початкового стану та початкового вводу (можливо, порожнього), інструкції описують обчислення, яке, виконуючись, проходить через обмежене число чітко визначених послідовних станів, врешті-решт, виробляючи "вихід" і закінчуючи у кінцевому кінцевому стані.

Технічно це система управління. З вікіпедії;

Система управління - це пристрій або набір пристроїв, який управляє, командує, спрямовує або регулює поведінку інших пристроїв або систем.

Люди, які хочуть отримати більш глибоку відповідь про різницю між математичними функціями та алгоритмами та більш потужними здібностями комп'ютерів робити такі побічні речі, як консольний вихід, показ графіки чи керування роботами, ознайомтеся з цим документом на Сильна гіпотеза Церкви-Тьюрінга

Анотація

Класичний вигляд обчислення позицій обчислень як перетворення закритих коробок входів (раціональних чисел або кінцевих рядків) у виходи. Згідно з інтерактивним поглядом на обчислення, обчислення - це триваючий інтерактивний процес, а не функціональне перетворення вводу на вихід. Зокрема, спілкування із зовнішнім світом відбувається під час обчислення, а не перед ним чи після нього. Цей підхід докорінно змінює наше розуміння того, що таке обчислення та як його моделюють.

Прийняттю взаємодії як нової парадигми заважає сильна церковна теза Тюрінга (SCT), поширена думка, що машини Тьюрінга (ТМ) охоплюють усі обчислення, тому моделі обчислень більш виразні, ніж ТМ, неможливі. У цій роботі ми показуємо, що SCT переосмислює оригінальну тезу Церкви-Тьюрінга (CTT) таким чином, який ніколи не передбачав Тьюрінг; її загальноприйнята еквівалентність оригіналу є міфом. Ми визначаємо та аналізуємо історичні причини поширеної віри в SCT. Тільки приймаючи, що це помилково, ми можемо почати сприймати взаємодію як альтернативну парадигму обчислення


Це не повинно бути послідовністю. Це лише деяке введення даних, і позначення landau описує час роботи стосовно певних показників цих даних - як правило, щось пов'язане з розміром.
Бергі

@Bergi - так, дивіться на ваш погляд! Насправді, я просто зробив наближення, але так - якщо ви можете виміряти кількість роботи, яку потрібно виконати, і кількість кроків, необхідних для того, щоб потрапити туди, великий -о відображає співвідношення цих двох заходів. Ближче?
Стів Купер

@kapep - це не чиста функція, оскільки це недійсний метод, але якщо порахувати вихід консолі, він все одно випадковий; це може вивести будь-яку з {"Привіт, світ!", "Ще не час надрукувати привіт ... \ n Привіт, світ!", "Ще не час надрукувати привіт ... Ще не час друкувати привіт ... \ nЗдравствуйте, світ! ", ...}
Стів Купер

1
Друк для stdout не є результатом?
rpax

4
@rpax Не математично, ні. Функція - це незмінний переклад з входів на вихід; наприклад, «квадрат» - це функція, яка завжди повертає 9, якщо ви вводите 3. Метод c # - це лише математична функція, якщо виклик з тими ж параметрами завжди дає одне і те ж повернене значення. В іншому випадку - якщо у нього є такі побічні ефекти, як запис на консоль, показ графіки, виділення пам'яті - це не математичні функції. (Додаю посилання на мою відповідь, яка вказує на неї з більшими подробицями :))
Стів Купер

41

Ні, ваш код має складність у часі O(2^|<DeltaTime>|),

Для правильного кодування поточного часу.
Будь ласка, дозвольте мені спочатку вибачитися за свою англійську.

Що таке і як працює Big O в CS

Позначення Big O не використовуються для прив'язки введення програми до часу її роботи .
Нотація великого O - це, залишаючи строгість позаду, спосіб виразити асимптотичне співвідношення двох величин .

У випадку аналізу алгоритму ці дві величини - це не вхід (для якого спочатку потрібно функціонувати "міряти"), а час роботи.
Вони - це довжина кодування екземпляра задачі 1 та метрика, що цікавить.

Поширені показники є

  1. Кількість етапів, необхідних для виконання алгоритму в заданій моделі обчислення.
  2. Простір, необхідний, якщо така концепція існує, для моделі обчислення.

Побічно передбачаються ТМ в якості моделі , так що перша точка переводить до числа застосувань переходу 2 функції , тобто «кроки», а другий переводить число різних стрічкових клітин , написаних щонайменше , один раз .

Чи часто також неявно передбачається, що ми можемо використовувати поліноміально пов'язане кодування замість оригінального, наприклад, функція, яка шукає масив від початку до кінця, має O(n)складність, незважаючи на те, що кодування екземпляра такого масиву повинно мати довжину n*b+(n-1)де b(постійне) число символів кожного елемента. Це тому b, що вважається константою обчислювальної моделі, тому вираз вище і nє асимптотично однаковим.

Це також пояснює, чому такий алгоритм, як пробний відділ, є експоненціальним алгоритмом, незважаючи на те, що він є for(i=2; i<=sqr(N); i++)подібним алгоритмом 3 .

Дивіться це .

Це також означає, що велика нотація O може використовувати стільки параметрів, які можуть знадобитися для опису проблеми, чи не незвично мати параметр k для деяких алгоритмів.

Тож мова не йде про "вхід" або про те, що "немає вводу".

Вивчіть справу зараз

Нотація великого O не ставить під сумнів ваш алгоритм, він просто передбачає, що ви знаєте, що робите. Це по суті інструмент, застосовний скрізь, навіть до алгоритму, який може бути навмисно хитрим (як і ваш).

Для вирішення вашої проблеми ви використовували поточну дату та майбутню дату, тому вони повинні якось бути частиною проблеми; просто кажучи: вони є частиною екземпляра проблеми.

Зокрема, це:

<DeltaTime>

Де <>означає будь-яке, непатологічне, кодування вибору.

Дивіться нижче для дуже важливих роз'яснень.

Отже, ваш великий час складності O справедливий O(2^|<DeltaTime>|), тому що ви робите ряд ітерацій, які залежать від значення поточного часу. Немає сенсу ставити інші числові константи, оскільки асимптотичні позначення корисні, оскільки вони виключають константи (так, наприклад, використання O(10^|<DeltaTime>|*any_time_unit)безглуздо).

Де хитра частина

Вище ми зробили одне важливе припущення: що модель обчислення повторно підтверджує 5 разів, а часом я маю на увазі (реальний?) Фізичний час. У стандартній обчислювальній моделі такої концепції немає, ТМ не знає часу, ми пов'язуємо час з кількістю кроків, тому що так працює наша реальність 4 .

У вашій моделі, однак час є частиною обчислень, ви можете використовувати термінологію функціональних людей, кажучи, що Main не є чистим, але концепція однаковою.

Щоб зрозуміти це, слід зазначити, що ніщо не заважає Рамкові використовувати підроблений час, який працює вдвічі, п’ять, десять разів швидше, ніж фізичний час. Таким чином ваш код буде працювати в "половині", "п'ятій п'ятірці", "одній десятій частині" часу ".

Це відображення важливе для вибору кодування <DeltaTime>, це, по суті, стислий спосіб написання <(CurrentTime, TimeInFuture)>. Оскільки часу не існує пріорі, кодування CurrentTime цілком може бути словом Now (або будь-яким іншим вибором) напередодні можна було кодувати як Вчора , там, порушивши припущення, що тривалість кодування збільшується як фізичний час йде вперед (а цей у DeltaTime зменшується)

Ми повинні правильно моделювати час у нашій обчислювальній моделі, щоб зробити щось корисне.

Єдиний безпечний вибір, який ми можемо зробити, - це кодувати часові позначки із збільшенням довжини (але все ще не використовуючи одинарних) як фізичний час вперед. Це єдине справжнє властивість часу, яке нам потрібно, і те, яке потрібно кодувати. Чи тільки при такому типі кодування ваш алгоритм, можливо, має складність у часі.

Ваша плутанина, якщо така є, випливає з того, що слово час у фразах "Яка її часова складність?" і "Скільки часу це займе?" означає дуже різні речі

На жаль, термінологія використовує одні і ті ж слова, але ви можете спробувати використати "складність кроків" в голові і перепросити собі своє питання, сподіваюся, що допоможе зрозуміти відповідь насправді ^ _ ^


1 Це також пояснює необхідність асимптотичного підходу, оскільки кожен екземпляр має різну, але не довільну довжину.
2 Я сподіваюся, що тут я вживаю правильний англійський термін.
3 І саме тому ми часто знаходимо log(log(n))в математиці терміни.
4 Точно крок повинен займати деякий кінцевий, але не нульовий і не пов'язаний інтервал часу.
5 Це означає, що обчислювальний режим як знання фізичного часу в ньому, тобто може виражати його своїми умовами. Аналогія - як дженерики працюють у рамках .NET.


3
"Отже, ваш великий час роботи O просто". Я впевнений, що ви мали на увазі "велику складність". Крім того, ми все ще можемо просто називати "deltaTime" нашим "n" правом. Тож ваше висловлювання O (2 ^ N) щось подібне до складності алгоритму Фібоначчі. Як ти прийшов до "2 ^"?
Росс

@Ross, дякую за точку. Я прийшов із 2-х звичок працювати з двійковими числами. Справа в тому, що кроки лінійні з довжиною подання числа. Фактична база насправді не важлива і змінюється залежно від конкретного кодування. Він псевдолінійний .
Yuni Mj

Вибачте, але ви можете, будь ласка, детальніше розкрити у своїй відповіді, як ви зробили висновок про складність O(2^n)? Початківцям незрозуміло.
Артуро Торрес Санчес

2
@YuniMj Хоча ваші міркування технічно не так, я думаю , що, наполягаючи на тому , щоб виміряти розмір від DeltaTimeзамість його вартості , ви просто додати додаткову плутанину. Наприклад, але це міркування, що немає алгоритму оптимального сортування, має складність у часі $ O (n \ cdot log n) $. Чому? Тому що ви або лише безмежно багато відмінних об'єктів для сортування, і в цьому випадку ви завжди можете використовувати сортування відра для сортування в $ O (n) $. Або розмір вашого об'єкта не обмежений, і в цьому випадку $ O (n \ cdot log n) $ не витримає, оскільки жодне порівняння більше не матиме постійного часу ...
fgp


29

Хоча тут є маса чудових відповідей, дозвольте трохи перефразувати їх.

Існує нотація Big-O для опису функцій . Що стосується аналізу алгоритмів, це вимагає, щоб ми спочатку визначили деяку характеристику цього алгоритму з точки зору функції . Загальним вибором є розгляд кількості кроків як функції вхідного розміру . Як зазначається в інших відповідях, придумати таку функцію у вашому випадку здається дивним, оскільки немає чітко визначеного "введення". Ми все ще можемо спробувати це зробити, хоча:

  • Ми можемо розглядати ваш алгоритм як постійну функцію, яка приймає будь-який ввід будь-якого розміру, ігнорує його, чекає фіксованого часу та закінчує. У цьому випадку час його виконання є f (n) = const , і це алгоритм O (1) -time. Це те, що ви очікували почути, правда? Так, це технічно є алгоритмом O (1) .
  • Ми можемо розцінювати TwentyYearsLaterяк цікавий параметр "вхідного розміру". У цьому випадку час виконання - f (n) = (nx), де x - "час тепер" у момент виклику. Якщо це бачити таким чином, це алгоритм O (n) -time. Очікуйте цього контр-аргументу щоразу, коли ви переходите демонструвати свій технічний O (1) -алгоритм іншим людям.
  • О, але зачекайте, якщо k =TwentyYearsLater вхід, то його розмір n - це фактично кількість бітів, необхідних для його представлення, тобто n = log (k) . Отже, залежність між величиною вхідного n та тривалістю виконання є f (n) = 2 ^ n - x . Схоже, ваш алгоритм просто став експоненціально повільним! Тьфу.
  • Іншим входом до програми є насправді потік відповідей, що даються ОС на послідовність DateTime.Nowвикликів у циклі. Ми можемо реально уявити, що вся ця послідовність надається як вхідний момент у момент запуску програми. Потім можна вважати, що час виконання залежить від властивості цієї послідовності, а саме від її довжини до першого TwentyYearsLaterелемента. У цьому випадку час виконання знову f (n) = n, а алгоритм - O (n) .

Але знову ж таки, у своєму запитанні ви навіть не сказали, що вас цікавить час виконання. Що робити, якщо ви мали на увазі використання пам'яті? Залежно від того, як ви моделюєте ситуацію, ви можете сказати, що алгоритмом є O (1) -пам'ять або, можливо, O (n) -пам'ять (якщо реалізація DateTime.Nowвимагає відстежувати всю послідовність викликів, чомусь).

І якщо ваша мета полягала в тому, щоб придумати щось абсурдне, чому б вам не зайти все і сказати, що вас цікавить, як розмір коду алгоритму в пікселях на екрані залежить від обраного масштабу. Це може бути щось на зразок f (zoom) = 1 / zoom, і ви можете з гордістю оголосити свій алгоритм розміром O (1 / n) -пікселя!


+1. Я вважаю, що "потік відповідей, що дається ОС на послідовність DateTime.Nowвикликів", є реальним вкладом тут. Але я думаю, висновок не повинен бути таким, що це O (n), але це O (k), де k - довжина до першого TwentyYearsLaterелемента
якразполовина

7
Це найкраща відповідь на даний момент - для того, щоб Big O мав значення, ви повинні застосувати математичну семантику / припущення до фізичної реалізації (по суті визначення математичної моделі для програми зі змістовим визначенням "введення"). У цьому сенсі складність "програми" залежить від застосовуваної семантики - якщо припустити, що N - різниця у часі, яка лінійно масштабується з кількістю операцій, це O (n). Якщо припустити фіксовану кількість операцій в результаті фіксованого періоду часу, це O (1).
Мураха P

21

Я злегка не погоджуюся з Серві. Є вхід до цієї програми, навіть якщо це не очевидно, і це час системи. Це може бути техніка, яку ви не планували, але вашаTwentyYearsFromNow змінна не за двадцять років з часу системи , вона статично призначається 1 січня 2035 року.

Отже, якщо ви берете цей код і виконайте його на машині, яка має системний час 1 січня 1970 року, на завершення знадобиться 65 років, незалежно від того, наскільки швидко працює комп'ютер (може бути певна різниця, якщо його годинник несправний ). Якщо взяти цей код і виконати його на машині, що має системний час 2 січня 2035 року, він завершиться майже миттєво.

Я б сказав ваш внесок, n є January 1st, 2035 - DateTime.Now, є , і це O (n).

Тоді ще й питання про кількість операцій. Деякі люди зазначили, що швидші комп’ютери швидше потраплять у цикл, викликаючи більше операцій, але це не має значення. Працюючи з нотацією big-O, ми не враховуємо швидкість процесора або точну кількість операцій. Якщо ви взяли цей алгоритм і запустили його на комп’ютері, а потім запустили його ще раз, але на 10 разів довше на тому ж комп’ютері, ви б очікували, що кількість операцій зросте на той же коефіцієнт у 10 разів.

Щодо цього:

Я думаю про використання фрагмента коду [відредагованого коду] як циклу зайнятості, щоб вносити його як жарт, коли хтось запитує алгоритм певної складності. Це було б правильно?

Ні, не дуже. Інші відповіді висвітлювали це, тому я просто хотів це згадати. Зазвичай ви не можете співвідносити роки виконання з будь-якою великою нотацією O. Напр. З цього приводу не можна сказати 20 років страти = O (n ^ 87) чи що-небудь інше. Навіть в алгоритмі, який ви подали, я міг змінити TwentyYearsFromNowрік на 20110, 75699436 або 123456789, і велике-O все одно O (n).


7
Час не є входом до функції, це постійно змінюється стан, який спостерігається під час виконання методу. Системний годинник можна навіть змінити під час роботи функції . Щоб Big O був значимим, вам також потрібно, щоб кожен вхід відповідав 1-1 з вихідним значенням, а також ряд операцій, необхідних для його обчислення. Для цієї операції вихідний сигнал навіть не відповідає одному і тому ж входу (насправді він різко змінюється ), на додаток до кількості виконуваних операцій також різко змінюється.
Сервіс

When working with big-O notation, we don't consider the speed of the processor or the exact number of operations.Це хибне твердження. Насправді, будь-яка розумна операція, яку ви намагаєтеся обчислити величиною Big O, не збирається змінювати кількість операцій, що виконуються на основі апаратних засобів, але це робить . Big O - це лише спосіб співвідношення кількості операцій з розміром вхідного сигналу. Для більшості операцій, які не залежать від системного обладнання. У цьому випадку це не так .
Сервіс

If you took this algorithm and ran it on a computer, and then ran it again but for 10x longer on the same computer, you would expect the number of operations to grow by the same factor of 10x.Це теж хибне твердження. Навколишнє середовище не обов'язково змінюватиме кількість операцій у циклі лінійно. Наприклад, на комп’ютері можуть бути інші програми, які використовують більше або менше часу процесора в різні моменти часу, постійно змінюючи час, присвячений цій програмі.
Сервіс

Я з @Servy на цьому, але з дещо іншої причини. Основна функція не приймає жодних параметрів і не повертає ніяких даних. Це функція nil => nil, якщо вам подобається. Не має значення, який час, він все одно нічого не повертає.
Стів Купер

1
Якщо ми використовуємо це визначення - "В математиці функція - це відношення між набором входів і набором допустимих виходів з властивістю, що кожен вхід пов'язаний з точно одним виходом". (wikipedia) - і ми зараховуємо вихід консолі як "вихід функції", це змінюється, стаючи довше на більш швидкому комп'ютері, оскільки він напише "" Ще не час друкувати привіт ... "" частіше.
Стів Купер

13

Аналіз Big-O стосується обсягу обробки, що займається, оскільки кількість оброблюваних даних без обмежень збільшується.

Тут ви справді маєте справу лише з одним об'єктом фіксованого розміру. Застосування аналізу big-O значною мірою залежить (перш за все?) Від того, як ви визначаєте свої умови.

Наприклад, ви можете мати на увазі вихід друку в цілому і накладення очікування настільки тривалий час, що будь-яка розумна кількість даних буде / буде надрукована точно за той самий проміжок часу. Ви також повинні додати трохи більше, як дещо незвичні (якщо не відверто неправильні) визначення, щоб отримати дуже далеко, зокрема, аналіз big-O зазвичай визначається з точки зору кількості основних операцій, необхідних для проведення певне завдання (але зауважте, що складність може розглядатися і в таких речах, як використання пам'яті, а не лише використання процесора / операцій, що виконуються).

Кількість фундаментальних операцій, як правило, досить чітко відповідає часу, який займає час, тому це не є великим розтягненням, яке стосується обох як синонімів. На жаль, ми все ще дотримуємося іншої частини: кількість оброблюваних даних збільшується без обмежень. У цьому випадку жодна фіксована затримка, яку ви можете накласти, справді не спрацює. Щоб прирівняти O (1) до O (N), вам доведеться накласти нескінченну затримку, щоб будь-який фіксований обсяг даних вічно друкувався так само, як і нескінченний обсяг даних.


10

big-O щодо чого?

Ви, здається, інтуїтивно зрозуміли, що twentyYearsLaterце "вхід". Якщо ви справді ви написали свою функцію як

void helloWorld(int years) {
   // ...
}

Це було б O (N), де N = роки (або просто сказати O(years)).

Я б сказав, що ваш алгоритм є O (N) щодо того, яке число ви запишете в рядку коду, починаючи з twentyYearsLater =. Але люди зазвичай не вважають числа в фактичному вихідному коді вхідним. Вони можуть розглядати вхід командного рядка як вхід, або вхід підпису функції як вхід, але, швидше за все, не сам вихідний код. Це те, що ви спірите зі своїм другом - це «вхід»? Ви встановлюєте свій код таким чином, щоб він інтуїтивно здавався вхідним, і ви, безумовно, можете запитати його великий час роботи O щодо числа N у рядку 6 вашої програми, але якщо ви використовуєте такий вибір, який не використовується за замовчуванням як вхідні дані вам дійсно повинні бути чіткими.

Але якщо ви вважаєте, що вхід є чимось звичнішим, наприклад командним рядком або входом у функцію, то виводу взагалі немає, а функція - O (1). Це займає двадцять років, але оскільки велика-O не змінюється до постійної кратної, O (1) = O (двадцять років).

Подібне запитання - який час виконання:

void sortArrayOfSizeTenMillion(int[] array)

Якщо припустити, що він робить те, що говорить, і введення є дійсним, і алгоритм використовує сортування швидкості або міхура або щось розумне, це O (1).


Жорстке кодування вводу не означає, що вхід зникає. Ні в якому разі не є швидкості і швидкості пухирців O (1). bigocheatsheet.com
Тео Брінкман

@TheoBrinkman Якщо ви хочете бути технічними, то в моделі машини Тьюрінга кодування того, що ви думаєте про вхід, в саму машину Тьюрінга робить це, за визначенням, не входом. Тоді машина Тьюрінга буде працювати в постійний час незалежно від того, який фактичний вхід у нього є. У певному сенсі це не запуск "сортування бульбашок", оскільки це не сортування нічого, а оперування власним представленням, однак у нетехнічному плані, звичайно, можна було б описати алгоритм як сортування бульбашок.
djechlin

В рівній мірі "нетехнічні терміни", ви можете описати розглянутий алгоритм як підвісний міст.
Тео Брінкман

@TheoBrinkman ні, ти не міг. Це нікому не мало б сенсу.
djechlin

Кожен біт має стільки ж сенсу, як описувати його як сортування міхурів O (1).
Тео Брінкман

8

Цей "алгоритм" правильно описано як O (1) або постійний час. Стверджувалося, що в цю програму немає ніякого вкладу, отже, немає Н для аналізу в термінах Big Oh. Я не погоджуюся з тим, що введення немає. Коли це компілюється у виконуваний файл і викликається, користувач може вказати будь-який вхід довільної довжини. Ця вхідна довжина - N.

Програма просто ігнорує вхід (будь-якої довжини), тому витрачений час (або кількість виконаних машинних інструкцій) є однаковим, незалежно від довжини введення (задана фіксована обстановка = час початку + обладнання), отже O (1 ).


Але кількість операцій не обов'язково узгоджується, навіть із однаковим часом запуску та обладнанням. Крім цього, для створення алгоритму O (1) вихід повинен завжди бути постійним, і це не так, воно буде дивовижно змінюватися залежно від часу запуску та обладнання. Це також може бути дуже нескінченним, що, безумовно, не є постійним. Немає зв'язку між визначеними вами входами та кількістю виконаних операцій. Це не постійно, це просто невизначено. Ви не можете назвати кінцеве число і знаєте, що операцій завжди буде менше, ніж це.
Сервіс

Максимальний реальний час, який знадобиться, - 20 років. Якщо ми розпочнемо це в майбутньому, так, це займе більше часу. Припустимо, що існує обмежена нижня межа часу, який триває цикл ітерації, і що ми працюємо на серійному обладнання. Тоді я можу зв'язати кількість разів, коли цикл запуститься, що означає, що все обчислення може бути обмежене постійною функцією, незалежно від розміру ігнорованого вводу.
waldol1

Let's suppose that there is a finite lower bound on the amount of time a loop iteration takesЦе помилкове припущення. Програма може працювати вічно. Все, що мені потрібно зробити, це встановити свій системний годинник на 50 років з цього часу, запустити його, і він ніколи не закінчиться. Або я міг би рухати годинник назад швидше, ніж він рухається вперед, або запускати його у невизначений момент у минулому . Ви просто не можете припустити, що існує нижня межа того, як триває програма; він може працювати вічно. Але, навіть якщо ми вважаємо ваше (помилкове) припущення як істинне, ви все одно не можете пов’язати кількість операцій, що виконуються, на вхід.
Сервіс

Повторна ітерація циклу займає обмежений час. Це може бути виконано нескінченну кількість разів, але кожен повинен бути приблизно постійним. Я не бачу проблем з цим припущенням.
waldol1

За цією [цілком неправильною] логікою кожен алгоритм кожен завжди є O (1), тому що кожна окрема операція завжди є постійною. Ви просто демонструєте, що не знаєте, що таке Big O навіть. Це інструмент для (в контексті) опису співвідношення між розміром вхідного сигналу та кількістю відповідних виконаних операцій. O (1) означає, що існує постійна кількість операцій, що виконуються незалежно від введення. Тут НЕ постійне число операцій , що виконується незалежно від входу, є потенційно нескінченні операції виконуються, нескінченні! = Константа.
Сервіс

6

Я здивований, ще не було згадано: позначення big-O - це верхня межа!

Усі, хто помітив, полягають у тому, що немає N, що описує входи в алгоритм, тому немає з чим робити великий аналіз O. Однак це легко пом'якшити за допомогою деяких основних хитрощів, таких як прийняття int nта друк "Hello World" nчасів. Це дозволить обійти цю скаргу і повернутися до реального питання про те, як DateTimeпрацює ця чудовисько.

Немає фактичної гарантії того, що цикл while будь-коли припиниться. Нам подобається думати, що це має бути на певний час, але вважаємо, що це DateTime.nowповертає дату та час системи . Фактично немає гарантії, що це монотонно зростає. Цілком можливо, що є якась патологічно навчена мавпа, яка постійно змінює дату та час роботи системи до 21 жовтня 2015 р. 12:00:00 UTC, поки хтось не подарує мавпі якесь взуття для автоматичного розміщення та ховерборд. Цей цикл насправді може працювати протягом нескінченної кількості часу!

Коли ви фактично заглиблюєтесь у математичне визначення нотацій з великим O, вони є верхніми межами. Вони демонструють найгірший випадок, яким би малоймовірно. Найгірший сценарій * тут - нескінченна тривалість виконання, тому ми змушені заявити, що немає великої нотації O, яка б описувала складність виконання цього алгоритму. Він не існує, так само як 1/0 не існує.

* Редагувати: з мого обговорення з KT не завжди справедливо припускати сценарій, який ми моделюємо з позначенням big-O - це найгірший випадок. У більшості випадків, якщо особа не вказує, який випадок ми використовуємо, він мав намір вивчити найгірший випадок. Однак ви можете зробити великий складний аналіз складності в кращому випадку виконання.


2
О, в певному сенсі є "верхньою межею", але це не означає, що ви можете говорити лише про "найгіршу складність", використовуючи O-позначення. Очікувана складність, найкраща складність, будь-яка інша функціональна властивість - усі вони можуть бути обговорені з точки зору їх O-меж.
КТ.

@KY кращий складний випадок називається мало-о, а очікувана складність - великим-тетою. big-o - це найгірший складний випадок, за його математичним визначенням.
Корт Аммон

Ні, ви тут помиляєтесь. Перевірте визначення.
КТ.

@KT Гаразд, я повторно перевіряю їх. Ви також повторно перевірите їх. en.wikipedia.org/wiki/Big_O_notation Її під нотаціями сімейства Бахмана – Ландау
Cort Ammon

Я думаю, ви могли б зробити щось божевільне, як взяти функцію fі оголосити функцію gтакою самою, як f, але з обмеженим доменом, щоб включити лише fкращий випадок, а потім зробити великий-о g, але це починає звучати вироджено, коли ви що.
Cort Ammon

5

Складність використовується для вимірювання обчислювальних "кінських сил" за часом / простором. Позначення Big O використовується для порівняння, які проблеми "обчислюються" чи "не обчислюються", а також для порівняння, які рішення - алгоритми - кращі за інші. Таким чином, ви можете розділити будь-який алгоритм на дві категорії: ті, які можна вирішити за багаточлен, і ті, які не можуть.

Такі проблеми, як сито Ератостена, є O (n ^ exp) і тому вирішуються для малих значень n. Вони піддаються обчислюванню, тільки не в поліноміальний час (NP), і тому, коли їх запитують, чи задане число є простим чи ні, відповідь залежить від величини такої кількості. Більше того, складність не залежить від апаратного забезпечення, тому наявність швидших комп'ютерів нічого не змінює ...

Hello World - це не алгоритм, і тому безглуздо намагатися визначити його складність - що таке ніхто. Простий алгоритм може бути чимось на зразок: задавши випадкове число, визначте, парне чи непарне. Тепер, чи має значення те, що вказане число має 500 цифр? Ні, тому що ви просто повинні перевірити, чи остання цифра є парною чи непарною. Більш складним алгоритмом було б визначити, чи дане число ділиться рівномірно на 3. Хоча деякі числа «легко» обчислити, інші - «важко», і це пов’язано з його величиною: порівняйте час, необхідний для визначення реманера між число з однією цифрою, а інше - з 500 цифр.

Складнішим випадком буде розшифровка тексту. У вас є очевидний випадковий масив символів, який ви також знаєте, що передають повідомлення для тих, хто має ключ розшифровки. Скажімо, відправник використав ключ зліва і ваш Hello World прочитав би: Gwkki Qieks. Рішення "з великим ударом, без мозку" створило б усі комбінації для цих букв: від Аааа до Zzzz, а потім здійснити пошук у словнику слів, щоб визначити, які слова є дійсними, і поділити дві загальні літери в цифрі (i, k) у та ж позиція. Ця функція перетворення - це те, що вимірює Big O!


4

У більшості людей, здається, не вистачає двох дуже важливих речей.

  1. Програма робить біля входу. Це жорстко кодована дата / час, з якою порівнюється системний час. Входи знаходяться під контролем людини, що працює за алгоритмом, а системний час - ні. Єдине, що людина, яка запускає цю програму, може контролювати - це дата / час, коли вони важко закодовані для порівняння.

  2. Програма змінюється залежно від вхідного значення , але не розміру вхідного набору , що стосується нотації big-O.

Отже, вона невизначена, і найкращою позначкою 'big-O' для цієї програми, ймовірно, буде O (null) або, можливо, O (NaN).


1
(2) є неправильним. Зазвичай вважається "довжина введення". Для списку або масиву об'єктів фіксованого розміру (наприклад, цілих чисел) це дійсно буде розмір набору. Для множення числа, наприклад 1395195191600333, це буде довжина його двійкового (або десяткового тощо) відображення, тобто кількість цифр. Як зазначено у вашому визначенні в (2), забороняється використовувати big-O для обговорення складності "findPrimeFactors (int num)", проти якої більшість криптографів заперечує.
djechlin

4

Всі правильно вказали, що ви не визначаєте N , але відповідь "не" під найдоцільнішою інтерпретацією. Якщо N - довжина струни, яку ми друкуємо, і "привіт, світ!" це лише приклад, як ми можемо зробити висновок з опису цього як алгоритму "для hello, world!", тоді алгоритм є O ( N ), тому що у вас може бути вихідний рядок, який потребує друку тридцяти, сорока або п'ятдесяти років, і ви додаємо до цього лише постійний час. O ( kN + c ) ∈ O ( N ).

Додаток:

На мій подив, хтось заперечує це. Пригадайте визначення великого O та великого Θ. Припустимо, у нас є алгоритм, який чекає постійну кількість часу dN + c років. Всякий раз, коли N > k , dN = c / k N > c . Тому dN < dN + c = f ( N ) <2 dN для всіх N c, а потім виводить повідомлення довжиною N у лінійному часі. (Це узагальнення оригінального зразка коду.) Скажімо довільно, що ми чекаємо двадцяти років, щоб почати друкувати, а на друк трильйона символів потрібно ще двадцять років. Нехай, наприклад, c = 20 і k = 10¹², але будь-які додатні дійсні числа будуть робити. Це швидкість d = c / k (в даному випадку 2 × 10⁻¹¹) років на персонаж, тому наш час виконання f ( N ) асимптотично > k , а f ( N ) ∈ Θ ( N ). QED


Де у нас N = 13.
djechlin

Але він не просто друкує "Привіт світ", він друкує невідому кількість рядків "Ще не час". Крім того, Big O насправді не використовується для порівняння розміру входу з розміром виводу, він, як правило, використовується для порівняння розміру вводу з кількістю операцій або обсягом використовуваної пам'яті.
Сервіс

@Servy Це постійна пам'ять, але я неявно обмежував час виконання. Розмір виводу також є O ( N ) для довільної рядки: рядок, який ми друкуємо, коли настає час, може бути довільно великим, навіть порівняно з повідомленнями, які варто чекати двадцяти років.
Девіслор

@ Сервіс Я відредагував, щоб уточнити, що ні, тут Н не розмір виводу. Я не впевнений, як справляв таке враження, але усуну будь-яку неясність.
Девіслор

1
Отже, якщо ви припускаєте, що програма бере вхід, коли він не робить, що вихід може бути довільно великим, коли він не може, що цикл нічого не робить, коли він робить, і що результат пов'язаний з вхід, коли його немає, тоді так, програма лінійна. Звичайно, кожне з цих припущень є абсолютно помилковим, тому висновок, який ви зробили з них, не має права. Якщо ви зможете продемонструвати свою думку, не роблячи помилкових припущень, то це щось би означало.
Сервіс

4

Я думаю , що люди стають все скидаються , тому що код не виглядати як традиційний алгоритм. Ось переклад коду, який є більш сформованим, але залишається вірним духу питання ОП.

void TrolloWorld(long currentUnixTime, long loopsPerMs){
    long laterUnixTime = 2051222400000;  //unix time of 01/01/2035, 00:00:00
    long numLoops = (laterUnixTime-currentUnixTime)*loopsPerMs;

    for (long i=0; i<numLoops; i++){
        print ("It's still not time to print the hello …");
    }
    print("Hello, World!");
}

Вхідні дані явні, тоді як раніше вони неявно задавалися часом запуску коду та швидкістю апаратного забезпечення коду. Код детермінований і має чітко визначений вихід для заданих входів.

Через обмеження, накладені на входи, які ми можемо надати, існує верхня межа кількості операцій, які будуть виконані, тому цей алгоритм насправді є O (1).


2

На даний момент часу, так

Цей алгоритм має неявний вхід, а саме час запуску програми. Час виконання буде змінюватися лінійно 1 залежно від того, коли воно розпочато. Протягом 2035 року і після цього цикл негайно вимикається, і програма припиняється після постійних операцій 2 . Тож можна сказати, що тривалість виконання - O(max(2035 - start year, 1))3 . Але оскільки наш стартовий рік має мінімальне значення, алгоритм ніколи не займе більше 20 років для виконання (тобто постійне значення).

Ви можете зробити свій алгоритм більш відповідним вашим намірам, визначивши DateTime TwentyYearsLater = DateTime.Now + new TimeSpan(365*20,0,0,0);4

1 Це стосується більш технічного сенсу часу виконання, виміряного як кількість операцій, оскільки існує максимальна кількість операцій за одиницю часу.
2 Припускаючи отримання DateTime.Now- це постійна операція, що є розумним.
3 Я дещо зловживаю великими позначеннями O, оскільки це погіршує функцію щодо start year, але ми могли б легко виправити це, висловивши це в термінах years prior to 2035.
4 Тоді алгоритм більше не залежить від неявного введення часу початку, але це не має жодного наслідку.


1

Я б стверджував, що це O (n). використовуючи http://www.cforcoding.com/2009/07/plain-english-explanation-of-big-o.html в якості посилання.

Що таке Big O?

Позначення Big O прагне описати відносну складність алгоритму шляхом зменшення швидкості росту до ключових факторів, коли ключовий фактор має тенденцію до нескінченності.

і

Найкращий приклад Big-O, який я можу придумати, - це робити арифметику. Основними арифметичними операціями, які ми вивчили в школі, були:

додавання; віднімання; множення; і поділ. Кожне з них - це операція чи проблема. Метод їх вирішення називається алгоритмом.

Для вашого прикладу,

заданий вхід n = 20 (з одиницями років).

алгоритм - математична функція f (). де f () трапляється чекати протягом n років, з рядками 'debug' між ними. Коефіцієнт масштабу - 1. f () можна зменшити / або збільшити, змінивши цей коефіцієнт масштабу.

для цього випадку вихід також дорівнює 20 (зміна входу змінює вихідний лінійно).

по суті функція є

f(n) = n*1 = n
    if  n = 20, then 
f(20) = 20 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.