O (N log N) Складність - схожа на лінійну?


78

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

Я застосував швидке сортування на Java та C, і я робив деякі базові порівняння. Графік вийшов у вигляді двох прямих ліній, причому C був на 4 мс швидшим, ніж аналог Java, понад 100 000 випадкових цілих чисел.

Результати

Код моїх тестів можна знайти тут;

Android-тести

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

Я встромив формулу в Excel і для бази 10, здається, це пряма лінія з перегином на початку. Це тому, що різниця між log (n) та log (n + 1) збільшується лінійно?

Дякую,

Гав


1
Пошук зображень Google здається напрочуд хорошим для таких пошуків, як "n log n".
Том Хоутін - таклін

1
Рядок Java зверху мені не виглядає прямо.
Щеня

Подібне, справді, саме тому його називають "
лінійним

Відповіді:


81

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

Наприклад (база 10):

log(1000000) = 6
log(1000000000) = 9
…

Отже, для сортування 1 000 000 чисел сортування O (n logn) додає мізерний коефіцієнт 6 (або лише трохи більше, оскільки більшість алгоритмів сортування залежать від логарифмів основи 2). Не дуже багато.

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

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


1
Хороші сорти, як правило, вибирають лінійний алгоритм, як тільки вони поділяються і завойовуються на досить маленькі шматочки. Наскільки саме малим є питання бенчмаркінгу (реальні дані).
Том Хоутін - таклін

2
Том: Я не впевнений, що саме ви маєте на увазі під лінійним. Часто алгоритми сортування роблять навпаки, використовуючи сортування O (n ^ 2), такі як сортування на вставці, на невеликі порції, оскільки їх постійний коефіцієнт настільки малий, що навіть квадратичний час виконання перевершує сортування logn. З іншого боку, introsort використовує стратегію для виходу з занадто глибоких рекурсій - але знову ж таки, це не десь лінійно, а просто обмінює квадрадичний найгірший випадок поведінки O (n logn).
Конрад Рудольф

11

FYI, швидкий сорт насправді O (n ^ 2), але із середнім випадком O (nlogn)

FYI, існує досить велика різниця між O (n) та O (nlogn). Ось чому він не обмежений O (n) для будь-якої константи.

Для графічної демонстрації див .:

O (n) проти O (nlogn)


2
а) Без зазначення, O () зазвичай використовується для позначення очікуваної (середньої) складності. б) Позначення O () не включає постійні фактори, тому O (n) і O (2n) однакові. Оскільки log (n) є майже постійним (для великих чисел, порівняно з n), можна сказати, що O (n) та O (n log (n)) майже однакові. Вам слід було скласти
Timmmm

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

Не думаю, що є велика різниця. Особливо, коли ви порівнюєте його із наступним порядком $ O (n ^ 2) $. i.sli.mg/9zXUQR.png
Ізопікнальне коливання

5

Для ще більшого задоволення в подібному ключі спробуйте побудувати графік часу, зайнятого n операціями, на стандартній структурі даних неперервного набору . Було показано, що асимптотично n  α ( n ), де α ( n ) є оберненою до функції Аккермана (хоча ваш звичайний підручник з алгоритмів, ймовірно, буде відображати лише межу з n log log n або, можливо, n  log *  n ). Для будь-якого числа, яке, швидше за все, ви зустрінете як вхідний розмір, α ( n ) ≤ 5 (і насправді log *  n  ≤ 5), хоча воно і наближається до нескінченності асимптотично.

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


3
  1. Зазвичай алгоритми O (n * log (n)) мають 2-базисну логарифмічну реалізацію.
  2. Для n = 1024, log (1024) = 10, отже n * log (n) = 1024 * 10 = 10240 обчислення, збільшення на порядок.

Отже, O (n * log (n)) подібний до лінійного лише для невеликого обсягу даних.

Порада: не забувайте, що швидка сортування поводиться дуже добре на випадкові дані і що це не алгоритм O (n * log (n)).


3
Всі логарифми однакові, вони відрізняються лише масштабом. Тож я не бачу значення Вашого першого твердження. Крім того, я не погоджуюся з вашим твердженням, що O (n log n) подібний лише до лінійного для невеликої кількості даних. Знову ж таки, це масштабування. Як зустрічний приклад, просто подивіться на графіки у вихідному питанні.
waxwing

Я не маю на увазі графічно схожий (на пряму лінію), але складність часу подібний. Час O (n logn) може бути на порядок більше O (n). Якби графіки порівнювали алгоритми O (n logn) та O (n), ви б зрозуміли, що я маю на увазі. :) Коли N стає більшим і більшим, O (n logn) * переходить до наступних логарифмічних шкал.
Нік Дандулакіс

1
У середньому Quicksort - це алгоритм O (n log n).
Ману

Перший пункт помилковий, як заявив @waxwing. Поділивши межі різних баз, можна довести, що зміна бази журналу лише впливає на складність на постійний коефіцієнт - база журналу не має значення з точки зору складності. Що стосується висновку, то із збільшенням кількості елементів форми лінійних і логарифмічно-лінійних ліній стануть більш схожими, не меншими.
mateor

2

Будь-які дані можна нанести на лінію, якщо вісь обрано правильно :-)

У Вікіпедії сказано, що Big-O - це найгірший випадок (тобто f (x) - O (N) означає, що f (x) "обмежена зверху" знаком N) https://en.wikipedia.org/wiki/Big_O_notation

Ось гарний набір графіків, що відображають відмінності між різними загальними функціями: http://science.slc.edu/~jmarshall/courses/2002/spring/cs50/BigO/

Похідна log (x) дорівнює 1 / x. Ось так швидко збільшується журнал (x) із збільшенням x. Він не є лінійним, хоча може виглядати як пряма, тому що так повільно згинається. Думаючи про O (log (n)), я думаю про це як O (N ^ 0 +), тобто найменша потужність N, яка не є константою, оскільки будь-яка позитивна постійна потужність N з часом її наздожене. Це не на 100% точно, тому професори будуть злитися на вас, якщо ви пояснюєте це так.

Різниця між журналами двох різних баз є постійним множником. Шукайте формулу для перетворення журналів між двома базами: (у розділі "зміна бази" тут: https://en.wikipedia.org/wiki/Logarithm ) Фокус полягає в тому, щоб розглядати k та b як константи.

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


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

1

log (N) - це (дуже) приблизно кількість цифр у N. Отже, здебільшого між log (n) та log (n + 1) є невелика різниця


3
log-base- 10 - це приблизно приблизно кількість цифр у N (припускаючи, що ви використовуєте десяткове подання). Більшість алгоритмів сортування / пошуку використовуватиме log-base-2, який, хоча і пропорційний log-base-10 (тому велике O все ще застосовується), є нічим не схожим на те, що ви описуєте :-)
paxdiablo

Інший спосіб сказати, що log-base-2 - це приблизно кількість цифр у N, коли вони записуються двійковою системою, тобто кількість бітів, необхідних для представлення N.
Тайлер Макгенрі

0

Спробуйте побудувати фактичну лінійну лінію поверх неї, і ви побачите невелике збільшення. Зверніть увагу, що значення Y на 50,0000 менше, ніж значення 1/2 Y на 100000.

Воно є, але воно невелике. Ось чому O (nlog (n)) так хороший!


Це все ще прокляте видовище краще за O (n ^ 2).
paxdiablo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.