2008-10-19 31 views
96

Pracuję nad rzadką klasą macierzową, która wymaga użycia w celu użycia macierzy LinkedList do przechowywania wartości macierzy. Każdy element tablicy (to znaczy każdy LinkedList) reprezentuje rząd macierzy. A każdy element w tablicy LinkedList reprezentuje kolumnę i zapisaną wartość.Nie można utworzyć tablicy LinkedLists w Javie ...?

w mojej klasie, mam deklarację tablicy jako:

private LinkedList<IntegerNode>[] myMatrix; 

i moim konstruktora dla SparseMatrix, staram się określić:

myMatrix = new LinkedList<IntegerNode>[numRows]; 

Błąd skończę Uzyskiwanie to

Nie można utworzyć ogólnej tablicy LinkedList<IntegerNode>.

Tak, mam dwa problemy z tym:

  1. Co robię źle i
  2. Dlaczego typ dopuszczalne w deklaracji tablicy, jeśli nie można go stworzył?

IntegerNode to klasa, którą stworzyłem. Wszystkie moje pliki klas są spakowane razem.

Odpowiedz

63

Nie można użyć ogólnego tworzenia macierzy. To wada/funkcja generycznych java.

Sposoby bez ostrzeżenia:

  1. Korzystanie z listy list zamiast Array of Lists:

    List< List<IntegerNode>> nodeLists = new LinkedList< List<IntegerNode>>(); 
    
  2. deklarowania specjalną klasę dla Array of Lists:

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

Lepszym rozwiązaniem z drugim rozwiązaniem byłoby: klasa 'IntegerNodeList rozciąga Lista {}' – kamasheto

+5

wyżej musiałby być Realizacja listy tj rozciąga ArrayList .... – Dori

+0

Ta implementacja jest outrageously powoli. Pobranie elementu [1000] [2000] (nodeLists.get (1000) .get (2000)) spowoduje, że LinkedList będzie iterować 3000 razy! Unikaj LinkedList, jeśli ktoś może się do niej indeksować. ArrayList indeksuje się szybciej, ale rozwiązanie Fredrika jest ogólnie lepsze. –

133

Z jakiegoś powodu trzeba rzucać typ i sprawiają, że deklaracja tak:

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

Zbadałem podobny problem i przeczytałem, że powyższa obsada jest bardzo popularnym "hack", który jest używany w całej strukturze kolekcji. – luke

+15

IMO, to powinna być wybrana odpowiedź. Nie eksperymentowałem, ale mam przeczucie, że metoda nr 2 Siergieja generuje spore obciążenie; i jestem POZYTYWNY, który robi # 1. Lista nie jest tak wydajna jak tablica na kilka sposobów, których nie będę tu szczegółowo opisywać, ale wykonałem eksperymenty i zaobserwowałem duże spowolnienie w przypadku korzystania z list w porównaniu do tablic. Szybsze jest zarządzanie własnymi tablicami i ich ponowne przydzielanie, niż dodawanie rzeczy do listy. – Ricket

+0

@Ricket Zgadzam się, zaczerpnięte z http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html – Peteter

5

Na stronie f z powodu problemów z składnią, wydaje mi się dziwne używanie tablicy i połączonej listy do reprezentowania macierzy. Aby uzyskać dostęp do dowolnych komórek macierzy, prawdopodobnie potrzebna byłaby faktyczna tablica lub przynajmniej ArrayList do przechowywania wierszy, ponieważ LinkedList musi przechodzić przez całą listę od pierwszego elementu do dowolnego elementu, operacji O(n), w przeciwieństwie do do znacznie szybszego z ArrayList lub rzeczywistą tablicą.

Ponieważ wspomniałeś, że ta macierz jest rzadka, być może lepszym sposobem przechowywania danych jest mapa map, gdzie klucz na pierwszej mapie reprezentuje indeks wierszy, a jego wartość jest mapą wiersza, której klucze są indeksami kolumn, których wartością jest twoja klasa IntegerNode.Zatem:

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 

Jeśli potrzebujesz, aby móc przechodzić wiersz macierzy przez rząd, można sprawić, że mapa rząd wpisać TreeMap, a sama dla przejeżdżające kolumny w kolejności indeksu, ale jeśli nie musisz te przypadki, HashMap, są szybsze niż TreeMap. Pomocne są oczywiście metody pomocnicze, aby uzyskać i ustawić dowolną komórkę, posługując się nieustawionymi wartościami pustymi.

3

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

rzucając w ten sposób działa, ale nadal pozostawia Państwu bolesnego ostrzeżeniem:

"Bezpieczeństwo Typ: Wyrażenie typu listy [] niezaznaczone potrzeb konwersji .."

Zgłaszanie specjalnej klasy dla Tablic list:

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

to sprytny pomysł, aby uniknąć ostrzeżenia. może trochę ładniejszy jest w użyciu interfejs do niego:

public interface IntegerNodeList extends List<IntegerNode> {} 

następnie

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

kompiluje bez ostrzeżenia.

nie wygląda tak źle, prawda?

+0

IntegerNodeList: z jakiej klasy używałbyś tego? Na przykład nie można przypisać do niego ArrayList . Będziesz także musiał rozszerzyć ArrayList ... –

+0

nie ma potrzeby używania interfejsu IntegerNodeList poza inicjalizacją tablicy: Lista [] myMatrix = new IntegerNodeList [5]; dla (int i = 0; i (); } – user306708

+1

'List [] myMatrix = new IntegerNodeList [numer];' Ma to subtelny, ale ważny problem. Możesz * tylko * wstawić 'IntegerNodeList' w tablicy. 'myMatrix [i] = new ArrayList ();' rzuci 'ArrayStoreException'. – Radiodef

4
class IntegerNodeList extends LinkedList<IntegerNode> {} 

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

Tęskniłeś za generycznymi dla LinkedList. –

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

ma żadnego ostrzeżenia. NetBeans 6.9.1, jdk1.6.0_24

+0

Prawda bez ostrzeżeń, ale z Oracle Java SE 6 Update 32 Otrzymuję błąd kompilacji "Lista typów nie jest generyczna, nie można jej sparametryzować za pomocą argumentów ". Usunięcie argumentu powoduje wygenerowanie kolejnego błędu "Niezgodność typu: nie można przekonwertować z listy odnośników na listę". –

0

Jeśli ja dostaję następujący komunikat o błędzie w pytaniu

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

Ale jeśli po prostu usunąć typ listy w deklaracji wydaje się mieć pożądaną funkcjonalność .

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

Czy te dwie deklaracje różnią się drastycznie w sposób, którego nie jestem świadomy?

EDIT

Ach, myślę, że napotkasz ten problem teraz.

Iterowanie na macierzy i inicjowanie list w pętli for wydaje się działać. Choć nie jest tak idealny jak niektóre inne oferowane rozwiązania.

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

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

Musisz tablicę listy, jedna alternatywa jest, aby spróbować:

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

Następnie node_array[i] sklepów głowy (pierwszy) węzeł z ArrayList<IntegerNode> lub LinkedList<IntegerNode> (niezależnie od swojego ulubionego realizacji liście).

W tym projekcie utracono metodę dostępu swobodnego list.get(index), ale w dalszym ciągu można przeglądać listę, zaczynając od magazynu węzłów głowa/pięść w bezpiecznej tablicy typów.

Może to być dopuszczalny wybór projektu w zależności od przypadku użycia. Na przykład, używam tego projektu do reprezentowania listy grafów sąsiadujących, w większości przypadków wymaga to przejścia przez listę przyległości do danego wierzchołka zamiast losowego dostępu do niektórych wierzchołków na liście.