Big-O è davvero così rilevante quando si lavora nell'industria?


65

In ogni intervista in cui sono stato, sono stato interrogato sull'analisi matematica della complessità, inclusa la notazione big-O.

Quanto è importante l'analisi big-O per lo sviluppo nell'industria? Quanto spesso lo usi davvero e quanto è necessario avere una mentalità raffinata per il problema?


5
@ MM01 L'ho studiato al liceo e all'università. Sebbene lo riconosca come un elemento fondamentale della conoscenza di un programmatore, non l'ho mai usato in nessuno dei miei compiti.
systempuntoout,

27
Quale settore esatto stai pensando quando lo chiedi? Stai scrivendo un codice di controllo per un rover lunare o una piattaforma di blog?
Tim Post

14
@systempuntoout, non hai mai, mai scelto un algoritmo più veloce di un altro perché più veloce?

3
@ MM01 - Se stai lottando con esso, una delle spiegazioni più semplici (anche se semplificate) può essere trovata qui: rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation
Tim Posta

6
@Systempuntoout, comprendere e usare la notazione O non implica una rigida prova matematica, ma può trasmettere in una semplice espressione come si comporta il tuo algoritmo. Se hai bisogno di ordinare in 1D vuoi un algoritmo O (n log n). Se vuoi un'implementazione del numero di Fibbonacci, scegli quella che gira in O (n). Anche se non lo si dice esplicitamente ad alta voce, questa è ancora la versione ridotta del numero di loop e ricorsioni che è estremamente utilizzabile. Salva molte parole. (E per il nitpicky - sì, anche k è importante se è significativamente grande o piccolo).

Risposte:


76

La mia domanda è: quanto è importante questo test per lo sviluppo nell'industria?

Una solida conoscenza della teoria della complessità computazionale (ad es. Notazione O grande) è essenziale per progettare algoritmi, applicazioni e sistemi scalabili. Poiché la scalabilità è estremamente rilevante per l'informatica nell'industria, lo è anche la grande notazione O.

Con quale frequenza lo usi in modo veritiero e quanto è necessario avere una mentalità raffinata per il problema?

Dipende da cosa intendi per "usalo davvero". Da un lato, non faccio mai prove formali della complessità computazionale per il software che scrivo. D'altra parte, quasi tutti i giorni ho a che fare con applicazioni in cui la scalabilità è una potenziale preoccupazione e le decisioni di progettazione includono la selezione (ad esempio) di tipi di raccolta appropriati in base alle loro caratteristiche di complessità.

(Non so se sia possibile implementare coerentemente sistemi scalabili senza una solida comprensione della teoria della complessità. Sarei propenso a pensare che non lo sia.)


+1 perché i principi sono importanti. Nella mia esperienza nel settore, è una considerazione da tenere in considerazione, non qualcosa su cui soffermarsi molto. Detto questo: ti viene chiesto un confronto tra l'inserimento di un elenco (esempio) rispetto all'inserzione di array, o l'ordinamento di bolle vs quicksort, quindi l'intervistatore punta a misurare le tue conoscenze. E ottieni un apprezzamento se pensi anche a complessità / tempo di esecuzione / scalabilità / prestazioni. Se non riesci / non riesci a pensare a queste cose, ci saranno alcuni lavori che non saprai fare bene. Raro, ma di tanto in tanto viene fuori.
Velocemente il

6
Bene, è possibile, così è sparare a bersagli nell'oscurità buio pesto. Dato abbastanza proiettili, alla fine colpirai il bersaglio. Quindi, sperimentando il risultato di vari fattori di progettazione e implementazione, il che si traduce in un minor numero di proiettili necessari la prossima volta. Pessima analogia, probabilmente, ma descrive accuratamente il modo in cui alcuni software sono scritti. Ho votato a favore della tua risposta.
Tim Post

Ma nota anche che la performance "in modo reale" è più spesso influenzata da problemi che non hanno nulla a che fare con la complessità, ma con scatole nere fuori dal tuo controllo. Un modello mentale di quelle scatole è un must per ottimizzare qualsiasi cosa. Queste considerazioni probabilmente non sono valide quando N si avvicina all'infinito, cosa che non accade mai davvero.
Dr. belisarius,

@Tim Post - Ho detto "... implementare costantemente sistemi scalabili ...". Sicuramente puoi essere fortunato, ma non puoi essere fortunato in modo coerente. Ma sono anche pronto ad accettare che una persona veramente intelligente / esperta potrebbe sviluppare una comprensione intuitiva della complessità senza andare da nessuna parte vicino a un libro di testo o un corso di informatica.
Stephen C,

Nota a margine, ha portato ad alcune buone risate sul lavoro quando un collega maschio ha detto a una collega femmina, "Sembra che tu abbia un grosso problema O", senza rendersi conto dell'altro significato del termine. Lo prese nello spirito che intendeva dire, ma non riuscì a smettere di ridacchiare.
Paul,

36

La ragione di ciò è perché indica la scalabilità .

Un processo che è O (n ^ 2) scalerà peggio di uno che è O (n log n), ma migliore di uno in O (n ^ 3) o addirittura O (n!).

Se non si conoscono le differenze e quando si applicano, si è meno adatti a scegliere le giuste implementazioni di funzionalità, nonché a estrapolare le prestazioni dei test in prestazioni di produzione.


EDIT: un confronto di 48n con n ^ 3 da http://www.codinghorror.com/blog/2007/09/everything-is-fast-for-small-n.html (che a sua volta proviene da Programming Pearls)

inserisci qui la descrizione dell'immagine


8
+1: Il modo peggiore per scoprire che il tuo processo non si ridimensiona è fare in modo che un gruppo di clienti urlanti si presenti tutto in una volta.
Larry Coleman,

22
@Larry, almeno le urla si ridimensionano linearmente con il numero di clienti!

10
Bene, immagino che ciò dimostri quanto sia importante il big-O: il suono è in realtà O(log Customers)dB.
MSalters il

4
@MSalters, ok, sono corretto: "il NUMERO di urla si ridimensiona linearmente con il numero di clienti". Il livello del suono è una questione diversa.

1
@ Thorbjørn Ravn Andersen: ho letto alcuni studi che implicano che è più una scala logaritmica, motivo per cui alcune classi di reclami dei clienti sono così importanti! Indicano che, maggiore è la base di clienti, molte più persone hanno questo problema e semplicemente non dicono nulla o partecipano alla concorrenza.
Steven Evers,

32

Dipende da cosa stai facendo.

Per gli sviluppatori web (come me) questo di solito conta molto. Volete ridimensionare le app Web. Se la tua app ha un collo di bottiglia che si ridimensiona con O (n ^ 2) e pensi che vada bene, perché il tuo server può gestire 1000 utenti simultanei, sembra che non ti interessi. Il fatto è che per gestirne solo il doppio (il che è ragionevolmente probabile che accada poco dopo la notte), avrai bisogno di 4 volte la potenza computazionale. Idealmente, le app Web devono essere ridimensionate su O (n), poiché l'hardware è economico con un rapporto utente / server costante ragionevole.

Generalmente nelle app, dove hai 100000s di oggetti, il grande O verrà a mangiarti. Sei incredibilmente vulnerabile alle cime. Ad esempio, sto attualmente lavorando a un gioco 3D, che è un'app che gestisce un sacco di dati. Oltre al rendering, hai il controllo delle collisioni, la navigazione ecc. Non puoi permetterti di andare nel modo ovvio. Hai bisogno di algoritmi efficaci, hai bisogno di molta cache per ammortizzare quelli meno efficienti. E così via.

Ovviamente se quello che fai è qualcosa come creare un'app mobile mettendo insieme una GUI in un designer di interfacce, collegalo con alcuni servizi web e basta, allora non avrai mai problemi con la complessità. Perché i servizi web che chiami già si occupano di esso.


Realizzare un'app mobile non è solo un caso di mettere insieme una GUI, ma ti perdonerò per aver fatto quella dichiarazione nel 2010 :) C'è complessità nell'architettura, threading, archiviazione dei dati, code di rete, nei dispositivi mobili. Ma Big O grezzo è irrilevante (almeno in iOS) perché dovresti usare strutture di dati e algoritmi nativi.
PostCodeism,

21

In realtà non ho mai applicato formalmente la regola nella mia vita lavorativa.

Tuttavia, devi conoscere questo concetto e applicarlo in modo intuitivo ogni volta che progetti un algoritmo.

La regola è:

Dovresti avere abbastanza familiarità con la notazione O per poter determinare, per un determinato compito, se è necessario calcolarlo formalmente, oppure è sufficiente per valutarlo in modo intuitivo o se puoi semplicemente saltarlo completamente. Proprio come molti altri concetti matematici di base.


10

Bene, forse una piccola storia ti illumina perché DEFINITAMENTE È NECESSARIO:

In un progetto a cui ho lavorato, c'era un programma responsabile della stampa di tutti i tipi di documenti (etichette, liste di prelievo ecc.). Questo programma consisteva in due parti, una che leggeva tutti i dati necessari dal database e li scriveva in un File .ini-style e un'altra parte che legge quei file e li ha riempiti nei template. Questo ha funzionato abbastanza bene per etichette e piccoli elenchi (con solo pochi campi) ma ha funzionato per quasi 10 minuti quando ha dovuto stampare un "grande" elenco di ~ 20 pagine. Poiché l'accesso a questi file ini ha comportato tempi di accesso O (n²), essendo n il numero di campi da stampare.

Se i programmatori originali di questo programma avessero capito la notazione O, non l'avrebbero mai fatto in quel modo. Sostituire quella stupidità con un hashtable lo ha reso molto più veloce.


8

Le prestazioni della Big-O sono importanti, ma sono state ampiamente interiorizzate.

Le prestazioni Big-O di ordinamento e ricerca non contano, perché le persone generalmente usano quelle fornite dal sistema e quelle saranno le migliori possibili (dato che devono essere generalmente utili). Esistono strutture di dati che sono più efficienti per cose diverse, ma di solito possono essere selezionate in base a principi generali (e sono generalmente integrate in linguaggi moderni). C'è un certo senso di algoritmi che si adattano o non si adattano.

Il risultato è che le questioni formali raramente emergono nella pratica, ma la pratica si basa sugli stessi principi.


Dove lo noti davvero è quando guardi il codice scritto da qualcuno che non ha interiorizzato Big-O, ed è sorpreso che il loro sottosistema funzioni in modo così orribile nella produzione. Anche una comprensione di base è sufficiente per farti mettere in discussione quattro loop foreach annidati sugli stessi due enormi array ...
eswald

6

IMHO molti programmi di informatica lasciano molti studenti che vagano laggiù tra le erbacce. Questi programmi non comunicano mai del tutto il quadro di cosa sia la scienza del calcolo. Gli studenti entrano nel settore, alle prese con come applicare i concetti che hanno appreso, con poca comprensione di come si relazionano con il mondo reale.

Direi che il cuore della scienza del calcolo è la capacità di ragionare sul calcolo. E impari vari metodi e tecniche per farlo e li applichi a problemi astratti, che sono primitivi prototipici che si trovano in molti problemi del mondo reale. Il trucco è individuare questi primitivi prototipici nel mondo reale e quindi ragionare su cose come correttezza, complessità, tempo ecc., Che, potresti essere d'accordo, sono problemi reali di cui devi preoccuparti. Comprensione di come si comportano le parti, spesso ti dà un'idea di come si comporta l'intero. E gli stessi metodi e tecniche generali possono anche essere applicati al tutto, ma non con la stessa rigorosità che viene offerta a parti più piccole, ben astratte e ben definite. Ma alla fine, la scienza del calcolo, ti dà la capacità di rendere ragionevole decisioni su come organizzare il calcolo, con una visione reale di come si comporterà in varie condizioni.


5

Promemoria per sé !:

Io e molti altri ci poniamo questa domanda regolarmente.

Penso che il vero motivo per cui lo chiediamo sia perché siamo diventati pigri.

Questa conoscenza non uscirà mai o diventerà obsoleta. Potresti non applicarlo direttamente su base giornaliera ma lo utilizzerai inconsciamente e avrà un effetto positivo sulle tue decisioni di progettazione. Un giorno potrebbe farti risparmiare ore o giorni di programmazione.

Dato che ulteriori problemi sono incapsulati da librerie e strumenti di terze parti e sono disponibili per un numero sempre maggiore di sviluppatori, sarà necessario conoscere queste conoscenze per distinguersi dagli altri e aiutare a risolvere nuovi problemi.


5

Non proprio. Fondamentalmente l'unica volta che ci abbia mai pensato è quando accedo al database. Di solito guardo il codice e dico "Sta facendo n + 1 query, dovresti cambiarlo per fare solo 1 o 2"

Poiché tutti i miei dati vengono letti da un database e mostrati all'utente, cerco di ridurre al minimo la quantità di dati con cui sto lavorando al punto in cui la differenza tra un algoritmo lineare e un O (n ^ 2) è piuttosto trascurabile.

Se c'è un problema, lo profileremo e lo ripareremo in seguito.


1
In realtà penso che questa domanda casuale "n + 1" sia pericolosa. In particolare, ho visto il codice che ha fatto n ^ d query (dove d> = 2) respinto come "n + 1", che ha reso una situazione davvero orribile semplicemente negativa.
philosodad,

3

Tre domande che poni e penso che risposte in forma abbreviata possano aiutare gli argomenti più lunghi forniti finora.

Quanto è importante questo test per lo sviluppo nell'industria?

Dipende dal settore.

Ovunque in cui la velocità del codice o lo spazio del codice sia un problema, è del tutto rilevante per il settore interessato. Spesso devi sapere quanto tempo richiederà una routine o quanta memoria (on / offline) richiederà.

Con quale frequenza lo usi in modo reale?

Dipende dal settore.

Se le prestazioni e il ridimensionamento sono di scarsa preoccupazione per il lavoro da svolgere, raramente, solo quando si verifica un grave calo delle prestazioni. Se sei un ingegnere per un sistema critico altamente utilizzato, probabilmente ogni giorno.

Quanto è necessario avere una mentalità raffinata per il problema?

Totalmente necessario.

Potrebbe essere necessario utilizzarlo ogni giorno o solo in circostanze terribili; ma a volte sarà necessario. Preferibilmente durante la progettazione prima che arrivi un problema, piuttosto che profilare disperatamente un sistema di soffocamento.


3

Direi che è molto frequente. Generalmente non provare qualcosa ha una particolare O-grande, ma abbiamo interiorizzato l'idea, e memorizzati / familiarizzare con le garanzie O grande per particolari strutture dati e algoritmi, e noi scegliere quelli più veloci per un uso particolare. Aiuta ad avere una libreria piena di tutte le opzioni, come la libreria di raccolte Java o C ++ STL. Implicitamente e naturalmente usi big-O ogni giorno quando scegli di usare una java.util.HashMap( O(1)ricerca) invece di una java.util.TreeMap( O(lg n)ricerca) e certamente scegli di non eseguire una ricerca lineare attraverso una java.util.LinkedList( O(n)ricerca) per qualcosa in cui non hai bisogno di un accesso ordinato.

Quando qualcuno sceglie un'implementazione non ottimale e qualcuno che conosce meglio arriva e vede il loro codice, è una parte del nostro vocabolario correggerli "l'implementazione richiede tempo quadratico, ma possiamo farlo scendere a n-log-n tempo facendolo in questo modo invece "naturalmente e automaticamente come useremmo la lingua inglese per ordinare una pizza.


3

Potrebbe non essere necessario eseguire analisi formali, ma almeno una comprensione dell'intestino della complessità dell'algoritmo - e di come confrontare due algoritmi attorno a ciò - è fondamentale se si desidera fare un lavoro non banale e farlo funzionare bene.

Ho lavorato su due diversi sistemi che sembravano a posto nei primi sviluppi, ma ho messo in ginocchio l'hardware nei test di produzione, perché qualcuno ha usato un algoritmo O (n ^ 2). E in entrambi i casi, la correzione è stata una banale modifica a un algoritmo O (n).


1

Probabilmente viene utilizzato in luoghi in cui stanno sviluppando API per il consumo. Il C ++ STL è una delle poche API a cui sono stati imposti limiti di complessità sui suoi algoritmi. Ma per il programmatore di lavoro quotidiano / programmatore senior / designer / architetto non passa molto per la testa.


Qualsiasi buona API per le raccolte offre queste garanzie, ad esempio l'API delle raccolte Java ha anche queste garanzie nella sua documentazione.
Ken Bloom,

1

Non l'ho trovato così importante se non per comunicare idee, e lavoro in settori critici per le prestazioni (raytracing, elaborazione di immagini e mesh, sistemi di particelle, motori fisici, ecc.) E ho dovuto ideare molti algoritmi e strutture dati proprietari quando si lavora in R&S. In queste aree, spesso una manciata di strutture dati e algoritmi molto efficienti possono produrre prodotti completamente nuovi e all'avanguardia mentre gli algoritmi di ieri rendono obsoleti i prodotti esistenti, quindi c'è sempre la ricerca di fare le cose in modo più efficiente. Come avvertimento, non ho mai pubblicato articoli sugli algoritmi che ho ideato. Erano tutti proprietari. Se lo facessi, avrei bisogno dell'aiuto di un matematico per formulare prove e così via.

Tuttavia, a mio avviso, la quantità di lavoro computazionale per iterazione è spesso di interesse più immediato rispetto alla scalabilità dell'algoritmo, a meno che l'algoritmo non si ridimensioni davvero male. Se qualcuno presenta una tecnica all'avanguardia per il raytracing, sono più interessato alle tecniche computazionali come il modo in cui rappresentano e accedono ai dati piuttosto che alla complessità algoritmica perché in questo scenario competitivo e innovativo è già data una ragionevole scalabilità. Non puoi essere competitivo inventando algoritmi che non si adattano.

Naturalmente, se stai confrontando la complessità quadratica con la linearitmica, questa è una differenza enorme. Ma la maggior parte delle persone nel mio campo sono abbastanza competenti da evitare di applicare un algoritmo di complessità quadratica su un input epico. Quindi la scalabilità è spesso profondamente implicita e le domande più significative e interessanti diventano: "Hai usato GPGPU? SIMD? Funziona in parallelo? Come hai rappresentato i dati? Hai riorganizzato per schemi di accesso compatibili con la cache? Come ci vuole molta memoria? Può gestire in modo efficace questo caso? Stai rinviando determinati processi o esegui tutto in una volta sola? "

Anche un algoritmo linearitmico può sovraperformare un algoritmo a tempo lineare se il primo accede alla memoria in un modello più ottimale, ad esempio, o è più adatto per il multithreading e / o SIMD. A volte anche un algoritmo lineare può sovraperformare un algoritmo logaritmico per questi motivi, e gli algoritmi a tempo lineare naturalmente superano quelli logaritmici per gli input di adolescenti.

Quindi per me ciò che conta di più sono quelle che alcune persone potrebbero chiamare "microottimizzazioni", come rappresentazioni di dati (layout di memoria, schemi di accesso con suddivisione del campo caldo / freddo, ecc.), Multithreading, SIMD e occasionalmente GPGPU. In un campo in cui tutti sono già abbastanza competenti da utilizzare algoritmi decenti e all'avanguardia per tutto, con nuovi articoli che vengono sempre pubblicati, il vantaggio competitivo nel battere i maghi algoritmici non deriva da miglioramenti della complessità algoritmica tanto quanto più diretto efficienza computazionale.

Il mio campo è dominato da matematici brillanti, ma non sempre quelli che conoscono il costo computazionale di ciò che stanno facendo o molti trucchi di livello inferiore per accelerare il codice. Di solito questo è il mio vantaggio nel progettare algoritmi e strutture dati più veloci e più stretti, nonostante il mio sia molto meno sofisticato. Sto giocando a ciò che piace all'hardware, verso bit e byte e rendendo ogni iterazione di lavoro molto più economica anche se sto facendo alcune iterazioni di lavoro in più rispetto all'algoritmo davvero sofisticato - il lavoro nel mio caso è drasticamente più economico. Anche il codice che scrivo tende ad essere molto più semplice. Se le persone pensano che le versioni micro-ottimizzate di algoritmi e strutture di dati semplici siano difficili da capire e mantenere,

Come esempio di base, ho trovato una semplice struttura a griglia che ha finito per sovraperformare un albero KD presso la nostra azienda per il rilevamento delle collisioni e la rimozione di punti ridondanti. La mia stupida griglia grezza era molto meno sofisticata dal punto di vista algoritmico e sono molto più stupida matematicamente e algoritmicamente rispetto al ragazzo che ha implementato l'albero KD con il suo nuovo modo di trovare il punto mediano, ma ho appena sintonizzato l'utilizzo della memoria della griglia e i modelli di accesso e è bastato a superare qualcosa di molto più sofisticato.

Un altro vantaggio che ho che mi permette di sopravvivere in un campo dominato da persone molto più intelligenti di me è capire davvero come funziona l'utente, poiché utilizzo il software che sviluppo allo stesso modo. Questo mi dà idee per algoritmi che si allineano molto immediatamente con gli interessi degli utenti. Come esempio di base, la maggior parte delle persone cerca di accelerare cose come il rilevamento delle collisioni usando l'indicizzazione spaziale. Ho fatto una semplice osservazione di orientamento alla carriera quasi un paio di decenni fa per modelli organici che, ad esempio, se un personaggio si mette le mani sul viso, una struttura di indicizzazione spaziale vorrebbe dover dividere i nodi e fare costosi aggiornamenti se il personaggio poi si tolse la mano dalla faccia. Se invece esegui la partizione in base ai dati di connettività anziché alle posizioni dei vertici, puoi finire con una struttura gerarchica stabile che si aggiorna molto rapidamente e non ha mai bisogno di dividere o riequilibrare l'albero (deve solo aggiornare i riquadri di delimitazione in ogni fotogramma di animazione) ... cose come questa - algoritmi di un bambino senza un pesante background matematico potrebbe venire fuori se avessero appena compreso il concetto di base, ma quelli che sfuggivano ai matematici poiché non pensavano alle cose in un modo così vicino a come gli utenti lavoravano e pensavano troppo alle proprietà della geometria e non a come la geometria era comunemente usato. Vado abbastanza d'accordo appoggiandomi più alla conoscenza computazionale generale e alla conoscenza dell'utente finale che alla magia algoritmica. Quindi, comunque, non ho trovato così importante concentrarmi sulla complessità algoritmica.


0

Sì, la complessità è importante nel settore. Se finisci per progettare qualcosa in cui un percorso critico si ridimensiona come N-quadrato (raddoppiando il numero di qualcosa rende il sistema quattro volte più carico), colpirai il collo di bottiglia del ridimensionamento molto più velocemente che se avessi qualcosa che si ridimensiona su N.

Tuttavia, di solito non viene fatto come una prova adeguata, formale, che qualcosa si trova in una data complessità, quindi avere una buona intuizione per quale complessità ha un modello di operazioni è un buon inizio.


0

Non penso mai alla grande O in una prospettiva matematica, non penso mai alla grande O, a meno che non venga chiesto. Vedo solo un algoritmo nella mia testa e posso dire se è male perché fa più cicli attraverso la memoria per ogni N, o se si divide e conquista o qualcosa del genere. Se necessario, posso tradurlo in grande notazione O in pochi secondi, ma è più facile per me sapere come funziona l'algoritmo / contenitore con la memoria, piuttosto che pensare alla prospettiva matematica.


-3

Le domande che vengono poste nelle interviste sono lì per scoprire se puoi spiegare le cose e pensare in modo logico . L'intervistatore sta anche cercando di scoprire se puoi impiegare ciò che sai per risolvere un problema correlato .

Tutti coloro che hanno studiato a fondo l'ingegneria del software si sono imbattuti in "Big O", anche per rispondere a una buona domanda su "Big O" è necessario conoscere alcune strutture di dati e algoritmi standard.

Quando intervisti per un membro dello staff stai cercando qualcuno che possa apprendere rapidamente il lavoro, non qualcuno che già conosce un determinato insieme di competenze dettagliate, quindi può essere molto difficile scegliere domande che l'intervistatore e l'intervistato hanno una comprensione comune di.

Quindi le domande sulla "grande O" possono essere molto rilevanti per il processo di intervista.

Almeno ogni anno nel corso del mio lungo periodo come programmatore di computer, ho dovuto correggere il codice che era lento a causa di qualcuno che non capiva le strutture dati e gli algoritmi corretti da usare, ma puoi risolvere questi problemi senza avere una comprensione dettagliata di Big O. Tuttavia, le persone che capiscono la grande tenda non evitano in primo luogo questi problemi.

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.