2008-10-19 16 views
96

Sto lavorando su una classe di matrice sparsa che richiede per utilizzare un array di LinkedList per memorizzare i valori di una matrice. Ogni elemento dell'array (ad esempio, ogni LinkedList) rappresenta una riga della matrice. Inoltre, ogni elemento nell'array LinkedList rappresenta una colonna e il valore memorizzato.Non è possibile creare un array di LinkedList in Java ...?

Nella mia classe, ho una dichiarazione della matrice come:

private LinkedList<IntegerNode>[] myMatrix; 

E, a mio costruttore per la SparseMatrix, cerco di definire:

myMatrix = new LinkedList<IntegerNode>[numRows]; 

L'errore finisco ottenere è

Impossibile creare un array generico di LinkedList<IntegerNode>.

Così, ho due problemi con questo:

  1. Che cosa sto facendo di sbagliato, e
  2. Perché il tipo accettabile nella dichiarazione per la matrice, se non può essere creato?

IntegerNode è una classe che ho creato. E tutti i miei file di classe sono raggruppati insieme.

risposta

63

Non è possibile utilizzare la creazione di un array generico. È un difetto/caratteristica dei generici java.

Le vie senza avvisi sono:

  1. Utilizzando lista di liste, invece di array di liste:

    List< List<IntegerNode>> nodeLists = new LinkedList< List<IntegerNode>>(); 
    
  2. dichiarare la classe speciale per Array di Liste:

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

Una migliore alternativa a quest'ultima soluzione sarebbe quella di: classe 'IntegerNodeList estende Lista {}' – kamasheto

+5

quanto sopra avrebbe dovuto essere l'implementazione di List cioè estende ArrayList .... – Dori

+0

Questa implementazione è scandalosamente lenta. Ottenere l'elemento [1000] [2000] (nodeLists.get (1000) .get (2000)) renderà LinkedList iterare 3000 volte! Evita LinkedList se qualcuno può indicizzarti. ArrayList indicizzerà più rapidamente, ma la soluzione di Fredrik è complessivamente migliore. –

133

Per qualche ragione si deve lanciare il tipo e fare la dichiarazione come questa:

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

Ho ricercato un problema simile e ho letto che il cast precedente è un "trucco" molto comune che viene utilizzato in tutto il framework delle raccolte. – luke

+15

IMO, questa dovrebbe essere la risposta selezionata. Non ho sperimentato, ma ho la sensazione che il metodo # 2 di Sergey crea un po 'di overhead; e io sono POSITIVO che lo fa # 1. Un elenco non è efficiente come un array in diversi modi che non descriverò qui, ma ho fatto esperimenti e ho visto grandi rallentamenti quando si usano gli elenchi rispetto agli array. È più veloce gestire i propri array e riallocarli, piuttosto che aggiungere elementi a un elenco. – Ricket

+0

@Ricket Sono d'accordo, tratto da http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html – Peteter

5

A parte f dai problemi di sintassi, mi sembra strano usare una matrice e una lista collegata per rappresentare una matrice. Per poter accedere a celle arbitrarie della matrice, probabilmente vorrai un array effettivo o almeno un ArrayList per contenere le righe, poiché LinkedList deve attraversare l'intera lista dal primo elemento a qualsiasi elemento particolare, un'operazione O(n), al contrario al molto più veloce O(1) con ArrayList o una matrice reale.

Dato che questa matrice è sparsa, tuttavia, forse un modo migliore per archiviare i dati è come una mappa di mappe, dove una chiave nella prima mappa rappresenta un indice di riga, e il suo valore è una mappa di riga le cui chiavi sono un indice di colonna, con il valore della classe IntegerNode.Così:

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 

Se è necessario essere in grado di attraversare la riga di matrice per riga, è possibile rendere la mappa fila digitare un TreeMap, e lo stesso per attraversare le colonne in ordine di indice, ma se non è necessario questi casi, HashMap è più veloce di TreeMap. I metodi di supporto per ottenere e impostare una cella arbitraria, gestendo valori nulli non impostati, sarebbero utili, ovviamente.

3

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

colata questo modo i lavori, ma ancora ti lascia con un brutto avvertimento:

"di sicurezza di tipo: L'espressione di tipo List [] esigenze di conversione incontrollato .."

Dichiarazione di una classe speciale per la matrice di elenchi:

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

è un'idea intelligente per evitare l'avviso. forse un po 'più bello è quello di utilizzare un'interfaccia per esso:

public interface IntegerNodeList extends List<IntegerNode> {} 

poi

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

compila senza avvisi.

non sembra troppo male, vero?

+0

IntegerNodeList: che classe useresti? Ad esempio, non è possibile assegnare a ArrayList . Dovresti estendere anche ArrayList ... –

+0

non è necessario utilizzare l'interfaccia IntegerNodeList all'esterno dell'inizializzazione dell'array: Elenco [] myMatrix = new IntegerNodeList [5]; per (int i = 0; i (); } – user306708

+1

'Elenco [] myMatrix = new IntegerNodeList [numRows];' Questo ha un problema sottile ma importante. È possibile * solo * inserire 'IntegerNodeList' nella matrice. 'myMatrix [i] = new ArrayList ();' genererà 'ArrayStoreException'. – Radiodef

4
class IntegerNodeList extends LinkedList<IntegerNode> {} 

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 
+0

Hai perso i generici per LinkedList. –

2
List<String>[] lst = new List[2]; 
lst[0] = new LinkedList<String>(); 
lst[1] = new LinkedList<String>(); 

Nessun eventuali avvisi. NetBeans 6.9.1, jdk1.6.0_24

+0

Vero nessun avviso ma con l'aggiornamento Java SE 6 di Oracle 32 Vengo visualizzato l'errore di compilazione "L'elenco dei tipi non è generico, non può essere parametrizzato con gli argomenti ". La rimozione dell'argomento genera un altro errore "Tipo non corrispondente: impossibile convertire da LinkedList in Elenco". –

0

Se faccio il seguente ottengo il messaggio di errore in questione

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

Ma se ho appena rimuovere il tipo di lista nella dichiarazione sembra avere la funzionalità desiderata .

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

Queste due dichiarazioni sono drasticamente diverse in un modo di cui non sono a conoscenza?

EDIT

Ah, penso che ho incontrato questo problema ora.

L'iterazione sulla matrice e l'inizializzazione degli elenchi in un ciclo continuo sembrano funzionare. Anche se non è l'ideale come alcune delle altre soluzioni offerte.

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

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

È necessario un allineamento di List, un'alternativa è quella di provare:

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

Poi node_array[i] memorizza la testa (prima) nodo di una (qualunque sia il vostro implementazione lista dei favoriti) ArrayList<IntegerNode> o LinkedList<IntegerNode>.

In questo modello, si perde il metodo di accesso casuale list.get(index), ma si potrebbe comunque attraversare l'elenco a partire dall'archivio del nodo testa/pugno nell'array di tipo safe.

Questa potrebbe essere una scelta di progettazione accettabile a seconda del caso d'uso. Per esempio, io uso questo disegno per rappresentare un elenco di grafici di adiacenza, nella maggior parte dei casi d'uso, richiede comunque l'attraversamento dell'elenco di adiacenze per un dato vertice invece dell'accesso casuale ad alcuni vertici nell'elenco.