Чи важливіший алгоритм, ніж мова програмування?


35

Під час поточного (2013) конкурсу Google Code Jam виникла проблема, яка взяла C ++ та Java людей 200+ рядків коду порівняно з людьми Python, які вирішили ту саму проблему лише за допомогою 40 рядків коду.

Python не є безпосередньо порівнянним з C ++ та Java, але різниця у багатослівності, як я вважав, може вплинути на ефективність алгоритму.

Наскільки важливим є знання правильного алгоритму порівняно з вибором мови? Чи могла б чудово реалізована програма Python реалізована в C ++ або Java краще (використовуючи той самий алгоритм) і чи це має якесь відношення до природного багатомовності певних мов програмування?


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

1
Багато цього повністю залежить від масштабу, над яким ви працюєте за межами LOC. Деякі мови просто не підтримують ні швидкість, ні паралельні потреби. Алгоритми важливі, але іноді, якщо мова x в y рази повільніша, ніж мова z, ви просто не можете використовувати x незалежно від багатослівності.
Ріг

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

5
@Travis: "дефект у швидкості SLOC залишається постійним незалежно від мови", проте це неправда. Дивіться відповідь Джона.
Бен Войгт

Тепер ви подумаєте, як вступити до наступного конкурсу, використовуючи F # як мову!
code4life

Відповіді:


73

Очевидно, якщо ви розглядаєте це питання в контексті чогось на кшталт Google Code Jam, алгоритмічне мислення явно важливіше, коли потрібно вирішувати алгоритмічні проблеми.

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

Просто зустрічний приклад: якщо вам потрібно ще 200 рядків на Java, але всі у вашій компанії знають Java, це не є великою справою. Якби ви могли написати це в 5 рядках Python або будь-якою іншою мовою, але ви б єдиним в компанії знали цю мову - це велика справа. Насправді така велика справа, що вам навіть цього не дозволять, а натомість доведеться писати це на Java.

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

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

Щодо алгоритмічних змагань, однак мій особистий досвід змагання в них протягом декількох років чітко підказує мені, що слід дотримуватися однієї мови. Швидкість - головний фактор, і ви просто не можете дозволити собі витрачати час на свої інструменти, коли вам слід присвятити його вирішенню проблем у визначений термін. Також врахуйте, що написання 200 рядків коду Java без роздумів все-таки набагато швидше, ніж обробка 50 рядків складного пітонного коду, що вимагає багато роздумів, але обидва вирішують більш-менш ту саму проблему.

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


1
+ 1 для "мільйонів інших факторів, які слід враховувати"
ozz

1
Я додам до цього, що якщо це функціональна проблема, яку ви намагаєтеся вирішити, то заради неба, будь ласка, використовуйте функціональну мову! Тому я заперечую, що вам слід дотримуватися однієї мови для основної парадигми програмування.
Martijn Verburg

6
+1 за останнє речення.
Дракон Шиван

4
+1 Рядки коду - сама по собі жахлива метрика. Нам потрібно вимірювати ремонтопридатність , а не рядки коду. 200 рядків безпечного типу коду потенційно можуть бути набагато більш корисними, ніж 50 рядків Python.
Філ

2
@Phil: І 200 рядків Python потенційно можуть бути набагато більш корисними, ніж 50 рядків безпечного типу коду. Я ніколи не бачив такої чіткої переваги в безпечних для мов мовах, маючи на увазі добре написаний код.
Девід Торнлі

17

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

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

Справа в суті: якщо я правильно пригадую, тут у програмі деякий час була публікація, в якій хтось скаржився на те, що він не став FizzBuzz в інтерв'ю, і звинувачував у тому, що він не знав про модуль оператора Java. Цей висновок помилковий - брак знань про те, як працює модуль, змусив його не в змозі алгоритмічно думати про проблему та вирішувати її, навіть за відсутності виділеного оператора модуля. Подальше: у Java є клас дерева - що робити, якщо в майбутньому вам доведеться працювати з мовою, яка не реалізує цей клас? Знову ж таки, вміння думати про проблему, що нагадує про конкретні мови.

Я визнаю, що приклади спрощені, але вони допомагають наблизити крапку.


14

Мова має значення.

DARPA і ВМС США провели експеримент з перестрілки майже 20 років тому. Переможцем темного коня став Хаскелл. Ада та C ++ були представлені; Яви не було.

Приблизно в той же час Pratt & Whitney провели дослідження даних щодо проектів контролерів реактивних двигунів, переглянувши дані таймкарту та помилки трекера. Вони виявили, що Ада давала подвоєну продуктивність програміста і 1/4 щільність дефектів будь-якої іншої мови, якою вони користуються.

Atari використовував FORTH для розробки відеоігор, і той факт, що вони використовували FORTH, вважався надзвичайно захищеним.

Зауваження Пола Грехема щодо використання LISP добре відомі. Erann GAT в коментарі на LISP в JPL однаково переконливі, хоча і не так добре відомі.

Програмне забезпечення авіоніки Boeing 777 - це майже вся Ада. Їх досвід був дуже хорошим, навіть якщо одному з головних субпідрядників довелося починати всередині потоку.

Мова має значення.


Очевидно, що Java випустили після того експерименту, з яким ви посилаєтесь.
тостів_флякс

стаття була опублікована в 1994 році. Перший публічний реліз Java був 1995 року.
Алессандро Теруцці

Справа не в тому, що ваша улюблена мова була або не була представлена ​​в одному конкретному експерименті. Справа в тому, що мова ВАМИ. Було багато анекдотичних досліджень, які показують це досить переконливо. Варто також зазначити, що, незважаючи на те, що американці-програмісти в основному відхиляються, Ада все ще активно використовується в Європі, особливо для високонадійних систем, і досі вона використовується в певних польових системах у США.
Джон Р. Стром

7

Деякі моменти:

  • Верхні позиції мають тенденцію до C ++ / C / Java, незалежно від кількості рядків коду різниця між цією та іншою мовою. Це може бути більше про те, що топ-кодери мають тенденцію вибирати ці мови над деякими іншими, можливо, через швидкість їх використання.
    На жаль, ви не можете легко побачити мову програмування в Google Code Jam, але я завантажив декілька найкращих і, наскільки я пам’ятаю, це переважно C / C ++. TopCoder (популярний веб-сайт хостингу конкурсів програмувань) здебільшого має подібні результати.

  • Оскільки вони досить низькі, я впевнений, що ви не збираєтеся легко перемогти C / C ++ з точки зору сирого часу роботи (а Java не відстає занадто далеко). З мого досвіду, динамічно типізовані мови, як правило, значно повільніше, ніж мови, які набираються статично. Оптимальне рішення може бути недостатньо швидким для деяких мов, але це не повинно бути загальним правилом.

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

  • Пряма кількість ліній не така вже й велика справа. Як тільки ви отримаєте достатній досвід програмування, ви дізнаєтесь, що можете витратити 10 хвилин на програмування 10 рядків або 200 рядків, все залежить від того, наскільки складні лінії. Крім того, якщо ви закодували подібний код сотні разів, ви зможете зробити це досить швидко. Не надто згадуйте про всі макроси, які найпопулярніші C / C ++ кодери часто використовують для оптимізації свого часу кодування.

  • Френк зазначає хорошу думку - (поза межами змагань з програмування) ви не можете займатися кодуванням в Python для вашої компанії, якщо вся їхня кодова база знаходиться на C або будь-якому іншому, вам потрібно відповідати їх мові.

  • Перемикатися між мовами досить просто, нелегко формувати роки знань алгоритмічного мислення. Я готовий зробити ставку майже будь-який відмінний програміст може перейти на іншу (смутно схожу) мову, скажімо, за тиждень. Можливо, він / вона не буде достатньо хорошим, щоб виграти змагання з програмування на цій мові (дайте йому ще 2 тижні), але буде знижено основи.


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

@LieRyan Щоправда, але участь у кількох десятках змагань з програмування (як я маю) на (мабуть) найпопулярнішому такому сайті (TopCoder) і завжди бачити більшість керівних позицій як C / C ++ / Java є досить вагомим. Крім того, я сказав: "схильні до" не "завжди".
Герцогство

не погоджуються, що "Пряма кількість рядків не така вже й велика справа". код ворога
jk.

6
@jk. Чи слід було б виділити "таких"? Це має значення, але це не альфа та омега. Ви віддаєте перевагу кілька менших рядків для читабельності? Я впевнений, що ні. Я візьму кілька простих if-висловлювань до дуже заплутаного, нечитабельного, зміщення бітів, множення, ділення, додавання, віднімання, XORing, ANDing, багатозначного вираження в будь-який день. Можливо, не те, про що ви говорили, але саме до цього зменшується кількість скорочень. І я більше говорив про реалізацію чогось складного в декількох рядках, або чогось простого у багатьох рядках; останні часто займають менше часу.
Герцогство

5

Чи можна таку ж логіку реалізувати краще в C ++? Звичайно, це може, якщо краще ви маєте на увазі швидше та ефективніше пам'ять. Проблема полягає в тому, що кількість зусиль, необхідних для цього, значно більша. Крім того, теоретично ви все ще можете знизити рівень і реалізувати його в чистому С або навіть ASM, що займе ще більше часу, але ви могли б мати ще більш оптимізований код.

Звичайно, у випадку таких змагань, як Code Jam чи TopCoder, це не велика вага, оскільки це всього 40 рядків проти 200 рядків. З іншого боку, для цього виду конкуренції найбільше значення має часова / просторова складність алгоритму. У той час як у реальному застосуванні YMMV, у цих типах змагань алгоритм O (n) , написаний на найповільніших мовах, завжди буде бити O (n²), записаний на найшвидших мовах. Тим більше, що буде кілька тестів, які є найгіршим сценарієм.

Але окрім змагань, якщо ми говоримо про великі проекти з реального життя, то це вже не 40 рядків проти 200 рядків. У великих проектах величезна база коду починає бути проблемою. У який момент ви дістаєтесь до:

C ++ проти Python?

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

Чистий Пітон повільний. Ось чому стандартний інтерпретатор Python (CPython) написаний на C. Практично всі з вбудованими функціями написані як оптимізовані C. Python також може бути легко використаний у поєднанні з бібліотеками C (через ctypes або як рідні модулі cpython ) та з бібліотеками C ++ через Boost :: Python . Таким чином ви можете записати свою логіку високого рівня на Python, гнучку мову, що дозволяє швидко прототипувати та адаптувати (це означає, що ви можете витратити більше часу на налаштування та вдосконалення свого алгоритму). OTOH, ви можете записати свої функції бібліотеки нижчого рівня в модуль C або C ++. Чудовим прикладом такого підходу є SciPy, що є бібліотекою Python, але під кришкою він використовує високооптимізовані числові бібліотеки, такі як ATLAS, LAPACK, Intels MKL або AMML AMML.


Те, що ви пишете, лише вичісує поверхню. Ви припускаєте поняття "кращого", яке не всі поділяють. Якість завжди є питанням придатності до своїх цілей. Програмування на C ++ не завжди підходить для кожної мети.
reinierpost

1
@reinierpost: саме тому я писав про значно більші зусилля. У випадках, про які ви згадуєте, C ++ не підходить, але це не тому, що це неможливо зробити. Це не дуже добре, оскільки це займе занадто багато ресурсів розробника.
vartec

Більше того, у цьому випадку це просто не краще.
reinierpost

2
і насправді це те, що відбувається у багатьох галузях, наприклад, у іграх є багато коду Lua, який склеює код C ++ разом для продуктивності та продуктивності.
gbjbaanb

4

На мою думку, те, що люди розмовно розглядають "мови програмування", - це фактично три окремі речі:

  1. Тип мови та синтаксис
  2. Мова IDE
  3. Наявні бібліотеки для мови

Наприклад, коли хтось виводить C # в дискусію, ви можете подумати, що він / вона говорить про синтаксис мови (1), але на 95% впевнено, що дискусія буде включати .Net Framework (3). Якщо ви не розробляєте нову мову, важко і зазвичай безглуздо виділяти (1) і ігнорувати (2) і (3). Це тому, що IDE та стандартна бібліотека - це "фактори комфорту", які безпосередньо впливають на досвід використання певного інструменту.

Останні кілька років я теж брав участь у програмі Google Code Jam. Перший раз я вибрав C ++, оскільки він має гарну підтримку для читання вводу. Наприклад, зчитування трьох цілих чисел зі стандартного вводу в C ++ виглядає так:

int n, h, w;
cin >> n >> h >> w;

Хоча в C # те саме буде виглядати так:

int n, h, w;
string[] tokens = Console.ReadLine().Split(' ');
n = int.Parse(tokens[0]);
h = int.Parse(tokens[1]);
w = int.Parse(tokens[2]);

Це набагато більше розумових витрат на просту функціональність. У C # речі з багаторядковим введенням ускладнюються. Можливо, я просто тоді не придумав кращого шляху. У всякому разі, я не зміг пройти перший раунд, тому що у мене виникла помилка, яку я не зміг виправити до кінця раунду. За іронією долі метод введення читання пригнічував помилку. Проблема була проста: введення містило число, яке було занадто великим для 32-бітного цілого числа. У C # int.Parse(string)буде викинуто виняток, але в C ++ потік введення файлу встановив би певний прапор помилки і не вдасться мовчки зробити так, щоб підозрюючий розробник не знав про проблему.

Обидва приклади демонструють, як бібліотека використовувалася, а не синтаксис мови. Перший демонструє багатослівність, а другий демонструє надійність. Багато бібліотек переносяться на кілька мов, а деякі мови можуть використовувати бібліотеки, які спеціально не створені для них (див. Відповідь @ vartec про Python з бібліотеками C).

Для завершення цього допомагає знання правильного алгоритму. У змаганнях з кодування це дуже важливо, особливо коли такі ресурси, як час виконання та пам'ять, навмисно обмежені. У розробці додатків це вітається, але, як правило, не має вирішального значення. Там важливіше технічне обслуговування. Цього можна досягти, застосувавши правильні шаблони дизайну, маючи гарну архітектуру, читабельний код та відповідну документацію, і всі ці методи сильно залежать від власних та сторонніх бібліотек. Отже, мені важливіше знати, які колеса вже винайдені і як вони підходять тоді, як зробити свої власні.


1
Підготовка важлива, коли це можливо. У Google Code Jam у мене є невелика бібліотека, яка читає вхідні дані та відображає висновки так, як вони цього хочуть, і я включаю цей код у своє подання.
Марк Херд

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

Я не можу згадати останній раз, коли я читав з stdin. Дайте мені файл, який я можу вставити в аналізатор JSON.
gnasher729

2

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

Integer prev = b.get(k)
if (prev == null) prev = 0
Integer v = a.get(k);
if (v == null) v = 0;
b.put(prev + v);

замість

b[k] += a[k]

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

NB

Різниця між 200 рядками коду та 40 рядками коду величезна, і вона ще більша, коли це різниця між лінією програми 200 000 та лінією програми 40000. Тоді це різниця між командою з п'яти плюс менеджер та командою з одного чи двох.


3
(а) Я знаю факт, що C / C ++ / Java, як правило, займає лідируючі позиції у змаганнях з програмування. (b) C / C ++ багатьма вважається "найпотужнішою мовою" (безумовно, вище Perl / Ruby / Python). (c) Через перевантаження оператора код C ++ може виглядати майже ідентично вашому другому прикладу. (г) Така велика перевірка (на Java, чи не так?) потрібна лише у тому випадку, якщо: (1) Ви не маєте поняття, що робите. (2) Характер даних такий, що цього потрібно (не відбувається у змаганнях з кодування). (3) Ви пишете код для використання іншими людьми (не застосовується).
Герцогство

1
@Dukeling: Відповідно до цього дослідження ( page.mi.fu-berlin.de/prechelt/Biblio/jccpprtTR.pdf ) мови сценаріїв дозволяють швидший розвиток та менший вихідний код. Згідно з іншим дослідженням ( flownet.com/gat/papers/lisp-java.pdf ), Lisp пропонує навіть більшу продуктивність, ніж мови сценаріїв. Відповідно до другого дослідження, процитованого вище, код Lisp виявляється майже таким же швидким, як код C ++, тоді як для запису потрібно менше часу.
Джорджіо

"між лініальною програмою на 200 000 і лінійною програмою в 40 000": я думаю, що вам потрібно розрізняти. Відмінності внаслідок багатомовності мови програмування (синтаксису) не додають складності коду і тому можуть мати незначний вплив на необхідні зусилля з обслуговування. З іншого боку, ви можете мати різну кількість рядків через різні мовні особливості. Наприклад, у Python вам не потрібно керувати пам'яттю, тоді як в C ви повинні самостійно реалізувати все управління пам’яттю. Тоді я погоджуюсь з вами, що у коді С ви маєте більше функціональних можливостей і вам обов'язково потрібен додатковий час на обслуговування.
Джорджіо

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

1
Я цитував дві наукові роботи (на які варто звернути увагу ІМО), я не говорив про те, що про це думають люди на веб-сторінках. Те, що думка широко поширена, не означає, що вона є дійсною. :-) Принаймні, треба перевірити це якось суворо.
Джорджіо

2

Будь-який алгоритм може бути реалізований на будь-якій мові програмування. Зрештою, це не той синтаксис, який має значення. Але використання мови високого рівня, як Python, має свої переваги. Менша робота та менша кількість кодування. Отже, щоб реалізувати алгоритм в Python, вам знадобиться менше рядків, ніж те, що потрібно для мови низького рівня, наприклад C.

Python має більшість структур даних, вбудованих у свою бібліотеку. Але в C нам потрібно починати з нуля і використовувати структуру, щоб все це будувати. Звичайно, існують відмінності між мовою високого та низького рівня, але мова не повинна заважати вам впроваджувати будь-який алгоритм.


2

Хоча екстраполяція прикладу "40 LoC проти 200 LoC", кажучи "ну, лише п'ята частина загального LoC, очевидно, швидше писати, так що це повинно бути краще", може здатися спокусливою, я дійсно думаю, що там правди мало.

На мою думку, оптимізація для найменшого LoC майже ніколи не є доброю ідеєю. Так, кожен написаний LoC - це потенціал для помилок, і вам ніколи не доведеться налагоджувати те, що ви ніколи не писали тощо. Справа в тому, що оптимізувати для читабельності та нерозбірливості. Не має значення, чи вирішуєте ви проблему за допомогою великого регексу в 20 рядків, на відміну від написання модуля 1k LoC. Регекс буде непрозорою стіною, надзвичайно схильною до помилок, важко зрозуміти, кошмарам змінювати, не змінюючи свою поведінку ненаголошеними способами тощо.

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

Дуже показове порівняння: я б скоріше мав 100-мільйонний лок-код тестово нерозчленованого коду C #, наповнений такими предметами, як «надмірне вбивство», як стратегічний зразок, фабрики тощо, а не програма з 20-пітним пітоном, яка просто «спрацьовує». У 5 разів більше коду чи ні, архітектура виграє щодня.

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

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