Quali algoritmi / strutture di dati dovrei "riconoscere" e conoscere per nome? [chiuso]


69

Vorrei considerarmi un programmatore abbastanza esperto. Sto programmando da oltre 5 anni. Il mio punto debole è la terminologia. Sono autodidatta, quindi mentre so programmare, non conosco alcuni degli aspetti più formali dell'informatica. Quindi, quali sono algoritmi / strutture dati pratici che potrei riconoscere e conoscere per nome?

Nota, non sto chiedendo una raccomandazione libro sull'implementazione di algoritmi. Non mi interessa implementarli, voglio solo essere in grado di riconoscere quando un algoritmo / struttura dati sarebbe una buona soluzione a un problema. Sto chiedendo di più un elenco di algoritmi / strutture di dati che dovrei "riconoscere". Ad esempio, conosco la soluzione a un problema come questo:

Gestisci un set di armadietti etichettati 0-999. Le persone vengono da te per affittare l'armadietto e poi tornano per restituire la chiave dell'armadietto. Come costruiresti un software per gestire sapendo quali armadietti sono gratuiti e quali sono utilizzati?

La soluzione sarebbe una coda o uno stack.

Quello che sto cercando sono cose come "in quale situazione dovrebbe essere usato un B-Tree - Quale algoritmo di ricerca dovrebbe essere usato qui" ecc. E forse una rapida introduzione di come le strutture di dati più complesse (ma comunemente utilizzate) / gli algoritmi funzionano.

Ho provato a guardare l'elenco di strutture dati e algoritmi di Wikipedia, ma penso che sia un po 'eccessivo. Quindi sto cercando di più per quali sono le cose essenziali che dovrei riconoscere?


10
Votare per chiudere come "non costruttivo". Qualsiasi risposta sarà del tutto soggettiva - non vi è consenso su ciò che si dovrebbe "sapere".
Oded,

2
Quale parte di quel problema di armadietto richiede l'ordinazione di input / output? [suggerimento!]
Telastyn il

5
@Oded c'è assolutamente un elenco che penso che la maggior parte delle persone concorderà per quali strutture di dati e algoritmi dovrebbe conoscere un programmatore esperto.
David Cowden,

6
@Oded Nessun consenso? Che dire del programma di un corso introduttivo su algoritmi e strutture dati nell'informatica? Abbastanza ben standardizzato e peer review . Un buon punto di partenza
MarkJ

3
Soluzione alternativa; supponi di addebitare di giorno in giorno e di avere un costo massimo. Allegare un tag di carta alla chiave quando si lascia l'armadietto e scrivere il numero del giorno giuliano su di esso. Quando viene restituita la chiave, guarda il tag per calcolare l'affitto dovuto. I tag mancanti o cancellati attirano la carica massima. Le chiavi inutilizzate sono conservate in un sacchetto (poiché non è necessario selezionare alcuna chiave particolare dalle chiavi libere quando si lascia un armadietto). Dimensione totale della struttura dei dati: zero bit. Tutte le parti dell'algoritmo sono O (1).
James Youngman,

Risposte:


78

Una risposta obiettiva:

Mentre la mia risposta iniziale a questa domanda si basava sulla mia esperienza empirica di studente universitario di prossima laurea e sulla mia proiezione dell'opinione sul tipo di persone con cui volevo lavorare nel campo CS. In realtà esiste una risposta obiettiva (rispetto alle opinioni soggettive delle società di elaborazione ACM SIGCSE e IEEE). Ogni 10 anni l' ACM e gli organismi IEEE collaborano a una pubblicazione congiunta che descriva in dettaglio suggerimenti per il curriculum di informatica in base alla conoscenza professionale dello stato del settore informatico. Maggiori informazioni sono disponibili su cs2013.org . Il comitato pubblica un rapporto finale che elenca le raccomandazioni del proprio curriculum .

Detto questo, penso ancora che la mia lista sia abbastanza buona.

Risposta originale di seguito.


Cosa dovrei sapere?

Minimo

Penso che un programmatore esperto dovrebbe avere almeno una conoscenza di livello universitario in Informatica. Certo, puoi essere efficace in molti lavori solo con un piccolo sottoinsieme di Informatica a causa della solida comunità su cui si trova CS e del focus ristretto della maggior parte delle posizioni professionali. Inoltre, molte persone si specializzeranno ulteriormente dopo gli studi universitari. Tuttavia, non penso nemmeno che sia una scusa per non essere al corrente delle conoscenze di base CS.

Per rispondere alla domanda sul titolo, ecco cosa dovrebbe sapere uno studente universitario (la base per un programmatore esperto) dopo la laurea:

Strutture dati

  • Rappresentazione dei dati macchina
    • Quello, il complemento a due e l'aritmetica correlata
    • Parole, puntatori, virgola mobile
    • Bit Access, Shifting e Manipulation
  • Elenchi collegati
  • Tabelle hash (mappe o dizionari)
  • Array
  • Alberi
  • Stacks
  • code
  • grafici
  • Banche dati

algoritmi

  • Ordinamento:
    • Bubble Sort (per sapere perché è male)
    • Ordinamento inserzione
    • Unisci ordinamento
    • Ordinamento rapido
    • Ordinamento in stile Radix, ordinamento conteggio e ordinamento benna
    • Ordinamento dell'heap
    • Bogo e Quantum Sort (=
  • Ricerca:
    • Ricerca lineare
    • Ricerca binaria
    • Profondità Prima ricerca
    • Larghezza Prima ricerca
  • Manipolazione delle stringhe
  • Iterazione
  • Traversal Tree
  • Elenco trasversale
  • Funzioni di hash
  • Implementazione concreta di una tabella hash, albero, elenco, pila, coda, matrice e set o raccolta
  • Algoritmi di pianificazione
  • Traversal e manipolazione del file system ( sull'inode o livello equivalente).

Modelli di progettazione

  • La modularizzazione
  • Fabbrica
  • Costruttore
  • Singleton
  • Adattatore
  • Decoratore
  • Pesi mosca
  • Osservatore
  • Iterator
  • Stato [Macchina]
  • Model View Controller
  • Threading e schemi di programmazione parallela

paradigmi

  • Imperativo
  • Orientato agli oggetti
  • Funzionale
  • Dichiarativo
  • Programmazione statica e dinamica
  • Markup dei dati

Teoria della complessità

  • Spazi di complessità
  • computabilità
  • Lingue complete regolari, senza contesto e universali
  • Espressioni regolari
  • Conteggio e combinazione di base

Al di là

Per entrare in quello che stai chiedendo più avanti nella tua domanda, se hai familiarità con quanto sopra, dovresti essere facilmente in grado di identificare il modello, l'algoritmo e la struttura dei dati appropriati per un determinato scenario. Tuttavia, dovresti riconoscere che spesso non esiste la soluzione migliore. A volte ti potrebbe essere richiesto di scegliere il minore tra due mali o anche semplicemente scegliere tra due soluzioni ugualmente praticabili. Per questo motivo, hai bisogno delle conoscenze generali per poter difendere la tua scelta dai tuoi pari.

Ecco alcuni suggerimenti per algoritmi e strutture dati:

  • La ricerca binaria può essere (e dovrebbe) essere utilizzata solo su dati ordinati.
  • I tipi di stile Radix sono fantastici, ma solo quando hai classi finite di cose da ordinare.
  • Gli alberi sono buoni per quasi tutto come le tabelle hash. La funzionalità di una tabella hash può essere estrapolata e utilizzata per risolvere molti problemi a costo dell'efficienza.
  • Le matrici possono essere utilizzate per supportare strutture di dati di livello superiore. A volte una "struttura di dati" non è altro che una matematica intelligente per accedere a posizioni in un array.
  • La scelta della lingua può fare la differenza tra strappare i capelli o navigare attraverso un problema.
  • La tabella ASCII e una matrice di 128 elementi formano una tabella hash implicita (=
  • Le espressioni regolari possono risolvere molti problemi, ma non possono essere utilizzate per analizzare l'HTML .
  • A volte la struttura dei dati è importante quanto l'algoritmo.

Alcuni dei precedenti potrebbero non sembrare dei cervelletti e altri possono sembrare vaghi. Se vuoi che vada più in dettaglio, posso. Ma la mia speranza è quando ci si imbatte in una domanda più concreta come "Progetta una funzione che conta il numero di occorrenze di ogni carattere in una stringa", guardi in punta alla tabella ASCII e 128 matrici di elementi che formano un hash implicito pulito tabelle per la risposta.

Sulla base di queste idee, proporrò una risposta al problema dell'armadietto indicato nella tua domanda.


Rispondi al problema posto nella tua domanda.

Questa potrebbe non essere la migliore risposta alla tua domanda, ma penso che sia interessante e che non richiede nulla di troppo complesso. E certamente batterà la complessità temporale dell'uso di una coda, o stack che richiede tempo lineare per determinare se un armadietto è libero o meno.

Hai 0-999 armadietti. Ora, poiché hai un numero fisso di armadietti, puoi facilmente concepire una funzione di hashing senza collisioni nell'intervallo 0-999. Questa funzione è semplicemente h (x) = x mod 1000. Ora, [concettualmente] costruiamo una tabella hash con chiavi intere e il contenuto di un array di caratteri di 1000 elementi come valori. Se un cliente desidera riservare l'armadietto 78 per l'uso, è sufficiente inserire 78 nella funzione hash (restituendo 78), quindi aggiungere quel numero al puntatore di base dell'array, memorizzando un valore vero nella posizione indicata dal valore di offset . Allo stesso modo, se è necessario verificare se 78 è in uso, è sufficiente leggere il valore memorizzato in quella posizione e verificare con true.

Questa soluzione opera in tempo costante per le ricerche e l'archiviazione rispetto a un archivio (n) tempo di archiviazione e ricerca nel caso di una coda prioritaria supportata da un albero binario. La descrizione è intenzionalmente dettagliata in modo da poter vedere i concetti più alti essere ridotti in un algoritmo efficiente.

Ora, potresti chiedere, e se avessi bisogno di conoscere tutti gli armadietti disponibili, una coda di priorità non sarebbe migliore? Se ci sono k locker disponibili nella coda di priorità, iterando su tutti loro verranno effettuati k passaggi. Inoltre, a seconda dell'implementazione della coda di priorità, potrebbe essere necessario ricostruire la coda di priorità mentre la si guarda tutto .. che richiederebbe i passaggi di k * log (k): (k <1000). Nella soluzione di array, devi solo iterare un array di 1000 elementi e verificare quali sono aperti. Puoi anche aggiungere un elenco disponibile o usato all'implementazione per archiviare solo k time.


1
Bella risposta! Vorrei anche aggiungere che dovresti davvero essere sicuro di usare le funzioni / strutture di dati predefinite del linguaggio che stai usando, ad esempio algoritmo e strutture di dati stl in C ++ o l'API Java per Java.
marktani,

1
Eccellente! Soprattutto "Le espressioni regolari possono risolvere molti problemi, ma non possono essere utilizzate per analizzare l'HTML."
FrustratedWithFormsDesigner

2
La risposta è stata buona, fino a quando è apparso il "problema". Non vi è alcun motivo per utilizzare una coda prioritaria o una tabella hash. Uno stack semplice è sufficiente. Aggiungi iterazione per ottenere l'elenco completo degli armadietti gratuiti, se lo desideri.
Matthieu M.,

1
dovremmo aggiungere database relazionale + SQL, conoscenza dell'albero B +, teoria dei compilatori, organizzazione dell'hardware delle conoscenze, conoscenza della teoria dei sistemi operativi, conoscenza delle reti TCP / IP?
dan_l

1
Sono scettico sui motivi di design. Molti sono utili in alcuni tipi di lingue mentre inutili e / o non necessari in altri. Potresti anche voler aggiungere l'euristica negli algoritmi e le strutture di dati trie e skip-list. Gli algoritmi / strutture di dati tradizionali raggiungono un limite di accesso sincrono ma possono essere battuti da altri approcci non tradizionali utilizzando più thread e concorrenza. L'euristica può ridurre drasticamente il numero di ricerche necessarie mentre strutture come un elenco di salto consentiranno di scrivere la struttura dei dati senza un blocco globale.
Evan Plaice,

6

L'Algorithm Design Manual di Steven S. Skiena sembra la fonte che stai cercando. La seconda parte è un elenco classificato di problemi con una revisione dei relativi algoritmi. C'è una versione web .


3
ottimo libro, ma non senti di dover dominare tutto per essere davvero un programmatore. L'ho appena comprato di recente e sono stato pagato per programmare dal 1979. (E sì, l'ho comprato credendo di poter imparare qualcosa da esso.)
Kate Gregory,

@KateGregory Ho comprato il libro e non sono riuscito a capirlo perché conosco solo linguaggi di alto livello come Ruby e Javascript (no alberi binari, liste collegate, ecc.) Alla fine ho rinunciato a leggerlo.
bigpotato

4

Non c'è "dovrebbe". A. Conosci le classi di complessità di base (lineare, logaritmica, ecc.) B. Comprendi che puoi fare qualsiasi cosa con un semplice array, come puoi con una struttura di dati elaborata come un B-tree. Il trucco nella scelta della struttura / algoritmo appropriato consiste nel bilanciare prestazioni, dimensioni di input attese e complessità di implementazione.

Poi ci sono cose astratte ma immensamente utili (sebbene l'utilità non sia immediatamente ovvia): macchine a stati, teoria dei grafi, teoria della convessità (programmazione lineare, ecc.).


1
Non sottovalutare l'importanza di sapere quando usare cosa. Perché quei problemi che hai risolto usando un semplice array torneranno indietro e ti morderanno proprio quando stai per avvolgerti in quel grande client e scoprire che la tua applicazione che ha funzionato bene per anni rallenta a una ricerca per indicizzazione solo perché hai usato unortice invece di un quicksort.
Pieter B,

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.