Bộ sưu tập Java nhanh nhất với chức năng cơ bản của Hàng đợi là gì?


75

Bộ sưu tập nhanh nhất trong Java là gì?

Tôi chỉ cần các thao tác thêm và bớt, thứ tự không quan trọng, các phần tử bằng không phải là vấn đề, không có gì khác hơn là thêm và bớt là vô ích.

Không có kích thước giới hạn cũng quan trọng.

Bộ sưu tập này sẽ có Đối tượng bên trong anh ta.

Hiện tại tôi đang sử dụng ArrayDeque vì tôi thấy đây là cách triển khai Hàng đợi nhanh hơn.


10
Nếu thứ tự không quan trọng, bạn không phải đang tìm một hàng đợi.
BoltClock

Hiện tại tôi đang thêm vào phần cuối cùng và truy xuất từ ​​đầu (như Hàng đợi), nhưng nếu tôi có thể lấy ra tất cả các phần tử, từng phần tử một, tôi có thể sử dụng Bộ sưu tập khác.
Renato Dinhani

3
"... tối ưu hóa quá sớm là gốc rễ của mọi điều ác"
mre

56
chọn đúng bộ sưu tập không phải là tối ưu hóa quá sớm.
Bozho

7
BoltClock, không chính xác đối với Hàng đợi viết hoa-Q trong Java. Nó chỉ có nghĩa là "một tập hợp có thể thay đổi với một phần tử đầu". Đọc lại java.util.Queue.
Kevin Bourrillion

Câu trả lời:


95

ArrayDequelà tốt nhất. Xem điểm chuẩn này , lấy từ bài đăng trên blog này về kết quả của điểm chuẩn này. ArrayDequekhông có chi phí phân bổ nút LinkedListcũng không có chi phí chuyển đổi nội dung mảng còn lại khi loại bỏ ArrayListcó. Trong điểm chuẩn, nó thực hiện khoảng 3x cũng như LinkedListđối với hàng đợi lớn và thậm chí tốt hơn một chút so ArrayListvới hàng đợi trống. Để có hiệu suất tốt nhất, có thể bạn sẽ muốn cung cấp cho nó một dung lượng ban đầu đủ lớn để chứa số lượng phần tử mà nó có thể giữ tại một thời điểm để tránh nhiều lần thay đổi kích thước.

Giữa ArrayListLinkedList, có vẻ như nó phụ thuộc vào số lượng trung bình của tổng các yếu tố hàng đợi sẽ chứa tại bất kỳ thời điểm nào và rằng LinkedListnhịp đập ArrayListbắt đầu từ khoảng 10 yếu tố.


ArrayList dùng làm ngăn xếp nên cũng giống như ArrayDeque, dung lượng ban đầu ảnh hưởng rất nhiều đến hiệu suất. Quá nhiều có nghĩa là nhiều bộ nhớ hơn để phân bổ và thu thập, quá ít có nghĩa là nhiều bản sao hơn (nhưng nhìn chung thì tốt hơn là quá lớn cho các vòng lặp chặt chẽ). Tôi không thể thấy nguồn của điểm chuẩn, nó có sẵn không?
bestsss

@bestsss: Có, được sử dụng như một ngăn xếp ArrayListsẽ gần tương đương, mặc dù ArrayDequejavadoc của gợi ý rằng nó có thể nhanh hơn một chút. Và vâng, với các yêu cầu trong câu hỏi, việc sử dụng giống như ngăn xếp sẽ hoạt động tốt. Tuy nhiên, điểm chuẩn dành riêng cho việc sử dụng hàng đợi FIFO (bạn có thể xem ví dụ về mã trong bài đăng blog được liên kết).
ColinD

7
Tôi nhận ra câu hỏi này đã cũ, nhưng cả hai liên kết của bạn đều đã chết. Có bất kỳ URL thay thế nào không?
rath

4
Vì tôi gặp sự cố tương tự như @rath, tôi đã thu thập dữ liệu blog gốc và tôi tìm thấy bài viết gốc: https://publicobject.com/2010/07/07/caliper_conf Enterprises_reality_linked_list_vs_array_list / . Thật không may, nếu tôi cố gắng xem kết quả điểm chuẩn, tôi sẽ gặp phải lỗi 401 - lỗi trái phép.
ocramot

3
Đây cũng là một thí nghiệm khác xác nhận rằng ArrayDeque là 3x nhanh hơn LinkedList: java-performance.info/linkedlist-performance
Dheeru Mundluru

6

Bạn có thể sử dụng a java.util.LinkedList- nó được liên kết kép và hình cicrular, vì vậy việc thêm vào một đầu và lấy từ đầu kia là O (1)

Dù bạn chọn cách triển khai nào, hãy tham khảo nó theo Queuegiao diện để bạn có thể dễ dàng thay đổi nó nếu nó không phù hợp với trường hợp của bạn (nếu, tất nhiên, hàng đợi là thứ bạn cần ngay từ đầu)

Cập nhật: Câu trả lời của Colin cho thấy một điểm chuẩn kết luận ArrayDequelà tốt hơn. Cả hai đều có các phép toán O (1), nhưng LinkedListtạo ra các đối tượng (nút) mới, có hiệu suất hơi cao. Vì cả hai đều có O (1), tôi không nghĩ sẽ quá sai lầm nếu chọn LinkedList.


2
ArrayDequekhách quan là tốt hơn mặc dù.
ColinD

@ColinD - Tôi đã thấy, nhưng tại sao? Do tạo đối tượng (các nút) trong linekdlist? Cả hai dường như đều là O (1)
Bozho

1
@ColinD @Bozho Thay đổi kích thước mảng trong ArrayDeque cũng vậy. Sự cân nhắc thực sự ở đây là độ phức tạp của thuật toán. Bất kỳ thứ gì liên quan đến mảng là O (N) để thêm / xóa, bất kỳ thứ gì liên quan đến liên kết là O (1).
user207421

16
@EJP: ArrayDeque O (1) để thêm và xóa ở front / end (tức là khi được sử dụng như một hàng đợi hoặc ngăn xếp) vì nó là một mảng tròn và không sao chép bất cứ thứ gì trong những trường hợp đó. Ngoài ra, thay đổi kích thước là một hoạt động không thường xuyên thường có thể tránh được với dung lượng ban đầu thích hợp. LinkedListChi phí của việc tạo đối tượng bổ sung (cộng với việc thu gom rác của đối tượng đó) ảnh hưởng đến mọi thêm / bớt trên hàng đợi. Điểm chuẩn mà tôi đã liên kết cho thấy nó luôn nhanh gấp 3 lần so với a LinkedList.
ColinD

1
O(1) != O(1). O()chỉ là thước đo độ phức tạp, không phải thời gian thực hiện. Một hoạt động luôn mất 5 năm bất kể nO(1), cũng như một hoạt động luôn mất 5 ms. Tôi muốn sử dụng một trong những mất 5 mili giây. Ngay cả một hoạt động mất 5 ms cho mỗi phần tử (tức là O(n)) sẽ tốt hơn hoạt động 5 năm nếu nkhông quá lớn.
Erick G. Hagstrom

0

ConcurrentLinkedDeque là lựa chọn tốt nhất cho Hàng đợi đa luồng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.