¿No se puede crear una matriz de LinkedLists en Java…?

102

Estoy trabajando en una clase de matriz dispersa que necesita usar una matriz de LinkedListpara almacenar los valores de una matriz. Cada elemento de la matriz (es decir, cada uno LinkedList) representa una fila de la matriz. Y cada elemento de la LinkedListmatriz representa una columna y el valor almacenado.

En mi clase, tengo una declaración de la matriz como:

private LinkedList<IntegerNode>[] myMatrix;

Y, en mi constructor para SparseMatrix, trato de definir:

myMatrix = new LinkedList<IntegerNode>[numRows];

El error que termino recibiendo es

No se puede crear una matriz genérica de LinkedList<IntegerNode>.

Entonces, tengo dos problemas con esto:

  1. ¿Qué estoy haciendo mal y
  2. ¿Por qué el tipo es aceptable en la declaración de la matriz si no se puede crear?

IntegerNodees una clase que he creado. Y todos mis archivos de clase están empaquetados juntos.

kafuchau
fuente

Respuestas:

64

No puede utilizar la creación de matrices genéricas. Es una falla / característica de los genéricos de Java.

Las formas sin advertencias son:

  1. Usando la lista de listas en lugar de la matriz de listas:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
  2. Declarando la clase especial para Array of Lists:

    class IntegerNodeList {
        private final List< IntegerNode > nodes;
    }
Sergey
fuente
19
Una mejor alternativa a la última solución sería: class IntegerNodeList extends List<IntegerNode> {}
kamasheto
Esta implementación es tremendamente lenta. Obtener el elemento [1000] [2000] (nodeLists.get (1000) .get (2000)) hará que LinkedList se repita 3000 veces. Evite LinkedList si alguien puede estar indexando en él. ArrayList indexará más rápido, pero la solución de Fredrik es mejor en general.
Steve Zobell
142

Por alguna razón, debe lanzar el tipo y hacer la declaración de esta manera:

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList<?>[numRows];
Fredrik
fuente
Investigué un problema similar y leí que el elenco anterior es un 'truco' muy común que se usa en todo el marco de colecciones.
luke
15
En mi opinión, esta debería ser la respuesta seleccionada. No he experimentado, pero tengo el presentimiento de que el método # 2 de Sergey crea bastante sobrecarga; y soy POSITIVO de que el # 1 lo hace. Una lista no es tan eficiente como una matriz de varias formas que no detallaré aquí, pero HE hecho experimentos y he visto grandes ralentizaciones al usar listas en comparación con las matrices. Es más rápido simplemente administrar sus propias matrices y reasignarlas, que agregar cosas a una lista.
Ricket
@Ricket Estoy de acuerdo, tomado de ibm.com/developerworks/java/library/j-jtp01255/index.html
Peteter
4
Todavía recibo una advertencia de "Seguridad de tipo: elenco sin marcar". La solución de Bob me parece la más limpia.
Marco Lackovic
3
En JDK 7, lo anterior da una advertencia de tipos sin formato. Eso se puede arreglar usando el tipo ilimitado <?>, Pero aún recibe una advertencia sin marcar (que se puede suprimir). p. ej., <code> myMatrix = (LinkedList <IntegerNode> []) new LinkedList <?> [numRows]; </code>
Neon
5

Aparte de los problemas de sintaxis, me parece extraño usar una matriz y una lista vinculada para representar una matriz. Para poder acceder a celdas arbitrarias de la matriz, probablemente desee una matriz real o al menos una ArrayListpara contener las filas, ya que LinkedListdebe atravesar toda la lista desde el primer elemento hasta cualquier elemento en particular, una O(n)operación, a diferencia de mucho más rápido O(1)con ArrayListuna matriz real.

Sin embargo, dado que mencionó que esta matriz es escasa, quizás una mejor manera de almacenar los datos es como un mapa de mapas, donde una clave en el primer mapa representa un índice de fila, y su valor es un mapa de fila cuyas claves son un índice de columna , siendo el valor su clase IntegerNode. Así:

private Map<Integer, Map<Integer, IntegerNode>> myMatrix = new HashMap<Integer, Map<Integer, IntegerNode>>();

// access a matrix cell:
int rowIdx = 100;
int colIdx = 30;
Map<Integer, IntegerNode> row = myMatrix.get(rowIdx); // if null, create and add to matrix
IntegerNode node = row.get(colIdx); // possibly null

Si necesita poder atravesar la matriz fila por fila, puede hacer que el mapa de filas sea de tipo a TreeMap, y lo mismo para atravesar las columnas en orden de índice, pero si no necesita esos casos, HashMapes más rápido que TreeMap. Los métodos auxiliares para obtener y establecer una celda arbitraria, manejando valores nulos no establecidos, serían útiles, por supuesto.

Dov Wasserman
fuente
4
class IntegerNodeList extends LinkedList<IntegerNode> {}

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 
Beto
fuente
Te perdiste los genéricos de LinkedList.
Peter Wippermann
3

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList[numRows];

La transmisión de esta manera funciona, pero aún te deja con una advertencia desagradable:

"Seguridad de tipos: la expresión de tipo Lista [] necesita una conversión sin marcar ..."

Declarando una clase especial para Array of Lists:

class IntegerNodeList { private final List< IntegerNode > nodes; }

es una idea inteligente para evitar la advertencia. tal vez sea un poco mejor usar una interfaz para ello:

public interface IntegerNodeList extends List<IntegerNode> {}

luego

List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];

compila sin advertencias.

no se ve tan mal, ¿verdad?

user306708
fuente
IntegerNodeList: ¿con qué clase usarías esto? Por ejemplo, no podría asignarle un ArrayList <IntegerNode>. También necesitaría extender ArrayList ...
Hans-Peter Störr
no es necesario utilizar la interfaz IntegerNodeList fuera de la inicialización de la matriz: List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; for (int i = 0; i <myMatrix.length; i ++) {myMatrix [i] = new ArrayList <IntegerNode> (); }
user306708
1
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];Esto tiene un problema sutil pero importante. Puede solamente poner IntegerNodeListen la matriz. myMatrix[i] = new ArrayList<IntegerNode>();arrojará ArrayStoreException.
Radiodef
2
List<String>[] lst = new List[2];
lst[0] = new LinkedList<String>();
lst[1] = new LinkedList<String>();

No hay advertencias. NetBeans 6.9.1, jdk1.6.0_24

Andrii
fuente
1
Es cierto que no hay advertencias, pero con Java SE 6 Update 32 de Oracle obtengo el error de compilación "La lista de tipos no es genérica; no se puede parametrizar con argumentos <String>". La eliminación del argumento <String> genera otro error "No coinciden los tipos: no se puede convertir de LinkedList <String> a List".
Marco Lackovic
0

Si hago lo siguiente, aparece el mensaje de error en cuestión.

LinkedList<Node>[] matrix = new LinkedList<Node>[5];

Pero si elimino el tipo de lista en la declaración, parece tener la funcionalidad deseada.

LinkedList<Node>[] matrix = new LinkedList[5];

¿Son estas dos declaraciones drásticamente diferentes de una manera que no conozco?

EDITAR

Ah, creo que me he encontrado con este problema ahora.

Iterar sobre la matriz e inicializar las listas en un bucle for parece funcionar. Aunque no es tan ideal como algunas de las otras soluciones que se ofrecen.

for(int i=0; i < matrix.length; i++){

    matrix[i] = new LinkedList<>();
}
Ryan
fuente
0

Necesita una matriz de List, una alternativa es probar:

private IntegerNode[] node_array = new IntegerNode[sizeOfYourChoice];

Luego node_array[i]almacena el nodo principal (primer) de un ArrayList<IntegerNode>o LinkedList<IntegerNode>(cualquiera que sea su implementación de lista favorita).

Bajo este diseño, pierde el método de acceso aleatorio list.get(index), pero luego aún puede recorrer la lista comenzando con el almacén de nodos de cabeza / puño en la matriz de tipo seguro.

Esta podría ser una opción de diseño aceptable según su caso de uso. Por ejemplo, utilizo este diseño para representar una lista de adyacencia de gráfico, en la mayoría de los casos de uso, requiere atravesar la lista de adyacencia de todos modos para un vértice dado en lugar de acceder aleatoriamente a algún vértice de la lista.

Yiling
fuente