L'algoritmo è più importante del linguaggio di programmazione?


35

Durante l'attuale concorso (2013) di Google Code Jam , si è verificato un problema che ha portato le persone C ++ e Java oltre 200 righe di codice rispetto alle persone Python che hanno risolto lo stesso problema utilizzando solo 40 righe di codice.

Python non è direttamente paragonabile a C ++ e Java, ma la differenza di verbosità che pensavo potesse forse avere un'influenza sull'efficienza dell'algoritmo.

Quanto è importante conoscere l'algoritmo giusto rispetto alla scelta della lingua? Potrebbe un programma Python ottimamente implementato essere implementato in modo C ++ o Java in modo migliore (usando lo stesso algoritmo) e questo ha qualche relazione con la naturale verbosità di alcuni linguaggi di programmazione?


16
È stato detto (e credo) che il linguaggio di programmazione in cui lavori ha un'influenza sul modo in cui pensi a un problema. Ciò implicherebbe che linguaggi di programmazione molto diversi potrebbero essere adatti a diverse classi di problemi.
Joris Timmermans,

1
Molto di tutto questo dipende interamente dalla scala su cui stai lavorando oltre a LOC. Alcune lingue non supportano la velocità o le esigenze di concorrenza. Gli algoritmi sono importanti ma a volte se la lingua x è y volte più lenta della lingua z, semplicemente non è possibile utilizzare x indipendentemente dalla verbosità.
Rig

Come nota l'unica cosa che ho imparato a scuola è che tutti hanno un bug per ogni riga di codice che rimane costantemente indipendente dal codice usato. Quindi, se una lingua che ti consente di farlo in meno righe di codice comporta quindi un minor numero di bug, puoi portarlo sul mercato più velocemente e meno possibilità apparirà un bug quando un utente lo sta usando. Quindi, a mio avviso, sceglierei la lingua migliore per il lavoro che tutti gli altri nell'azienda sanno che è necessario per lavorare su quel progetto.
Travis Pessetto,

5
@Travis: "il difetto per frequenza SLOC rimane costante indipendentemente dalla lingua", tuttavia non è vero. Vedi la risposta di John.
Ben Voigt,

Ora mi stai pensando di partecipare al prossimo concorso usando F # come lingua!
code4life

Risposte:


73

Ovviamente, se consideri questa domanda nel contesto di qualcosa come Google Code Jam, il pensiero algoritmico è chiaramente più importante quando devi risolvere problemi algoritmici.

Nella vita di tutti i giorni, tuttavia, devono essere considerati anche circa un milione di altri fattori, il che rende la domanda molto meno nera rispetto al bianco.

Solo un contro-esempio: se hai bisogno di altre 200 linee in Java, ma tutti nella tua azienda conoscono Java, questo non è un grosso problema. Se potessi scriverlo in 5 righe di Python o in qualsiasi altra lingua, ma saresti l'unico in azienda a conoscere quella lingua - è un grosso problema. Un affare così grande, infatti, che non ti sarà nemmeno permesso farlo e invece dovrai scriverlo in Java.

Dal punto di vista di un artigiano, cerchiamo sempre di avvicinarsi con lo strumento giusto per il lavoro, ma la parola giusta in là è così difficile che si può facilmente sbagliare.

Al contrario, ho trovato quasi assente il pensiero algoritmico nelle aziende. Solo poche persone selezionate lo possiedono, mentre il joe medio spesso ha già problemi a stimare le complessità di runtime di loop, ricerche, ecc.

In termini di competizioni algoritmiche, tuttavia, la mia esperienza personale derivante dalla competizione in esse per diversi anni, mi dice chiaramente che dovresti attenersi a una lingua. La velocità è un fattore importante e semplicemente non puoi permetterti di perdere tempo con i tuoi strumenti, quando dovresti dedicarla alla risoluzione dei problemi entro il limite di tempo. Considera anche che scrivere 200 righe di codice Java senza pensare è ancora molto più veloce rispetto alla creazione manuale di 50 righe di codice pitone complicato che richiede molta riflessione, eppure entrambe risolvono più o meno lo stesso problema.

Oh, e infine, assicurati di comprendere le principali differenze tra il codice di concorrenza algoritmica e il codice di produzione dell'azienda. Ho visto fantastici programmatori algoritmici, che hanno scritto un codice orribile che non avrei mai accettato in un prodotto.


1
+ 1 per "milioni di altri fattori da considerare"
ozz

1
Aggiungerò a ciò che se si tratta di un problema funzionale che si sta tentando di risolvere, per l'amor del cielo, si prega di utilizzare un linguaggio funzionale! Quindi direi che dovresti davvero applicare una lingua per ogni grande paradigma di programmazione.
Martijn Verburg,

6
+1 per l'ultima frase.
Drago di Shivan,

4
+1 Le righe di codice sono di per sé una terribile metrica. Dobbiamo misurare la manutenibilità , non le righe di codice. 200 righe di codice sicuro possono essere molto più gestibili di 50 righe di Python.
Phil,

2
@Phil: E 200 righe di Python possono potenzialmente essere molto più gestibili rispetto a 50 righe di codice sicuro. Non ho mai visto questo vantaggio di chiarezza nei linguaggi sicuri per i tipi, assumendo un codice ben scritto.
David Thornley,

17

Direi che, anche al di fuori delle competizioni, il pensiero algoritmico è più importante che conoscere ogni trucco per un linguaggio specifico.

Certo, vuoi conoscere la lingua con cui lavori il più bene possibile, ma le lingue vanno e vengono, mentre la capacità di pensare in modo astratto in termini di algoritmi è un'abilità altamente trasferibile.

Caso in questione: se ricordo bene, qualche tempo fa c'era un post su Programmers in cui qualcuno si lamentava del fallimento di FizzBuzz in un'intervista e incolpava la sua mancanza di conoscenza dell'operatore modulo Java. Questa conclusione è sbagliata: la mancanza di conoscenza del funzionamento del modulo lo ha reso incapace di pensare algoritmicamente al problema e risolverlo, anche in assenza di un operatore modulo dedicato. Andare oltre: Java ha una classe Tree - e se in futuro dovessi lavorare con un linguaggio che non implementa questa classe? Ancora una volta, la capacità di pensare al problema supera i dettagli specifici della lingua.

Ammetto che gli esempi sono semplicistici, ma aiutano a chiarire il punto.


14

La lingua conta.

DARPA e la US Navy hanno fatto un esperimento di sparatorie quasi 20 anni fa. Il vincitore dell'oscurità fuggiasco cavallo fu Haskell. Ada e C ++ erano entrambi rappresentati; Java no.

Più o meno nello stesso periodo, Pratt & Whitney ha condotto uno studio di data mining su progetti di controller di motori a reazione, esaminando i dati relativi a timecard e bug tracker. Hanno scoperto che Ada ha raddoppiato la produttività del programmatore e 1/4 della densità di difetto di qualsiasi altra lingua che stavano usando.

Atari usava FORTH per sviluppare videogiochi e il fatto che stessero usando FORTH era considerato estremamente proprietario.

I commenti di Paul Graham sull'uso di LISP sono ben noti. I commenti di Erann Gat su LISP a JPL sono altrettanto convincenti, sebbene non così noti.

Il software avionico Boeing 777 è praticamente tutto Ada. La loro esperienza è stata molto positiva, anche se un importante subappaltatore ha dovuto ricominciare da capo.

La lingua conta.


Ovviamente, java è stato rilasciato dopo quell'esperimento a cui ti stai collegando.
toasted_flakes

l'articolo fu pubblicato nel 1994. La prima versione pubblica di Java fu il 1995.
Alessandro Teruzzi,

Il punto non è che la tua particolare lingua preferita fosse o non fosse rappresentata in un particolare esperimento. Il punto è che la lingua è MATERIA. Ci sono stati MOLTI studi aneddotici, che mostrano questo in modo abbastanza conclusivo. Vale anche la pena notare che, nonostante sia stato in gran parte respinto dai programmatori americani, Ada è ancora ampiamente utilizzato in Europa, in particolare per i sistemi ad alta affidabilità, ed è ancora utilizzato in alcuni sistemi in campo negli Stati Uniti.
John R. Strohm,

7

Alcuni punti:

  • Le prime posizioni tendono ad essere C ++ / C / Java, indipendentemente da quante righe di codice la differenza è tra quella e qualche altra lingua. Questo potrebbe essere più che i migliori programmatori tendono a scegliere queste lingue rispetto ad altre, probabilmente a causa della loro velocità non elaborata.
    Sfortunatamente non puoi vedere facilmente il linguaggio di programmazione su Google Code Jam, ma ho scaricato alcuni dei migliori e, per quanto mi ricordo, questi sono principalmente C / C ++. TopCoder (un popolare sito di hosting di contest di programmazione online) per lo più ha risultati simili.

  • Dato che hanno un livello piuttosto basso, sono abbastanza sicuro che non batterai facilmente C / C ++ in termini di tempo di esecuzione grezzo (e Java non è troppo indietro). Dalla mia esperienza, le lingue tipizzate in modo dinamico tendono ad essere significativamente più lente delle lingue tipizzate staticamente. La soluzione ottimale potrebbe non essere nemmeno abbastanza veloce in alcune lingue, ma questa non dovrebbe essere una regola generale.

  • L'algoritmo giusto è vitale. Se hai saputo risolvere tutti i problemi (in dettaglio) fin dall'inizio e sei un buon programmatore veloce, molto probabilmente vincerai, indipendentemente dalla lingua in cui codifichi (assumendo la soluzione ottimale in quella lingua è abbastanza veloce).

  • Il numero di righe non è un grosso problema. Una volta che avrai abbastanza esperienza di programmazione, saprai che puoi passare 10 minuti a programmare 10 linee o 200 linee, tutto dipende dalla complessità delle linee. Inoltre, se hai codificato codice simile centinaia di volte, sarai in grado di farlo abbastanza rapidamente. Non troppo menzione di tutte le macro che i migliori programmatori C / C ++ usano spesso per ottimizzare i loro tempi di codifica.

  • Frank ha un buon punto - (al di fuori delle competizioni di programmazione) non puoi fare la codifica in Python per la tua azienda se la loro intera base di codice è in C o altro, devi conformarti al loro linguaggio.

  • È abbastanza facile passare da una lingua all'altra, non è facile accumulare anni di conoscenza del pensiero algoritmico. Sono disposto a scommettere che quasi tutti i programmatori eccellenti possono passare a un'altra lingua (vagamente simile) in una settimana, diciamo. Forse lui / lei non sarà abbastanza bravo da vincere concorsi di programmazione in quella lingua (date altre 2 settimane), ma avrà le basi giù.


Falsità: il download di diverse soluzioni da alcuni siti di contest di codice è uno studio scientifico definitivo sufficiente per concludere che si sa sicuramente come siano le posizioni migliori.
Lie Ryan,

@LieRyan Vero, ma prendere parte a poche decine di competizioni di programmazione (come ho fatto io) sul (probabilmente) il sito più popolare (TopCoder) e vedere sempre la maggior parte delle prime posizioni come C / C ++ / Java è piuttosto significativo. Inoltre, ho detto che "tendono a" non "sono sempre".
Dukeling,

non sono d'accordo sul fatto che "Il numero di righe non è un grosso problema". il codice è il nemico
jk.

6
@jk. Avrei dovuto evidenziare "tale"? È importante, ma non è l'alfa e l'omega. Preferisci qualche riga in meno alla leggibilità? Di sicuro no. Porterò alcune semplici istruzioni if ​​a un'espressione molto confusa, illeggibile, che sposta i bit, moltiplica, divide, aggiunge, sottrae, XORing, ANDing, espressione multi-condizionale ogni giorno. Forse non è quello di cui stavi parlando, ma è a questo che a volte si riduce il conteggio delle linee. E stavo parlando più dell'implementazione di qualcosa di complesso in poche righe o di qualcosa di semplice in molte righe; quest'ultimo spesso richiede meno tempo.
Dukeling,

5

La stessa logica può essere implementata meglio in C ++? Certo che può, se per meglio intendi più veloce ed efficiente memoria. Il problema è che lo sforzo richiesto per farlo è significativamente più alto. Inoltre, teoricamente potresti comunque passare al livello inferiore e implementarlo in C o ASM puro, il che richiederebbe ancora più tempo, ma potresti avere un codice ancora più ottimizzato.

Naturalmente, nel caso di competizioni come Code Jam o TopCoder non è un grosso problema, in quanto è solo 40 linee contro 200 linee. D'altra parte in questo tipo di competizione ciò che conta di più è la complessità tempo / spazio dell'algoritmo. Durante l'applicazione nella vita reale, YMMV, in questi tipi di competizioni, l' algoritmo O (n) scritto nelle lingue più lente batterà sempre O (n²) scritto nelle lingue più veloci. Soprattutto che ci saranno test multipli che rappresentano lo scenario peggiore.

Ma a parte le competizioni, se stiamo parlando di grandi progetti nella vita reale, allora non sono più 40 linee contro 200 linee. Nei grandi progetti l'enorme base di codice inizia a rappresentare un problema. A quel punto si arriva a:

C ++ vs Python?

inserisci qui la descrizione dell'immagine

Pure Python è lento. Ecco perché l'interprete Python standard (CPython) è scritto in C. Praticamente tutto con funzioni integrate scritte come C. Python altamente ottimizzato può anche essere facilmente usato insieme alle librerie C (via ctypes o come moduli nativi cpython ) e con le librerie C ++ tramite Boost :: Python . In questo modo puoi scrivere la tua logica di alto livello in Python, un linguaggio flessibile, che consente la prototipazione e l'adattamento rapidi (il che significa che puoi dedicare più tempo a modificare e migliorare il tuo algoritmo). OTOH, puoi scrivere le tue funzioni di libreria di livello inferiore nel modulo C o C ++. Un grande esempio di tale approccio è SciPy, che è la libreria Python, ma sotto il cofano utilizza librerie numeriche altamente ottimizzate come ATLAS, LAPACK, Intels MKL o ACD di AMD.


Quello che stai scrivendo raschia solo la superficie. Stai assumendo una nozione di "migliore" che non tutti condividono. La qualità è sempre una questione di idoneità ai propri obiettivi. La programmazione in C ++ non è sempre adatta a tutti gli obiettivi.
reinierpost,

1
@reinierpost: ecco perché ho scritto di sforzi significativamente più elevati. Nei casi in cui menzioni C ++ non è adatto, ma non perché non può essere fatto. Non è adatto, perché ci vorranno troppe risorse per gli sviluppatori.
vartec,

Inoltre, in questo caso non è meglio.
reinierpost,

2
e in effetti questo è ciò che accade in molti settori, ad esempio i giochi hanno molto codice Lua che incolla il codice C ++ sia per prestazioni che per produttività.
gbjbaanb,

4

A mio avviso, ciò che le persone colloquialmente considerano un "linguaggio di programmazione" sono in realtà tre cose separate:

  1. Tipo di lingua e sintassi
  2. IDE lingua
  3. Librerie disponibili per una lingua

Ad esempio, quando qualcuno fa apparire C # in una discussione, potresti pensare che stia parlando della sintassi del linguaggio (1), ma è certo al 95% che la discussione coinvolgerà .Net framework (3). Se non stai progettando una nuova lingua, è difficile e di solito inutile isolare (1) e ignorare (2) e (3). Questo perché IDE e la libreria standard sono "fattori di comfort", elementi che influenzano direttamente l'esperienza di utilizzo di un determinato strumento.

Negli ultimi anni anche io ho partecipato a Google Code Jam. La prima volta che ho optato per il C ++ perché ha un buon supporto per leggere l'input. Ad esempio, la lettura di tre numeri interi da un input standard in C ++ è simile alla seguente:

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

Mentre in C # lo stesso sarebbe simile a questo:

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

Questo è molto più sovraccarico mentale per una semplice funzionalità. Le cose diventano ancora più complicate in C # con input multilinea. Forse semplicemente non ho capito un modo migliore di allora. Comunque, non sono riuscito a superare il primo round perché avevo un bug che non riuscivo a correggere prima della fine del round. Ironia della sorte, il metodo di lettura dell'input ha offuscato il bug. Il problema era semplice, l'input conteneva un numero troppo grande per un numero intero a 32 bit. In C # int.Parse(string)genererebbe un'eccezione, ma in C ++ il flusso di input di file imposterebbe un determinato flag di errore e fallirebbe silenziosamente rendendo inconsapevole lo sviluppatore ignaro di un problema.

Entrambi gli esempi dimostrano come è stata utilizzata la libreria piuttosto che la sintassi del linguaggio. Il primo dimostra la verbosità e l'altro dimostra l'affidabilità. Molte librerie sono portate su più lingue e alcune lingue possono usare librerie che non sono state create appositamente per loro (vedi la risposta di @ vartec su Python con le librerie C).

Per concludere, conoscere l'algoritmo giusto aiuta. Nelle competizioni di codifica è cruciale, specialmente quando risorse come il tempo di esecuzione e la memoria sono volutamente limitate. Nello sviluppo di applicazioni è il benvenuto ma generalmente non cruciale. La manutenibilità è più importante lì. Ciò può essere ottenuto applicando modelli di progettazione corretti, con buona architettura, codice leggibile e documentazione pertinente e tutti questi metodi dipendono fortemente dalle librerie interne e di terze parti. Quindi, trovo più importante sapere che tipo di ruote sono già state inventate e come si adattano quindi come costruirle.


1
La preparazione è importante quando possibile. Con Google Code Jam ho una piccola libreria che legge l'input e visualizza l'output come lo desidera, e includo quel codice nella mia richiesta.
Mark Hurd,

La seconda volta ho fatto qualcosa di simile ma come modello di progetto. Crea un file sorgente con una classe di input in basso Maine alcune cose all'interno del Mainmetodo (istanza della mia classe di input e flusso di output e case case).
Imperatore Orionii

Non ricordo l'ultima volta che ho letto da Stdin. Dammi un file che posso inserire in un parser JSON.
gnasher729,

2

Se vuoi competere in gare di programmazione a tempo, dovresti imparare il linguaggio più espressivo consentito nella competizione. Perl sarebbe probabilmente il migliore, seguito da Ruby o Python. Avrai comunque bisogno di una buona facilità con gli algoritmi, ma almeno non ti impantanerai a scrivere qualcosa del genere

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

invece di

b[k] += a[k]

Non preoccuparti di imparare diverse librerie. Sono tutti molto simili e la documentazione è online. Diventare fluente in linguaggi più espressivi ti renderà un programmatore migliore (ma probabilmente frustrato) in linguaggi meno espressivi. Non è vero il contrario.

NB

La differenza tra 200 righe di codice e 40 righe di codice è enorme, ed è ancora maggiore quando è la differenza tra un programma di 200.000 righe e un programma di 40.000 righe. Quindi è la differenza tra una squadra di cinque più un manager e una squadra di uno o due.


3
(a) So per certo che C / C ++ / Java tendono ad essere le prime posizioni nelle competizioni di programmazione. (b) C / C ++ è considerato il "linguaggio più potente" da molti (decisamente sopra Perl / Ruby / Python). (c) A causa del sovraccarico dell'operatore, il codice C ++ può sembrare quasi identico al secondo esempio. (d) Tale controllo approfondito (in Java, vero?) è richiesto solo se: (1) Non hai idea di cosa stai facendo. (2) La natura dei dati è tale che ciò è necessario (non accade nelle competizioni di codifica). (3) Stai scrivendo il codice per essere utilizzato da altre persone (non applicabile).
Dukeling,

1
@Dukeling: secondo questo studio ( page.mi.fu-berlin.de/prechelt/Biblio/jccpprtTR.pdf ) i linguaggi di scripting consentono uno sviluppo più rapido e un codice sorgente più piccolo. Secondo un altro studio ( flownet.com/gat/papers/lisp-java.pdf ), Lisp offre una produttività ancora maggiore rispetto ai linguaggi di scripting. Secondo il secondo studio sopra citato, il codice Lisp risulta quasi veloce quanto il codice C ++ mentre richiede meno tempo per scrivere.
Giorgio,

"tra un programma di 200.000 linee e un programma di 40.000 linee": penso che tu debba distinguere. Le differenze dovute alla verbosità del linguaggio di programmazione (sintassi) non aggiungono complessità al codice e pertanto possono avere un impatto limitato sullo sforzo di manutenzione richiesto. D'altra parte, è possibile avere un conteggio di riga diverso a causa delle diverse funzionalità della lingua. Ad esempio in Python non è necessario gestire la memoria mentre in C è necessario implementare tutta la gestione della memoria da soli. Quindi sono d'accordo con te sul fatto che nel codice C hai più funzionalità e sicuramente hai bisogno di tempi di manutenzione aggiuntivi.
Giorgio,

@Giorgio Non sto discutendo dei tempi di sviluppo o delle dimensioni del codice sorgente, ma semplicemente di ciò che accade effettivamente nelle competizioni di programmazione, sulla base di esperienze significative.
Dukeling,

1
Stavo citando due articoli scientifici (che vale la pena dare un'occhiata all'IMO), non stavo parlando di cosa ne pensano le persone sulle pagine web. Il fatto che un'opinione sia diffusa non implica automaticamente che sia valida. :-) Almeno, bisogna verificarlo in modo rigoroso.
Giorgio,

2

Qualsiasi algoritmo può essere implementato in qualsiasi linguaggio di programmazione. Dopotutto, non è la sintassi che conta. Ma usare un linguaggio di alto livello come Python ha i suoi vantaggi. Meno lavoro e meno quantità di codifica. Quindi, per implementare un algoritmo in Python, avrai bisogno di meno righe rispetto a quanto richiesto in un linguaggio di basso livello come C.

Python ha la maggior parte delle strutture di dati integrate nella sua libreria. Ma in C, dobbiamo iniziare da zero e usare una struttura per costruirlo tutto. Certamente ci sono differenze tra il linguaggio di alto e basso livello, ma il linguaggio non dovrebbe impedirti di implementare alcun algoritmo.


2

Estrapolando l'esempio "40 LoC vs 200 LoC", dicendo "beh, solo un quinto del LoC totale è ovviamente più veloce da scrivere, quindi deve essere migliore" può sembrare allettante, penso davvero che ci sia poca verità da trovare lì.

L'ottimizzazione per un minor numero di LoC non è quasi mai una buona idea secondo me. Sì, ogni LoC scritto è un potenziale bug e non devi mai eseguire il debug di ciò che non hai mai scritto eccetc. Il punto è ottimizzare per leggibilità e disaccoppiamento. Non importa se risolvi un problema usando una regex di 20 righe, invece di scrivere un modulo di 1k LoC. Il regex sarà una parete opaca, estremamente soggetta a bug, difficile da capire, da incubo da modificare senza cambiare il suo comportamento in modi non prevedibili ecc.

Sbarazzarsi di boilerplate e verbosità che non aggiunge alcun valore va bene, ma d'altra parte, usando qualcosa come Java o C #, avere conoscenza di modelli di progettazione e strumenti come resharper ti consente così tanta flessibilità nel refactoring del codice , ripulendolo nel tempo, rompendo le cose, ecc., Sarebbe semplicemente MOLTO più difficile se lo scrivessi come uno script python molto più piccolo o un'app ruby.

Un confronto molto eloquente: preferirei avere 100k LoC di codice C # disaccoppiato coperto da test, pieno di roba "eccessiva" come modello di strategia, fabbriche ecc., Piuttosto che un'app 20k python che semplicemente "fa cose". 5 volte più codice o meno, l'architettura vince ogni giorno.

Concordo pienamente sul fatto che alcuni tipi di lavoro siano più facili e più convenienti in alcune lingue, ma credo di più nella scelta della lingua in base agli strumenti necessari e ai requisiti (e che potrebbero essere nel prossimo futuro).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.