2011-10-13 30 views
15

Trong một trò chơi tôi có một danh sách các cầu thủ, chúng ta hãy nói như thế này:Sao chép một Iterator trong Java?

LinkedList<String> players = new LinkedList<String>(); 

Tôi muốn để cho mỗi người chơi tương tác với nhau của các cầu thủ khác, vì vậy tôi viết hai vòng lồng nhau:

Iterator<String> i1 = players.iterator(); 
while (i1.hasNext()) { 
    String p1 = i1.next(); 
    Iterator<String> i2 = players.iterator(); 
    // But I want to do this: Iterator<String> i2 = i1.clone(); 
    while (i2.hasNext()) { 
     String p2 = i2.next(); 
     System.out.println("Interact: " + p1 + ", " + p2); 
    } 
} 

Vì tôi chỉ muốn mỗi cặp người chơi tương tác một lần, tôi muốn bắt đầu vòng lặp bên trong với trình phát sau trình phát hiện tại của vòng lặp bên ngoài. Vì vậy, tôi muốn sao chép các iterator, nhưng điều đó không biên dịch.

Vì vậy, tôi nên làm gì để thay thế?

+3

Tại sao không chỉ sử dụng 'ArrayList ' thay thế? Một thuật toán sử dụng các vị trí sẽ là tầm thường với cấu trúc dữ liệu đó. –

+0

Điều này có dẫn đến việc ghép nối trình phát A với A không? –

+0

@Kirk: Có, ArrayList sẽ hoạt động, nhưng vì tôi có thể phải chèn và xóa người chơi ở giữa danh sách, tôi muốn một LinkedList. –

Trả lời

25

Sau đây sẽ làm điều đó:

ListIterator<String> i1 = players.listIterator(0); 
while (i1.hasNext()) { 
    String p1 = i1.next(); 
    ListIterator<String> i2 = players.listIterator(i1.nextIndex()); 
    while (i2.hasNext()) { 
     String p2 = i2.next(); 
     System.out.println("Interact: " + p1 + ", " + p2); 
    } 
} 

Nó phụ thuộc vào khả năng của ListIterator để bắt đầu từ vị trí nhất định và cũng để biết vị trí hiện tại của nó.

+1

aix tấn công lần nữa. 1, giải pháp đẹp. – aioobe

+0

Cảm ơn! Nhưng, một câu hỏi: phương thức listIterator (int) hoạt động như thế nào - nó không bắt đầu ở đầu danh sách và lặp lại theo cách của nó đến vị trí đã cho, đúng không? –

+3

@ ThomasPadron-McCarthy: Đó không phải là một phần của giao diện. Tuy nhiên, do bản chất của danh sách liên kết, gần như chắc chắn không. Mặt khác, tôi không biết bất kỳ giải pháp nào có thể tránh được điều này. – NPE

2

Ngoài aix answer, tôi muốn chỉ ra rằng tuy nhiên bạn tạo một trình lặp bắt đầu từ một chỉ mục cụ thể, nó bị ràng buộc là một hoạt động tuyến tính. Nếu không, bạn sẽ có thể thực hiện quyền truy cập tùy ý vào danh sách trong thời gian không đổi bằng cách sử dụng

elementN = createIterator(linkedList, N).next(); 

sẽ mâu thuẫn.

Trong trường hợp của bạn do đó tôi tin rằng các giải pháp hiệu quả nhất sẽ thực sự có thể làm

List<String> tmp = new ArrayList<String>(players); 
for (int p1 = 0; p1 < tmp.size(); p1++) 
    for (int p2 = p1+1; p2 < tmp.size(); p2++) 
     System.out.println("Interact: " + tmp.get(p1) + ", " + tmp.get(p2)); 

Lưu ý tuy nhiên, nó là vẫn cùng phức tạp như các giải pháp bởi aix; O (n) nhưng có thể có yếu tố không đổi nhỏ hơn.

+1

Tôi không đồng ý. Nếu bạn có một trình vòng lặp trỏ đến chỉ mục bạn muốn, bạn sẽ có thể nhận được chỉ mục đó ngay lập tức, miễn là giao diện cho phép. Phương thức 'i1.clone()' tưởng tượng này sẽ là 'O (1)' trong khi 'players.listIterator (i1.nextIndex()) 'là' O (n) '. Phương thức 'clone()' sẽ cung cấp trình vòng lặp nhân bản với nút mà nó hiện đang nắm giữ, loại bỏ sự cần thiết phải lặp lại đến điểm đó trong danh sách. – anthropomorphic

+0

Về nguyên tắc bạn nói đúng. Phương pháp sao chép ảo sẽ là tầm thường để thực hiện. Tuy nhiên, trong trường hợp này, OP có nhiều khả năng liên quan đến java.util.LinkedList không hỗ trợ nhân bản. Nhiều câu hỏi về chủ đề này. Xem ví dụ http://stackoverflow.com/questions/5963399/how-can-i-make-a-copy-of-an-iterator-in-java – aioobe

0

Để biết giải pháp tránh chi phí tuyến tính được liên kết với listIterator(int) (câu trả lời của NPE), hãy xem answer to a similar question của tôi. Tóm lại, miễn là bạn không quan tâm đến thứ tự danh sách được truy cập, bạn có thể bắt đầu vòng lặp bên ngoài từ phần tử cuối cùng và lặp lại, và bắt đầu vòng lặp bên trong từ phần tử đầu tiên và lặp lại cho tới khi hai vòng lặp gặp. Cuộc gọi đến list.listIterator (list.size()) là nhanh vì danh sách là một LinkedList, tức là danh sách được liên kết kép và việc truy cập phần tử cuối cùng không yêu cầu lặp qua danh sách. Xem ví dụ bên dưới:

public static int iterRevIterator(List<Integer> list) { 
    int sum = 0; 
    for(ListIterator<Integer> outer = list.listIterator(list.size()); outer.hasPrevious();) { 
     Integer oVal = outer.previous(); 
     for(ListIterator<Integer> inner = list.listIterator(); inner.nextIndex() <= outer.previousIndex();) { 
      sum += oVal * inner.next(); 
     } 
    } 
    return sum; 
} 
Các vấn đề liên quan