Perché le scuole insegnano le matrici su List? [chiuso]


36

La maggior parte degli incarichi nella mia scuola per le lezioni di programmazione iniziale mi richiedevano di usare gli array. Lavoro a tempo pieno ora e non ho mai usato un array per nessun progetto a cui ho lavorato. Anche nei progetti esistenti non ho mai visto l'uso di array da nessuna parte. Secondo me, l' elenco è più facile da usare ed è uno standard. Perché i professori dicono agli studenti di usare le matrici nei loro compiti? È solo così che gli studenti capiscono le basi?

Poiché la maggior parte delle università insegna Java, questa domanda è specifica per Java.


7
Le matrici sono più fondamentali.
user253751

I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Ingegnere mondiale

Risposte:


120

Poiché gli array insegnano concetti come indicizzazione e limiti, due concetti di fondamentale importanza nella programmazione informatica.

Gli elenchi non sono uno "standard". Esiste un'ampia varietà di spazi problematici per i quali gli array si adattano perfettamente.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Ingegnere mondiale

48

Probabilmente volevano iniziare con la struttura dei dati che rappresenta in modo più accurato il funzionamento di un computer, quindi hai familiarità con i fondamenti prima che inizino a introdurre astrazioni di livello superiore come gli elenchi che semplificano il lavoro. Altrimenti non avresti modo di capire perché una certa struttura o algoritmo è lento / veloce per alcune operazioni e non altre; se la memoria del computer fosse effettivamente composta da elenchi collegati, il mondo sarebbe un posto molto diverso.

Per lo stesso motivo, la mia prima lezione di programmazione al college era in C, e il resto delle lezioni erano tutte in C ++, Java e altri linguaggi. Non è che C sia in qualche modo migliore o più facile, è che C (e Array) non ti nascondono nulla.


7
Un elenco è più facile da lavorare con il codice reale, ma un array è più facile da comprendere (completamente) e più importante da capire poiché sono fondamentali e universali, mentre l'elenco (Java) non lo è. Almeno questa è la mia opinione.
Ixrec,

21
Un compito in cui si memorizzano elementi in un array e si accede in un secondo momento è un compito di struttura dei dati . Potresti non averlo capito. Devi chiederti, cosa produce ingegneri migliori, capire i modelli computazionali di base o apprendere la libreria standard di una lingua? Il consenso generale (e sono d'accordo, prima) è che non capirai molto dei contenuti della biblioteca senza prima capire le basi del calcolo.
Kent A.

12
LinkedList, ArrayList, OrderedList, ecc. Quale elenco dovresti imparare per primo? Come apprezzeresti quello che fanno per te se non capissi perché esistono in primo luogo?
Kent A.

10
+1 a @KentAnderson. Le scuole devono produrre ingegneri che comprendano strutture di dati a basso livello; idealmente, la produzione di ingegneri che possono facilmente implementare le strutture di base in C. Qualsiasi altro programma è semplicemente una JavaSchool.
Christian Willman,

2
"Probabilmente volevano iniziare con la struttura di dati che rappresenta in modo più accurato il funzionamento di un computer" - Allora, che dire dei computer con memoria strutturata in elenchi o strutturata per oggetti? "Non è che C sia in qualche modo migliore o più facile, è che C (e Array) non ti nasconde nulla." - A meno che il tuo computer non abbia puntatori, come l'AS / 400, in cui C funziona essenzialmente in una VM e nasconde praticamente tutto per te.
Jörg W Mittag,

21

Le risposte sopra sono fantastiche, ma ne ho un'altra in mente. Il main()metodo Java significa che gli studenti incontrano array di base molto presto, spesso non appena il primo giorno di lezione. Perché?

public static void main(String[] args)

È la prima cosa che dovrai affrontare per scrivere Hello World e oltre. (Ho visto alcuni corsi utilizzare inizialmente insegnare IDE come BlueJ, che ti consentono di puntare e fare clic per eseguire metodi arbitrari, ma li metteremo da parte ...) Mentre potrebbe valere la pena di passare in rassegna alcuni dei queste parole chiave per un po ', prima o poi la maggior parte degli insegnanti vorrà spiegarle. In effetti, una classica domanda di test a livello di principiante è chiedere agli studenti di dare il significato di ogni parola chiave in un programma Hello World di base. E cosa troviamo come parte della nostra firma del metodo principale? Un array (il motivo è in parte storico. ArrayList non esisteva in Java 1.0). Le matrici fanno parte di quel set di conoscenze di base. L'elenco non lo è.

Detto questo, non è raro che le classi introducano ArrayList un po 'più tardi nel corso, specialmente una volta che gli oggetti e il loro uso sono stati coperti. Anche il curriculum AP Computer Science per Java include ArrayList (lo so che era solito fare e Google sembra indicare che lo fa ancora), sebbene ignori il fatto che ArrayList implementa List e il resto del Framework delle collezioni.

Infine, è la mia esperienza che i programmi CS universitari usano Java come mezzo per esplorare CS e concetti di programmazione piuttosto che insegnare agli studenti come diventare buoni sviluppatori Java. Alcuni programmi potrebbero essere più focalizzati sulla creazione di sviluppatori professionisti, mentre altri si concentrano maggiormente sulla teoria, ma in entrambi i casi, c'è molto da imparare su come utilizzare Java in un vero lavoro professionale che non verrà insegnato nella maggior parte dei curricula universitari. Ciò spazia da modelli e tecniche di progettazione come quelli di Effective Java a framework come Spring, Hibernate o JUnit o anche a cose più comuni come JSP o JDBC. Con questa filosofia in mente, enfatizzare le matrici sull'ArrayList più comunemente usato ha un po 'più senso.


3
@Deduplicator sicuro. Semplicemente non era pertinente al mio punto sugli array, quindi l'ho omesso. Inoltre non ho incluso System.out.println ("Hello World!"); o.
Zach Lipton,

+1 per concetti vs. tecniche efficaci per il "mondo reale". Nessuno insegnava nemmeno il controllo della versione, almeno non quando ero a scuola - ma poi sono antico :)
David

Ho preso una classe di sistemi operativi in ​​cui dovevamo implementare vari pezzi come uno scheduler; ci siamo concentrati su uno di questi pezzi alla volta (esclusivamente) perché a quel punto non eravamo in grado di fare di più . Ma pensare a provare a far funzionare tutti quei pezzi allo stesso tempo è stato ciò che mi ha dato (gli inizi di) un apprezzamento delle complessità dello sviluppo del "mondo reale" / "programmazione in generale".
David

14

Uno dei motivi per cui le classi di programmazione del primo anno usano gli array è l'eredità: è così che i professori lo avevano originariamente imparato prima di iniziare a utilizzare le librerie standard con elenchi dinamici inseriti. L'uso dei tipi di dati primitivi è anche più generalmente applicabile: gli array esistono praticamente in qualsiasi computer linguaggio sotto il sole (e può essere implementato in una manciata di istruzioni di montaggio). Quando stavo imparando la programmazione per la prima volta, l'implementazione di un elenco collegato era uno dei compiti.

È molto più facile partire dai primi principi e poi dire "Questa è la struttura di base. Questo linguaggio (o le sue librerie) ti offre questa struttura di dati di alto livello che fa tutto ciò, ma ti dà x, ye z" rispetto a vale a dire "Quindi queste sono queste strutture di dati di alto livello, ora ecco cosa c'è sotto il cofano". Imparare a ragionare sull'opportunità di utilizzare un LinkedList rispetto a un ArrayList (o un HashSet rispetto a un TreeSet) è in genere un corso di algoritmi del secondo o terzo anno. Elenchi e mappe hanno le stesse interfacce e danno gli stessi risultati, ma possono avere comportamenti drammaticamente diversi in un'applicazione di qualsiasi dimensione. E una volta usciti dalla programmazione 101, non vi è alcuna garanzia che la programmazione 102 userà la stessa lingua. Se inizi dal concetto di un array, puoi semplicemente dire "

Un altro motivo per preferire "array" a "Elenco" in un corso introduttivo è che gli array sono fondamentalmente facili da capire: un array di 20 bytesrichiede 20 byte (più una coppia per indicare la fine dell'array o la lunghezza, a seconda dell'implementazione ).

Un "Elenco" è un bollitore di pesce completamente diverso e può essere implementato in molti modi diversi (ArrayList, LinkedList e probabilmente un paio che ho dimenticato), con caratteristiche prestazionali fondamentalmente diverse. Senza capire il coraggio di ciò che le diverse classi List stanno facendo, non si può avere una discussione significativa di quando si dovrebbe usare List foo = new ArrayList()contro List foo = new LinkedList(). Se si tenta di convincere lo studente a utilizzare un'implementazione dell'elenco, qualcuno chiederà perché si sta utilizzando ArrayList invece di una delle altre implementazioni. E "ArrayList" include la parola "Array" ed è supportato da uno, quindi in realtà non è un enorme salto di logica da "array" a "ArrayList".

Contrariamente alla credenza popolare, ci sono situazioni in cui ha senso usare matrici su Elenchi, in particolare quando si ha a che fare con un elenco di dimensioni statiche. Eccone un paio:

  • La ricerca e l'iterazione sono leggermente più veloci perché non si ha a che fare con l'invocazione del metodo: le foo[n]dereferenze e l'aritmetica del puntatore dietro le quinte, mentre si foo.get(n)deve fare la dereferenza, fare l'invocazione di un metodo, fare una seconda dereferenza e quindi forse fare l'aritmetica del puntatore (se stai usando una ArrayList; le liste collegate potrebbero potenzialmente scorrere su ogni elemento dell'elenco).
  • L'inizializzazione è molto più chiara: int[] foo = new int[]{1, 2, 3, 4, 5}rispetto ai suggerimenti in un'altra domanda StackOverflow

Un altro scenario in cui le matrici battono massicciamente le matrici è quando la sequenza in cui gli elementi diventano disponibili corrisponde alla sequenza in cui saranno note le loro posizioni finali, ma non corrisponde alla sequenza finale. Se permè un int[256]detentore di una permutazione, si può facilmente capovolgerla con un array: int[] inv = new int[256]; for (int i=0; i<256; i++) inv[perm[i]]=i; non credo che nulla con cui si possa scrivere ArrayList<>sia altrettanto pulito.
supercat

@supercat Non è proprio un problema con gli array dinamici, ma solo l'implementazione particolare; ArrayListavrebbe potuto facilmente avere un costruttore che crea un elenco inizializzato di default di una certa dimensione.
Doval,

Esistono fonti per il backup dell'affermazione secondo cui un elenco di array deve gestire l'overhead di chiamata del metodo? In teoria lo fa, ma in pratica sarei sorpreso se gete setnon fossi allineato.
Doval,

@Doval: non c'è motivo per cui un linguaggio / framework ben progettato non dovrebbe fornire un tipo di array dinamico che può aggiungere convenientemente elementi fuori sequenza, ma Java non fornisce un tale tipo.
supercat

@Doval: Anche se gete setpuò essere allineato, qualcosa di simile myList.set(23,myList.get(23)+1)non sarà affatto efficiente myArray[23]+=1. Inoltre, anche per i tipi che non necessitano di boxe, sarei molto sorpreso se qualsiasi JITter potesse equivalere a for (i=0; i<1000; i++) myList2.set(i+2000,myList2.get(i+3000));qualcosa in cui le prestazioni sono da qualche parte vicine System.arrayCopy(myArray1,3000,myArray2,2000,1000); Non c'è motivo per cui il tipo di array dinamico di un framework non dovrebbe offrire un'operazione di intervallo di copia veloce, ma Java no.
supercat

7

Java consente di memorizzare variabili di qualsiasi tipo in array. Al contrario, ArrayListconsente solo la memorizzazione di riferimenti. Pertanto, non è possibile discutere utilmente ArrayListsenza prima coprire il modo in cui l'auto-boxing convertirà i primitivi in ​​tipi di riferimento e come l'auto-boxing a volte convertirà i tipi di riferimento in primitivi:

for (int i=10; i<=10000; i*=10)
{
    ArrayList<Integer> l = new ArrayList<Integer>();
    l.add(i);
    l.add(i);
    l.add(l.get(0));
    System.out.print("i=" + i);
    System.out.print(" #0==i:" + (l.get(0)==i));
    System.out.print(" #1==i:" + (l.get(1)==i));
    System.out.print(" #2==i:" + (l.get(2)==i));
    System.out.print(" #0=#1:" + (l.get(0)==l.get(1)));
    System.out.print(" #1=#2:" + (l.get(1)==l.get(2)));
    System.out.println(" #0=#2:" + (l.get(0)==l.get(2)));
}

Se il codice avesse usato un int[3]anziché un ArrayList, non ci sarebbero sorprese. Tutti e tre gli elementi comparerebbero uguali itra loro. Usando ArrayList, tuttavia, anche se tutti e tre gli elementi dell'elenco compareranno sempre uguali ie il primo e il terzo compareranno sempre uguali tra loro, i primi due elementi saranno uguali tra loro solo quando iè 1, 10 o 100, ma (sulla maggior parte delle implementazioni) non quando iè 1000 o 10000.


Potresti spiegare perché # 0 e # 1 saranno uguali quando saranno 1 o 10 o 100? Ho seguito fino a quel punto.
Matteo Leggi il

2
@MatthewRead: la Integerclasse ha una classe nidificata chiamata IntegerCacheche contiene Integeroggetti pre-inizializzati per un intervallo di valori che in genere estende -128..127; l'inscatolamento di un valore al di fuori di tale intervallo richiederà la creazione di un nuovo oggetto, ma l'inscatolamento di un valore all'interno dell'intervallo memorizzato nella cache restituirà semplicemente un riferimento a uno degli oggetti preinizializzati memorizzati IntegerCache.cache. Ogni buon programmatore Java deve essere consapevole del fatto che due Integervariabili di tipo che incapsulano lo stesso valore possono o non possono essere paragonate uguali, ma introdurre quell'idea troppo presto può far fuggire gli studenti nel terrore.
supercat

Eh, non avrei mai immaginato che fosse dovuto a oggetti preinizializzati. Grazie per le informazioni!
Matteo Leggi il

1
@MatthewRead: Vorrei che Java non avesse consentito alcuni tipi di conversione implicita con ==. Data la possibilità che l'auto-unboxing possa lanciare, sarei propenso a non consentirlo del tutto, ma il suo comportamento ==è particolarmente orribile. L' ==operatore si comporta male anche in casi come 16777217==16777216f[riporta vero], e le conversioni implicite long v=Math.Round(123456789), w=Math.Round(123456789012345)sono suscettibili di essere inaspettate [riesci a indovinare cosa produrranno quelle espressioni?]
supercat

Per quanto riguarda IntegerCache, ci sono certamente momenti in cui può aiutare le prestazioni, ma spesso può causare il codice che è semplicemente sbagliato a funzionare in qualche modo. In un certo senso, vorrei che ci fosse una modalità in cui il pugilato avrebbe restituito quasi casualmente oggetti da due cache intere e avrebbe sostituito quasi casualmente gli elementi della cache con quelli nuovi, in modo che il codice basato sul comportamento di boxe dei valori -128..127 sarebbe è improbabile che ci riesca per molto tempo.
supercat

6

Penso che abbia senso insegnare come utilizzare prima gli array a causa del fatto che ArrayListutilizza un array internamente. La ArrayListclasse ha una variabile membro chiamata elementDatache è un Objectarray.

Dal ArrayList codice sorgente JDK :

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer.
 */
private transient Object[] elementData;

Quando aggiungi, aggiorni, recuperi o rimuovi elementi da un ArrayListesso usa questo array interno per fare quelle operazioni. Come ha già sottolineato l' utente Ixrec , ArrayListè solo un'astrazione di livello superiore che in genere è più facile da lavorare.


Ma un array utilizza un puntatore a un blocco di memoria, internamente. Perché iniziare a quel livello specifico di astrazione?

La domanda è taggata come Java- Si stava chiedendo perché insegnare agli array quando in genere si può usare ArrayList. Java non ha puntatori. Giusto o sbagliato, ritengo che C / C ++ sia un linguaggio migliore con cui iniziare gli studenti rispetto a Java. Molti argomenti nella programmazione possono essere meglio compresi conoscendo C / C ++.
Derek W,

3

Supponendo che l'elenco sia davvero più facile da lavorare, come dici tu, non importa. L'apprendimento è più "dal semplice al complesso" che dal "facile al difficile". Se i fondamenti non fossero importanti, l'informatica non sarebbe un campo accademico. Potresti semplicemente imparare a fare clic insieme sulle app usando i framework / le librerie esistenti dai tutorial online. (Certo, qualcuno deve scrivere quelle librerie ... e qualcuno deve implementare ArrayListin primo luogo ....)


In molti casi l'uso ArrayListpuò essere gestito meglio utilizzando un array separato e il conteggio "liveItems", tranne per il fatto che non esiste un modo conveniente per lavorare con l'array e contare insieme se non aggregandoli.
supercat

2

È perché la cosa più cruciale nell'educazione accademica è insegnarti a usare la terminologia corretta per descrivere le cose che fai.

L'elenco è qualcos'altro che array. e non puoi usare java.util.Listin Java perché è un'interfaccia. Di solito si utilizza java.util.ArrayListquale essendo un'implementazione dell'elenco, non è un elenco, ma un wrapper di oggetti attorno all'array dinamico. Quindi dici di usare un 'Elenco' ma usi un array.

È molto ragionevole saltare quel caos terminologico e usare semplicemente gli array per imparare agli studenti cos'è l'array. Se si utilizzano array in Java, almeno si utilizzano array.

Onestamente, è anche l'argomento per cui insegnare la programmazione con Java non è una buona idea. È difficile imparare correttamente i concetti di base della programmazione.


che dire di hashmap? un array è solo un tipo di hashmap, in un certo senso ..
Giovedì

@Thufir come può un array essere una hashmap? Quelle sono strutture di dati completamente diverse.
Danubian Sailor,

puoi rappresentare un array con una hashmap. quale è più "fondamentale"? Direi che l'hashmap è concettualmente più interessante.
Thufir

1
@Thufir no, non puoi. Puoi solo emulare. Internamente ogni struttura di dati sarà quella che è. Quelle sono cose fondamentalmente e concettualmente diverse. Ecco perché è una cattiva idea iniziare a imparare la programmazione con linguaggi così astratti come Java o JavaScript. Qui non è chiaro quali siano realmente le strutture di dati.
Danubian Sailor,

1

Non hai mai visto o usato letteralmente alcun array? Li usiamo sempre, oltre alle liste. Di solito non usiamo Java, ma usiamo molte altre lingue che disegnano ovvie somiglianze.

Tra array e Liste, uno più leggero e, inoltre, più preciso, mentre l'altro ha più funzionalità. Come regola generale nella programmazione, quando ci sono due tipi simili che sono sostanzialmente divisi lungo quelle linee, dovresti scegliere quello più leggero a meno che tu non abbia effettivamente bisogno di quello più elaborato. Oltre a ridurre le spese generali, questo aiuta effettivamente a gestire la quantità di disordine e lo stato nel programma e in particolare il suo codice . Se qualcosa va storto durante il test, hai meno posti in cui cercare; e, soprattutto, nel caso di matrici vs. Elenchi, le persone ottengono una migliore idea dell'ambito limitato di ciò per cui lo si sta effettivamente utilizzando e provando a utilizzarlo.

E sì, da un punto di vista accademico, c'è l'ulteriore motivo di insegnare agli studenti le basi. Tuttavia, questo va un po 'più in profondità. Le matrici e gli elenchi sono un buon esempio di tipi più voluminosi, spesso costruiti solo sopra, e spesso semplicemente avvolgenti, istanze sottostanti dei tipi più leggeri. Anche quando gli Elenchi non hanno array sottostanti, si comportano esternamente come fanno. Una parte dell'insegnamento a qualcuno di cosa sia una Lista sarebbe quella di insegnare loro cos'è una matrice.

Ho potuto vedere questo forse sfuggire di mano in un linguaggio come il C ++, in cui le matrici fondamentalmente non potevano essere più ridotte di loro, ma in linguaggi di livello superiore, sono quasi degli Elenchi. Se soddisfano perfettamente le tue esigenze in una determinata situazione, perché dovresti usare qualcos'altro?


Non direi che un elenco abbia funzionalità "più", tanto quanto ha funzionalità "diverse". Un nuovo T[]sarà pronto, subito fuori dal cancello, per accettare gli oggetti in qualsiasi ordine, mentre è ArrayList<T>necessario che gli articoli vengano aggiunti, in ordine, prima che possano essere modificati. A T[]può copiare un intervallo arbitrario di articoli in un intervallo di dimensioni simili di un altro T[]relativamente rapidamente, mentre ArrayList<T>richiederebbe la lettura individuale degli elementi da un elenco e la loro memorizzazione nell'altro - molto più lento e meno conveniente.
supercat
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.