2008-10-19 18 views
96

Tôi đang làm việc trên một lớp ma trận thưa thớt mà cần để sử dụng một mảng LinkedList để lưu trữ các giá trị của ma trận. Mỗi phần tử của mảng (nghĩa là mỗi LinkedList) đại diện cho một hàng của ma trận. Và, mỗi phần tử trong mảng LinkedList đại diện cho một cột và giá trị được lưu trữ.Không thể tạo một mảng các LinkedLists trong Java ...?

Trong lớp học của tôi, tôi có một lời tuyên bố của các mảng như:

private LinkedList<IntegerNode>[] myMatrix; 

Và, trong constructor của tôi cho SparseMatrix, tôi cố gắng xác định:

myMatrix = new LinkedList<IntegerNode>[numRows]; 

Các lỗi tôi kết thúc nhận được là

Không thể tạo mảng chung là LinkedList<IntegerNode>.

Vì vậy, tôi có hai vấn đề với điều này:

  1. Tôi đang làm gì sai, và
  2. Tại sao các loại chấp nhận được trong việc kê khai cho mảng nếu nó không thể được tạo ra?

IntegerNode là lớp mà tôi đã tạo. Và, tất cả các tệp lớp của tôi được đóng gói cùng nhau.

Trả lời

63

Bạn không thể sử dụng tạo mảng chung. Đó là một lỗ hổng/tính năng của Generics java.

Những cách mà không cần cảnh báo là:

  1. Sử dụng Danh sách Danh sách thay vì Array của Lists:

    List< List<IntegerNode>> nodeLists = new LinkedList< List<IntegerNode>>(); 
    
  2. Tuyên bố lớp học đặc biệt cho mảng của Lists:

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

Một giải pháp thay thế tốt hơn cho giải pháp sau sẽ là: 'lớp IntegerNodeList mở rộng Danh sách {}' – kamasheto

+5

ở trên sẽ phải thực hiện Danh sách mở rộng ArrayList .... – Dori

+0

Việc triển khai này quá chậm. Lấy phần tử [1000] [2000] (nodeLists.get (1000) .get (2000)) sẽ làm cho LinkedList lặp lại 3000 lần! Tránh LinkedList nếu có ai đó có thể lập chỉ mục vào nó. ArrayList sẽ lập chỉ mục nhanh hơn, nhưng giải pháp của Fredrik thì tốt hơn. –

133

Đối với một số lý do bạn phải đúc các loại và thực hiện việc kê khai như thế này:

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

Tôi đã nghiên cứu một vấn đề tương tự và đọc rằng dàn diễn viên ở trên là một 'hack' rất phổ biến được sử dụng trên toàn bộ khung công tác. – luke

+15

IMO, đây phải là câu trả lời đã chọn. Tôi chưa thử nghiệm, nhưng tôi có cảm giác ruột rằng phương pháp # 2 của Sergey tạo ra khá nhiều chi phí; và tôi là TÍCH CỰC mà số 1 thực hiện. Một danh sách không hiệu quả như một mảng theo nhiều cách mà tôi sẽ không chi tiết ở đây, nhưng tôi đã thực hiện các thí nghiệm và thấy sự chậm lại lớn khi sử dụng các danh sách so với các mảng. Việc quản lý các mảng của riêng bạn và phân bổ lại chúng nhanh hơn là thêm nội dung vào Danh sách. – Ricket

+0

@Ricket Tôi đồng ý, được lấy từ http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html – Peteter

5

Ngoài f rom các vấn đề cú pháp, nó có vẻ lạ với tôi để sử dụng một mảng và một danh sách liên kết để đại diện cho một ma trận. Để có thể truy cập các ô tùy ý của ma trận, bạn có thể muốn một mảng thực hoặc ít nhất là ArrayList để giữ các hàng, vì LinkedList phải đi qua toàn bộ danh sách từ phần tử đầu tiên đến bất kỳ phần tử cụ thể nào, hoạt động O(n). đến nhanh hơn O(1) với ArrayList hoặc một mảng thực tế. Vì bạn đã đề cập ma trận này thưa thớt, có lẽ cách tốt hơn để lưu trữ dữ liệu là bản đồ bản đồ, trong đó khóa trong bản đồ đầu tiên biểu thị chỉ mục hàng và giá trị của nó là bản đồ hàng có khóa là một chỉ mục cột, với giá trị là lớp IntegerNode của bạn.Như vậy:

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 

Nếu bạn cần để có thể đi qua hàng ma trận bởi hàng, bạn có thể làm cho các bản đồ hàng gõ một TreeMap, và cùng để vượt qua các cột theo thứ tự chỉ mục, nhưng nếu bạn không cần những trường hợp đó, HashMap nhanh hơn TreeMap. Các phương thức của trình trợ giúp để nhận và đặt một ô tùy ý, xử lý các giá trị null chưa được đặt, sẽ hữu ích, tất nhiên.

3

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

đúc theo cách này công trình nhưng vẫn để lại cho bạn với một cảnh báo khó chịu:

"Loại an toàn: Các biểu hiện của loại List [] nhu cầu chuyển đổi không được kiểm soát .."

Khai báo một lớp đặc biệt cho Array of Lists:

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

là một ý tưởng thông minh để tránh cảnh báo. có thể là một chút đẹp hơn là sử dụng một giao diện cho nó:

public interface IntegerNodeList extends List<IntegerNode> {} 

sau đó

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

biên dịch mà không cần cảnh báo.

không quá tệ, phải không?

+0

IntegerNodeList: bạn sẽ sử dụng lớp này với lớp nào? Ví dụ bạn không thể gán một ArrayList cho nó. Bạn sẽ cần phải mở rộng ArrayList là tốt ... –

+0

không cần sử dụng giao diện IntegerNodeList bên ngoài việc khởi tạo mảng: Danh sách [] myMatrix = new IntegerNodeList [5]; cho (int i = 0; i (); } – user306708

+1

'Danh sách [] myMatrix = new IntegerNodeList [numRows];' Điều này có một vấn đề tinh tế nhưng quan trọng. Bạn có thể * chỉ * đặt 'IntegerNodeList' trong mảng. 'myMatrix [i] = new ArrayList ();' sẽ ném 'ArrayStoreException'. – Radiodef

4
class IntegerNodeList extends LinkedList<IntegerNode> {} 

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

Bạn đã bỏ lỡ các generics cho LinkedList. –

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

Không bất kỳ cảnh báo. NetBeans 6.9.1, jdk1.6.0_24

+0

Đúng là không có cảnh báo nhưng với Oracle SE 6 Update của Oracle 32 tôi nhận được lỗi biên dịch "Danh sách loại không phải là chung chung; nó không thể được tham số hóa với các đối số ". Xóa đối số sẽ tạo ra lỗi khác "Loại không khớp: không thể chuyển đổi từ LinkedList thành Danh sách". –

0

Nếu tôi làm như sau tôi nhận được thông báo lỗi trong câu hỏi

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

Nhưng nếu tôi chỉ loại bỏ các loại danh sách trong khai báo nó dường như có chức năng mong muốn .

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

Hai khai báo này có khác biệt đáng kể theo cách mà tôi không biết?

EDIT

Ah, tôi nghĩ rằng tôi đã chạy vào vấn đề này ngay bây giờ.

Lặp lại ma trận và khởi tạo danh sách trong vòng lặp for dường như hoạt động. Mặc dù nó không lý tưởng như một số giải pháp khác được cung cấp.

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

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

Bạn cần một mảng của List, một thay thế là để thử:

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

Sau đó node_array[i] cửa hàng đầu (đầu tiên) node của một ArrayList<IntegerNode> hoặc LinkedList<IntegerNode> (bất cứ điều gì thực hiện danh sách yêu thích của bạn).

Theo thiết kế này, bạn mất phương thức truy cập ngẫu nhiên list.get(index), nhưng sau đó bạn vẫn có thể duyệt qua danh sách bắt đầu bằng cửa sổ nút đầu/nắm tay trong mảng an toàn loại.

Đây có thể là lựa chọn thiết kế phù hợp tùy thuộc vào trường hợp sử dụng của bạn. Ví dụ, tôi sử dụng thiết kế này để đại diện cho một danh sách kề của đồ thị, trong hầu hết trường hợp sử dụng, nó đòi hỏi đi qua danh sách kề nhau cho một đỉnh đã cho thay vì truy cập ngẫu nhiên một số đỉnh trong danh sách.

Các vấn đề liên quan