¿Por qué las escuelas enseñan matrices sobre List? [cerrado]

36

La mayoría de las tareas en mi escuela para las clases de programación inicial me obligaban a usar matrices. Ahora trabajo a tiempo completo y nunca utilicé una matriz para ningún proyecto en el que he trabajado. Incluso en los proyectos existentes, nunca vi el uso de matrices en ningún lado. En mi opinión, List es más fácil de usar y es un estándar. ¿Por qué los profesores les dicen a los estudiantes que usen matrices en sus tareas? ¿Es solo para que los estudiantes entiendan los conceptos básicos?

Como la mayoría de las universidades enseñan Java, esta pregunta es específica de Java.

Aullidos Hagrid
fuente
77
Las matrices son más fundamentales.
user253751
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Ingeniero mundial

Respuestas:

120

Debido a que las matrices enseñan conceptos como indexación y límites, dos conceptos fundamentalmente importantes en la programación de computadoras.

Las listas no son un "estándar". Existe una amplia variedad de espacios problemáticos para los cuales las matrices son perfectas.

Robert Harvey
fuente
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Ingeniero mundial
48

Probablemente querían comenzar con la estructura de datos que representa con mayor precisión cómo funciona una computadora, por lo que está familiarizado con los fundamentos antes de que comiencen a introducir abstracciones de nivel superior como Listas que hacen que sea más fácil trabajar con ellas. De lo contrario, no tendría forma de entender por qué una determinada estructura o algoritmo es lento / rápido para algunas operaciones y no para otras; Si la memoria de la computadora estuviera hecha de listas enlazadas, el mundo sería un lugar muy diferente.

Por la misma razón, mi primera clase de programación en la universidad fue en C, y el resto de las clases fueron todas en C ++, Java y otros lenguajes. No es que C sea de alguna manera mejor o más fácil, es que C (y Array) no te oculta nada.

Ixrec
fuente
77
Es más fácil trabajar con una lista en código real, pero una matriz es más fácil de entender (completamente) y más importante de entender ya que son fundamentales y universales, mientras que la Lista (de Java) no lo es. Al menos esa es mi opinión.
Ixrec
21
Una asignación en la que almacena cosas en una matriz y accede a ellas más tarde es una asignación de estructura de datos . Puede que no te hayas dado cuenta. Tiene que preguntarse, ¿qué produce mejores ingenieros, comprender los modelos computacionales básicos o aprender la biblioteca estándar de un idioma? El consenso general (y estoy de acuerdo, fwiw) es que no comprenderá gran parte del contenido de la biblioteca sin comprender primero los conceptos básicos de la computación.
Kent A.
12
LinkedList, ArrayList, OrderedList, etc. ¿Qué lista debe aprender primero? ¿Cómo agradecería lo que hacen por usted si no entiende por qué existen en primer lugar?
Kent A.
10
+1 a @KentAnderson. Las escuelas deben producir ingenieros que entiendan las estructuras de datos a un nivel bajo; idealmente, producir ingenieros que puedan implementar fácilmente las estructuras básicas en C. Cualquier otro programa es simplemente una JavaSchool.
Christian Willman
2
"Probablemente quisieron comenzar con la estructura de datos que representa con mayor precisión cómo funciona una computadora". Entonces, ¿qué pasa con las computadoras con memoria estructurada en listas o estructurada en objetos? "No es que C sea de alguna manera mejor o más fácil, es que C (y Array) no te oculta nada". - A menos que su computadora no tenga punteros, como el AS / 400, donde C esencialmente se ejecuta en una VM y oculta casi todo para usted.
Jörg W Mittag
21

Las respuestas anteriores son geniales, pero tengo otra en mente. El main()método de Java significa que los estudiantes encuentran matrices básicas muy temprano, a menudo tan pronto como el primer día de clase. ¿Por qué?

public static void main(String[] args)

Es lo primero con lo que tendrás que lidiar para escribir Hello World y más allá. (Al principio, he visto que algunos cursos usan IDE de enseñanza como BlueJ, que le permiten señalar y hacer clic para ejecutar métodos arbitrarios, pero los dejaremos de lado ...) Si bien puede valer la pena pasar por alto algunos de Estas palabras clave por un tiempo, tarde o temprano, la mayoría de los maestros querrán explicarlas. De hecho, una pregunta clásica de prueba de nivel de principiante es pedirles a los estudiantes que den el significado de cada palabra clave en un programa básico de Hello World. ¿Y qué encontramos como parte de nuestra firma de método principal? Una matriz (la razón de esto es, en parte, histórica. ArrayList no existía en Java 1.0). Las matrices son parte de ese conjunto básico de conocimientos. La lista no lo es.

Dicho esto, no es raro que las clases presenten ArrayList un poco más tarde en el curso, especialmente una vez que los objetos y su uso han sido cubiertos. Incluso el plan de estudios AP Computer Science para Java incluye ArrayList (lo sé, y Google parece indicar que todavía lo hace), aunque ignora el hecho de que ArrayList implementa List y el resto del Framework de colecciones.

Finalmente, según mi experiencia, los programas universitarios de CS usan Java como un medio para explorar CS y conceptos de programación en lugar de enseñar a los estudiantes cómo convertirse en buenos desarrolladores de Java. Algunos programas pueden estar más centrados en producir desarrolladores profesionales, mientras que otros se centran más en la teoría, pero en cualquier caso, hay mucho que aprender sobre cómo usar Java en el trabajo profesional real que no se enseñará en la mayoría de los planes de estudio universitarios. Esto abarca desde patrones de diseño y técnicas como las de Java efectivo hasta marcos como Spring, Hibernate o JUnit, o incluso cosas más comunes como JSP o JDBC. Con esa filosofía en mente, enfatizar las matrices sobre la ArrayList más utilizada tiene un poco más de sentido.

Zach Lipton
fuente
3
@Deduplicator seguro. Simplemente no era relevante para mi punto sobre las matrices, así que lo omití. Tampoco incluí System.out.println ("Hello World!"); ya sea.
Zach Lipton
+1 para conceptos versus técnicas efectivas para el "mundo real". Nadie estaba enseñando el control de versiones tampoco, al menos no cuando estaba en la escuela, pero luego soy antiguo :)
David
Tomé una clase de sistemas operativos donde tuvimos que implementar varias piezas como un planificador; nos centramos en una de esas piezas a la vez (exclusivamente) porque en ese momento no éramos capaces de hacer más . Pero pensar en tratar de hacer que todas esas piezas funcionen al mismo tiempo fue lo que me dio (el comienzo de) una apreciación de las complejidades del desarrollo del "mundo real" / "programación en general".
David
14

Una de las razones por las que las clases de programación de primer año usan matrices es heredada: así es como los profesores lo aprendieron originalmente antes de comenzar a usar bibliotecas estándar con listas dinámicas integradas. El uso de los tipos de datos primitivos también es aplicable de manera más general: las matrices existen en casi cualquier computadora lenguaje bajo el sol (y se puede implementar en un puñado de instrucciones de montaje). Cuando estaba aprendiendo programación, la implementación de una lista vinculada era una de las tareas.

Es mucho más fácil comenzar desde los primeros principios y luego decir "Esa es la estructura básica. Este lenguaje (o sus bibliotecas) le brinda esta estructura de datos de alto nivel que hace todo eso, pero le da x, y y z", que es decir "Así que estas son estructuras de datos de alto nivel, ahora esto es lo que hay debajo del capó". Aprender a razonar acerca de si usar LinkedList o ArrayList (o HashSet vs. un TreeSet) suele ser un curso de Algoritmos de segundo o tercer año. Las listas y los mapas tienen las mismas interfaces y dan los mismos resultados, pero pueden tener comportamientos dramáticamente diferentes en una aplicación de cualquier tamaño. Y una vez que salga de la Programación 101, no hay garantía de que la Programación 102 usará el mismo lenguaje. Si parte del concepto de una matriz, simplemente puede decir "

Otra razón para preferir "matriz" en lugar de "Lista" en un curso introductorio es que las matrices son fundamentalmente fáciles de entender: una matriz de 20 bytesocupa 20 bytes (más un par para indicar el final de la matriz o la longitud, dependiendo de la implementación )

Una "Lista" es un hervidor de pescado completamente diferente y se puede implementar de muchas maneras diferentes (ArrayList, LinkedList y probablemente una pareja que he olvidado), con características de rendimiento fundamentalmente diferentes. Sin la comprensión de las entrañas de lo que las diferentes clases de lista están haciendo, no se puede tener una discusión significativa de cuándo se debe utilizar List foo = new ArrayList()vs List foo = new LinkedList(). Si intenta que el alumno use una implementación de Lista, alguien le preguntará por qué está usando ArrayList en lugar de una de las otras implementaciones. Y "ArrayList" incluye la palabra "Array" y está respaldado por uno, por lo que realmente no es un gran salto lógico de "array" a "ArrayList".

Contrariamente a la creencia popular, hay situaciones en las que tiene sentido usar matrices sobre listas, particularmente cuando se trata de una lista de tamaño estático. Aquí hay una pareja:

  • La búsqueda y la iteración son un poco más rápidas porque no se trata de la sobrecarga de la invocación de métodos: foo[n]desreferencia y hace algo de aritmética de puntero detrás de escena, mientras que foo.get(n)tiene que desreferenciar, hacer una invocación de método, hacer una segunda desreferencia y quizás hacer aritmética de puntero (si está utilizando una ArrayList; LinkedLists potencialmente necesita iterar sobre cada elemento de la Lista).
  • La inicialización es mucho más limpia: int[] foo = new int[]{1, 2, 3, 4, 5}frente a las sugerencias en otra pregunta de StackOverflow
Carl C.
fuente
Otro escenario en el que las matrices vencen masivamente a las matrices es cuando la secuencia en la que los elementos están disponibles coincide con la secuencia en la que se conocerán sus posiciones finales, pero no coincide con la secuencia final. Si se permtrata de una int[256]permutación, se puede invertir fácilmente con una matriz: int[] inv = new int[256]; for (int i=0; i<256; i++) inv[perm[i]]=i; no creo que nada con lo que se pueda escribir ArrayList<>sea ​​tan limpio.
supercat
@supercat Eso no es realmente un problema con las matrices dinámicas, solo la implementación particular; ArrayListfácilmente podría haber recibido un constructor que crea una lista inicializada por defecto de cierto tamaño.
Doval
¿Tiene fuentes para respaldar la afirmación de que una lista de matriz tiene que lidiar con la sobrecarga de invocación de métodos? En teoría sí, pero en la práctica me sorprendería si gety setno obtener inline.
Doval
@Doval: No hay razón para que un lenguaje / marco bien diseñado no proporcione un tipo de matriz dinámica que pueda agregar elementos fuera de secuencia, pero Java no proporciona ese tipo.
supercat
@Doval: Incluso si gety setpueden estar en forrado, algo así como myList.set(23,myList.get(23)+1)será ni mucho menos tan eficiente como myArray[23]+=1. Además, incluso para los tipos que no necesitarían boxeo, me sorprendería mucho si cualquier JITter pudiera hacer algo equivalente a for (i=0; i<1000; i++) myList2.set(i+2000,myList2.get(i+3000));algo cuyo rendimiento esté cerca. System.arrayCopy(myArray1,3000,myArray2,2000,1000); No hay razón para que el tipo de matriz dinámica de un marco no ofrezca una operación rápida de rango de copia, pero Java no.
supercat
7

Java permite que las variables de cualquier tipo se almacenen en matrices. Por el contrario, ArrayListsolo permite el almacenamiento de referencias. Por lo tanto, no se puede discutir útilmente ArrayListsin primero cubrir cómo el auto-boxing convertirá primitivas en tipos de referencia, y cómo el auto-desempaquetado a veces convertirá tipos de referencia en primitivas:

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)));
}

Si el código hubiera utilizado un en int[3]lugar de un ArrayList, no habría sorpresas. Los tres elementos se compararían ientre sí. El uso ArrayList, sin embargo, a pesar de que los tres elementos de la lista siempre se compararán igual a i, y la primera y la tercera siempre compararán iguales entre sí, los dos primeros elementos sólo serán iguales entre sí cuando ies de 1, 10 o 100, pero (en la mayoría de las implementaciones) no cuando ies 1000 o 10000.

Super gato
fuente
¿Podría explicar por qué # 0 y # 1 serán iguales cuando son 1 o 10 o 100? Seguí hasta ese punto.
Mateo leyó el
2
@MatthewRead: la Integerclase tiene una clase anidada llamada IntegerCacheque contiene Integerobjetos preinicializados para un rango de valores que generalmente se extiende -128..127; boxear un valor fuera de ese rango requerirá crear un nuevo objeto, pero boxear un valor dentro del rango en caché simplemente devolverá una referencia a uno de los objetos preinicializados almacenados IntegerCache.cache. Cualquier buen programador de Java debe ser consciente de que las Integervariables de dos tipos que encapsulan el mismo valor pueden o no ser iguales, pero introducir esa idea demasiado pronto puede hacer que los estudiantes huyan aterrorizados.
supercat
Huh, nunca habría adivinado que se debía a objetos preinitalizados. Gracias por la info!
Mateo leyó el
1
@MatthewRead: Deseo de Java había anulado ciertos tipos de conversión implícita con ==. Dada la posibilidad de que el desempaquetado automático pueda arrojarse, me inclinaría a no permitirlo por completo, pero su comportamiento ==es especialmente horrible. El ==operador también se comporta mal en casos como 16777217==16777216f[informes verdaderos], y las conversiones implícitas para long v=Math.Round(123456789), w=Math.Round(123456789012345)pueden ser inesperadas [¿puedes adivinar qué producirán esas expresiones?]
supercat
En cuanto a IntegerCache, ciertamente hay momentos en que puede ayudar al rendimiento, pero con frecuencia puede causar que el código que es simplemente incorrecto funcione de alguna manera. De alguna manera, desearía que hubiera un modo en el que el boxeo devolviera de forma cuasialeatoria los objetos de dos cachés de números enteros y reemplazara de forma cuasialeatoria los elementos de la caché por otros nuevos, de modo que el código basado en el comportamiento del boxeo de los valores -128..127 fuera Es poco probable que tenga éxito por mucho tiempo.
supercat
6

Creo que tiene sentido enseñar cómo usar matrices primero debido al hecho de que ArrayListusa una matriz internamente. La ArrayListclase tiene una variable miembro llamada elementDataque es una Objectmatriz.

Del ArrayList código fuente 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;

Cuando agrega, actualiza, recupera o elimina elementos de un ArrayList, utiliza esta matriz interna para realizar esas operaciones. Como el usuario Ixrec ya ha señalado, ArrayListes solo una abstracción de nivel superior con la que generalmente es más fácil trabajar.

Derek W
fuente
Pero una matriz usa un puntero a un bloque de memoria, internamente. ¿Por qué comenzar en ese nivel específico de abstracción?
La pregunta está etiquetada como Java: preguntaba por qué enseñar matrices cuando normalmente se puede usar ArrayList. Java no tiene punteros. Bien o mal, considero que C / C ++ es un mejor lenguaje para comenzar con los estudiantes que Java. Muchos temas de programación se pueden entender mejor al tener conocimiento de C / C ++.
Derek W
3

Asumir que esa lista es realmente más fácil de trabajar, como usted dice, eso realmente no importa. El aprendizaje se trata más de "básico a complejo" que de "fácil a difícil". Si los fundamentos no fueran importantes, entonces la informática no sería un campo académico. Podrías aprender cómo hacer clic en aplicaciones usando los marcos / bibliotecas existentes de los tutoriales en línea. (Por supuesto, alguien tiene que escribir esas bibliotecas ... y alguien tiene que implementar ArrayListen primer lugar ...)

Matthew Read
fuente
En muchos casos, ese uso ArrayListpodría manejarse mejor mediante el uso de una matriz separada y el recuento "liveItems", excepto que no hay una manera conveniente de trabajar con la matriz y contar juntos, excepto agregándolos.
supercat
2

Es porque lo más crucial en la educación académica es enseñarte a usar la terminología correcta para describir las cosas que haces.

La lista es otra cosa que la matriz. y no se puede usar java.util.Listen Java porque es una interfaz. Usualmente, lo java.util.ArrayListque es una implementación de Lista, no es una lista, sino un contenedor de objetos alrededor de una matriz dinámica. Entonces dice que usa una 'Lista' pero usa una matriz.

Es muy razonable saltear ese caos terminológico y simplemente usar matrices para aprender de los estudiantes qué es la matriz. Si usa matrices en Java, al menos usa matrices.

Honestamente, también es el argumento por qué enseñar programación con Java no es una buena idea. Es difícil aprender los conceptos básicos de programación correctamente.

Marinero danubiano
fuente
¿Qué hay de hashmap? una matriz es solo un tipo de hashmap, en cierto modo ..
Thufir
@Thufir, ¿cómo puede una matriz ser un hashmap? Esas son estructuras de datos completamente diferentes.
Danubian Sailor
puedes representar una matriz con un hashmap. ¿Cuál es más "fundamental"? Yo diría que el hashmap es más interesante conceptualmente.
Thufir
1
@Thufir no, no puedes. Solo puedes emular. Internamente cada estructura de datos será lo que es. Esas son cosas fundamental y conceptualmente diferentes. Es por eso que es una mala idea comenzar a aprender programación con lenguajes tan abstractos como Java o JavaScript. Allí no está claro cuáles son realmente las estructuras de datos.
Danubian Sailor
1

¿Literalmente nunca has visto o usado ninguna matriz? Los usamos todo el tiempo, además de las listas. Usualmente no usamos Java, pero usamos muchos otros lenguajes que dibujan similitudes obvias.

Entre las matrices y las listas, uno es más liviano y, además, más preciso, mientras que el otro tiene más funcionalidad. Como regla general en la programación, cuando hay dos tipos similares que se dividen básicamente en esas líneas, debe optar por el más liviano a menos que realmente necesite el más elegante. Además de reducir los gastos generales, esto realmente ayuda a controlar la cantidad de desorden y estado en el programa y, en particular, su código . Si algo sale mal durante la prueba, tiene menos lugares para buscar; y, lo que es más importante, en el caso de las matrices frente a las listas, las personas tienen una mejor idea del alcance limitado de lo que realmente están utilizando y de lo que intentan hacer con él.

Y sí, desde un punto de vista académico, existe la razón adicional de enseñar a los estudiantes los conceptos básicos. Sin embargo, esto va un poco más profundo. Las matrices y las listas son un buen ejemplo de tipos más voluminosos que a menudo se están construyendo sobre, y con frecuencia simplemente envolviendo, instancias subyacentes de los tipos más livianos. Incluso cuando las listas no tienen matrices subyacentes, se comportan externamente como lo hacen. Una parte de enseñarle a alguien qué es una Lista sería enseñarle qué es una matriz.

Pude ver que esto quizás se salga de control en un lenguaje como C ++, donde las matrices básicamente no podrían ser más simples de lo que son, pero en lenguajes de nivel superior, son casi Listas en sí mismas. Si se ajustan perfectamente a sus necesidades en una situación dada, ¿por qué necesitaría usar otra cosa?

Panzercrisis
fuente
No diría que una lista tiene "más" funcionalidad, tanto como tiene una funcionalidad "diferente". Un nuevo T[]estará listo, desde el inicio, para aceptar artículos en cualquier orden, mientras que uno ArrayList<T>requiere que los artículos se agreguen, en orden, antes de que puedan modificarse. A T[]puede copiar un rango arbitrario de elementos en un rango de tamaño similar de otro con T[]relativa rapidez, mientras ArrayList<T>que requeriría leer elementos individualmente de una lista y almacenarlos en el otro, mucho más lento y menos conveniente.
supercat