Tidak dapat membuat array LinkedLists di Java…?

102

Saya sedang mengerjakan kelas matriks renggang yang perlu menggunakan array LinkedListuntuk menyimpan nilai matriks. Setiap elemen dari array (yaitu masing-masing LinkedList) mewakili baris matriks. Dan, setiap elemen dalam LinkedListarray mewakili kolom dan nilai yang disimpan.

Di kelas saya, saya memiliki deklarasi array sebagai:

private LinkedList<IntegerNode>[] myMatrix;

Dan, dalam konstruktor saya untuk SparseMatrix, saya mencoba mendefinisikan:

myMatrix = new LinkedList<IntegerNode>[numRows];

Kesalahan yang akhirnya saya dapatkan adalah

Tidak dapat membuat larik umum dari LinkedList<IntegerNode>.

Jadi, saya punya dua masalah dengan ini:

  1. Apa yang saya lakukan salah, dan
  2. Mengapa tipe dapat diterima dalam deklarasi untuk larik jika tidak dapat dibuat?

IntegerNodeadalah kelas yang telah saya buat. Dan, semua file kelas saya dikemas bersama.

kafuchau
sumber

Jawaban:

64

Anda tidak dapat menggunakan pembuatan array umum. Ini adalah kelemahan / fitur java generics.

Cara-cara tanpa peringatan adalah:

  1. Menggunakan Daftar Daftar alih-alih Array Daftar:

    List< List<IntegerNode>> nodeLists = new LinkedList< List< IntegerNode >>();
  2. Mendeklarasikan kelas khusus untuk Array of List:

    class IntegerNodeList {
        private final List< IntegerNode > nodes;
    }
Sergey
sumber
19
Alternatif yang lebih baik untuk solusi terakhir adalah: class IntegerNodeList extends List<IntegerNode> {}
kamasheto
Implementasi ini sangat lambat. Mendapatkan elemen [1000] [2000] (nodeLists.get (1000) .get (2000)) akan membuat LinkedList melakukan iterasi 3000 kali! Hindari LinkedList jika ada yang mengindeks ke dalamnya. ArrayList akan mengindeks lebih cepat, tetapi solusi Fredrik lebih baik secara keseluruhan.
Steve Zobell
142

Untuk beberapa alasan Anda harus memasukkan tipe dan membuat deklarasi seperti ini:

myMatrix = (LinkedList<IntegerNode>[]) new LinkedList<?>[numRows];
Fredrik
sumber
Saya meneliti masalah serupa dan membaca bahwa pemeran di atas adalah 'peretasan' yang sangat umum yang digunakan di seluruh kerangka koleksi.
Lukas
15
IMO, ini harus menjadi jawaban yang dipilih. Saya belum bereksperimen, tetapi saya memiliki firasat bahwa metode # 2 Sergey menciptakan sedikit overhead; dan saya POSITIF yang # 1 lakukan. Daftar tidak seefisien array dalam beberapa hal yang tidak akan saya detailkan di sini, tetapi saya TELAH melakukan eksperimen dan melihat perlambatan besar saat menggunakan daftar dibandingkan dengan array. Lebih cepat hanya mengelola array Anda sendiri dan mengalokasikannya kembali, daripada menambahkan barang ke Daftar.
Ricket
@Ricket Saya setuju, diambil dari ibm.com/developerworks/java/library/j-jtp01255/index.html
Peteter
4
Saya masih mendapatkan peringatan "Jenis keamanan: tidak dicentang". Solusi Bob terlihat paling bersih bagi saya.
Marco Lackovic
3
Di JDK 7 di atas memberikan peringatan rawtypes. Itu bisa diperbaiki menggunakan tipe <?> Tak terbatas, tapi Anda masih mendapatkan peringatan yang tidak dicentang (yang bisa disembunyikan). misalnya <br> <code> myMatrix = (LinkedList <IntegerNode> []) LinkedList baru <?> [numRows]; </code>
Neon
5

Selain dari masalah sintaks, tampaknya aneh bagi saya untuk menggunakan array dan daftar tertaut untuk mewakili matriks. Untuk dapat mengakses sel sembarang dari matriks, Anda mungkin menginginkan larik aktual atau setidaknya sebuah ArrayListuntuk menahan baris, karena LinkedListharus melintasi seluruh daftar dari elemen pertama ke elemen tertentu, sebuah O(n)operasi, sebagai lawan dari banyak. lebih cepat O(1)dengan ArrayListatau array yang sebenarnya.

Karena Anda menyebutkan matriks ini jarang, mungkin cara yang lebih baik untuk menyimpan data adalah sebagai peta peta, di mana kunci di peta pertama mewakili indeks baris, dan nilainya adalah peta baris yang kuncinya adalah indeks kolom , dengan nilai menjadi kelas IntegerNode Anda. Jadi:

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

Jika Anda ingin dapat melintasi matriks baris demi baris, Anda dapat membuat peta baris tipe a TreeMap, dan sama untuk melintasi kolom dalam urutan indeks, tetapi jika Anda tidak membutuhkan kasus tersebut, HashMaplebih cepat dari TreeMap. Metode pembantu untuk mendapatkan dan menyetel sel arbitrer, menangani nilai null yang tidak disetel, tentu saja akan berguna.

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

IntegerNodeList[] myMatrix = new IntegerNodeList[numRows]; 
Bob
sumber
Anda melewatkan generik untuk LinkedList.
Peter Wippermann
3

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

casting dengan cara ini berhasil tetapi masih meninggalkan Anda dengan peringatan buruk:

"Keamanan jenis: Ekspresi daftar jenis [] membutuhkan konversi yang tidak dicentang .."

Mendeklarasikan kelas khusus untuk Array of List:

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

adalah ide yang cerdas untuk menghindari peringatan tersebut. mungkin sedikit lebih baik adalah menggunakan antarmuka untuk itu:

public interface IntegerNodeList extends List<IntegerNode> {}

kemudian

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

mengkompilasi tanpa peringatan.

tidak terlihat terlalu buruk, bukan?

pengguna306708
sumber
IntegerNodeList: dengan kelas apa Anda akan menggunakan ini? Misalnya Anda tidak dapat menetapkan ArrayList <IntegerNode> untuk itu. Anda juga perlu memperpanjang ArrayList ...
Hans-Peter Störr
tidak perlu menggunakan antarmuka IntegerNodeList di luar inisialisasi array: List <IntegerNode> [] myMatrix = new IntegerNodeList [5]; untuk (int i = 0; i <myMatrix.length; i ++) {myMatrix [i] = new ArrayList <IntegerNode> (); }
pengguna306708
1
List<IntegerNode>[] myMatrix = new IntegerNodeList[numRows];Ini memiliki masalah yang halus namun penting. Anda hanya dapat memasukkan IntegerNodeListarray. myMatrix[i] = new ArrayList<IntegerNode>();akan melempar ArrayStoreException.
Radiodef
2
List<String>[] lst = new List[2];
lst[0] = new LinkedList<String>();
lst[1] = new LinkedList<String>();

Tidak ada peringatan apapun. NetBeans 6.9.1, jdk1.6.0_24

Andrii
sumber
1
Benar tidak ada peringatan tetapi dengan Oracle Java SE 6 Update 32 Saya mendapatkan kesalahan kompilasi "Jenis Daftar tidak umum; tidak dapat diparameterisasi dengan argumen <String>". Menghapus argumen <String> menghasilkan kesalahan lain "Ketik ketidakcocokan: tidak dapat mengubah dari LinkedList <String> ke Daftar".
Marco Lackovic
0

Jika saya melakukan hal berikut, saya mendapatkan pesan kesalahan yang dimaksud

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

Tetapi jika saya hanya menghapus jenis daftar di deklarasi itu tampaknya memiliki fungsionalitas yang diinginkan.

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

Apakah kedua pernyataan ini sangat berbeda dengan cara yang tidak saya sadari?

EDIT

Ah, sepertinya saya sudah mengalami masalah ini sekarang.

Iterasi atas matriks dan menginisialisasi daftar dalam loop-for tampaknya berhasil. Padahal itu tidak seideal beberapa solusi lain yang ditawarkan.

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

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

Anda memerlukan array List, salah satu alternatifnya adalah mencoba:

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

Kemudian node_array[i]simpan simpul kepala (pertama) dari a ArrayList<IntegerNode>atau LinkedList<IntegerNode>(apa pun implementasi daftar favorit Anda).

Di bawah desain ini, Anda kehilangan metode akses acak list.get(index), tetapi kemudian Anda masih bisa melintasi daftar yang dimulai dengan penyimpanan node head / fist dalam tipe safe array.

Ini mungkin pilihan desain yang dapat diterima tergantung pada kasus penggunaan Anda. Misalnya, saya menggunakan desain ini untuk mewakili daftar grafik kedekatan, dalam banyak kasus penggunaan, ini memerlukan melintasi daftar ketetanggaan untuk titik tertentu alih-alih akses acak beberapa titik dalam daftar.

Yiling
sumber