Câu trả lời:
Điều này đến rất muộn, nhưng có một lớp trong JDK chỉ với mục đích có một danh sách được sắp xếp. Nó được đặt tên (hơi lỗi so với các Sorted*
giao diện khác ) " java.util.PriorityQueue
". Nó có thể sắp xếp Comparable<?>
s hoặc sử dụng a Comparator
.
Sự khác biệt với List
cách sử dụng Collections.sort(...)
được sắp xếp là điều này sẽ duy trì một thứ tự từng phần, với hiệu suất chèn O (log (n)), bằng cách sử dụng cấu trúc dữ liệu heap, trong khi chèn vào một sắp xếp ArrayList
sẽ là O (n) (nghĩa là, sử dụng tìm kiếm nhị phân và di chuyển).
Tuy nhiên, không giống như a List
, PriorityQueue
không hỗ trợ truy cập được lập chỉ mục ( get(5)
), cách duy nhất để truy cập các mục trong một đống là lấy chúng ra, mỗi lần một cái (như tên PriorityQueue
).
TreeMap và TreeSet sẽ cung cấp cho bạn một lần lặp lại các nội dung theo thứ tự được sắp xếp. Hoặc bạn có thể sử dụng một ArrayList và sử dụng Collections.sort () để sắp xếp nó. Tất cả các lớp đó đều ở trong java.util
Nếu bạn muốn duy trì một danh sách được sắp xếp mà bạn sẽ thường xuyên sửa đổi (nghĩa là một cấu trúc, ngoài việc được sắp xếp, cho phép trùng lặp và các phần tử có thể được tham chiếu hiệu quả theo chỉ mục), sau đó sử dụng ArrayList nhưng khi bạn cần chèn một phần tử , luôn luôn sử dụng Collections.binarySearch () để xác định chỉ mục mà bạn thêm một yếu tố nhất định. Phương thức sau cho bạn biết chỉ mục bạn cần chèn vào để giữ danh sách của bạn theo thứ tự được sắp xếp.
Sử dụng lớp TreeMultiset của Google Guava . Quả ổi có một bộ sưu tập API ngoạn mục.
Một vấn đề với việc cung cấp một triển khai Danh sách duy trì thứ tự được sắp xếp là lời hứa được thực hiện trong JavaDocs của add()
phương thức.
List
luôn luôn thêm vào cuối.
Bạn muốn triển khai Sắp xếp Sắp xếp , cụ thể là Treeset .
Có một vài lựa chọn. Tôi muốn đề xuất TreeSet nếu bạn không muốn trùng lặp và các đối tượng bạn đang chèn có thể so sánh được.
Bạn cũng có thể sử dụng các phương thức tĩnh của lớp Bộ sưu tập để làm điều này.
Xem Bộ sưu tập # sort (java.util.List) và Treeset để biết thêm thông tin.
Nếu bạn chỉ muốn sắp xếp một danh sách, hãy sử dụng bất kỳ loại Danh sách nào và sử dụng Collections.sort () . Nếu bạn muốn đảm bảo các thành phần trong danh sách là duy nhất và luôn được sắp xếp, hãy sử dụng Sắp xếp .
Những gì tôi đã làm là triển khai Danh sách có một thể hiện bên trong với tất cả các phương thức được ủy quyền.
public class ContactList implements List<Contact>, Serializable {
private static final long serialVersionUID = -1862666454644475565L;
private final List<Contact> list;
public ContactList() {
super();
this.list = new ArrayList<Contact>();
}
public ContactList(List<Contact> list) {
super();
//copy and order list
List<Contact>aux= new ArrayList(list);
Collections.sort(aux);
this.list = aux;
}
public void clear() {
list.clear();
}
public boolean contains(Object object) {
return list.contains(object);
}
Sau đó, tôi đã triển khai một phương thức mới "putOrdered", chèn vào vị trí thích hợp nếu phần tử không tồn tại hoặc thay thế chỉ trong trường hợp nó tồn tại.
public void putOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
list.add(index, contact);
}else{
list.set(index, contact);
}
}
Nếu bạn muốn cho phép các phần tử lặp đi lặp lại, chỉ cần thực hiện addOrdered thay thế (hoặc cả hai).
public void addOrdered(Contact contact) {
int index=Collections.binarySearch(this.list,contact);
if(index<0){
index= -(index+1);
}
list.add(index, contact);
}
Nếu bạn muốn tránh chèn, bạn cũng có thể ném và ngoại lệ hoạt động không được hỗ trợ trên các phương thức "thêm" và "đặt".
public boolean add(Contact object) {
throw new UnsupportedOperationException("Use putOrdered instead");
}
... Và bạn cũng phải cẩn thận với các phương thức ListIterator vì chúng có thể sửa đổi danh sách nội bộ của bạn. Trong trường hợp này, bạn có thể trả lại một bản sao của danh sách nội bộ hoặc ném lại một ngoại lệ.
public ListIterator<Contact> listIterator() {
return (new ArrayList<Contact>(list)).listIterator();
}
List
hợp đồng. Có lẽ sẽ tốt hơn nếu chỉ thực hiện Collection
. Và nếu ContactList
được sắp xếp, sau đó contains()
có thể được thực hiện bằng cách sử dụng binarySearch
để có hiệu quả hơn.
Cách hiệu quả nhất để thực hiện một danh sách được sắp xếp như bạn muốn là triển khai một skiplist có thể lập chỉ mục như ở đây: Wikipedia: Skiplist có thể lập chỉ mục . Nó sẽ cho phép có các phần chèn / xóa trong O (log (n)) và sẽ cho phép có quyền truy cập được lập chỉ mục cùng một lúc. Và nó cũng sẽ cho phép trùng lặp.
Skiplist là một thứ khá thú vị và, tôi muốn nói, cấu trúc dữ liệu bị đánh giá thấp. Thật không may, không có triển khai skiplist được lập chỉ mục trong thư viện cơ sở Java, nhưng bạn có thể sử dụng một trong các triển khai nguồn mở hoặc tự thực hiện nó. Có triển khai Skiplist thường xuyên như ConcurrentSkipListSet và ConcurrentSkipListMap
TreeSet sẽ không hoạt động vì chúng không cho phép trùng lặp cộng với việc chúng không cung cấp phương thức để tìm nạp phần tử ở vị trí cụ thể. PriorityQueue sẽ không hoạt động vì nó không cho phép tìm nạp các phần tử ở vị trí cụ thể, đây là một yêu cầu cơ bản cho danh sách. Tôi nghĩ rằng bạn cần phải thực hiện thuật toán của riêng mình để duy trì một danh sách được sắp xếp trong Java với thời gian chèn O (logn), trừ khi bạn không cần trùng lặp. Có lẽ một giải pháp có thể đang sử dụng TreeMap trong đó khóa là lớp con của mục ghi đè phương thức bằng để sao cho phép trùng lặp.
Bạn có thể thử giải quyết các tác vụ này với LambdaJ nếu bạn đang sử dụng các phiên bản trước cho java 8. Bạn có thể tìm thấy nó ở đây: http://code.google.com.vn/p/lambdaj/
Ở đây bạn có một ví dụ:
Sắp xếp lặp đi lặp lại
List<Person> sortedByAgePersons = new ArrayList<Person>(persons);
Collections.sort(sortedByAgePersons, new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return Integer.valueOf(p1.getAge()).compareTo(p2.getAge());
}
});
Sắp xếp với LambdaJ
List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge());
Tất nhiên, có loại tác động làm đẹp này trong hiệu suất (trung bình 2 lần), nhưng bạn có thể tìm thấy một mã dễ đọc hơn không?
Collections.sort(persons, (p1, p2) -> p1.getAge().compareTo(p2.getAge()));
//or
persons.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));
-(p1.getAge().compareTo(p2.getAge()))
Vấn đề với PriorityQueue là nó được sao lưu bởi một mảng đơn giản và logic lấy các phần tử theo thứ tự được thực hiện bởi "queue [2 * n + 1] và queue [2 * (n + 1)]". Nó hoạt động rất tốt nếu bạn chỉ cần kéo từ đầu, nhưng làm cho nó vô dụng nếu bạn đang cố gắng gọi .toArray trên đó vào một lúc nào đó.
Tôi giải quyết vấn đề này bằng cách sử dụng com.google.common.collect.TreeMultimap, nhưng tôi cung cấp Trình so sánh tùy chỉnh cho các giá trị, được gói trong Đơn đặt hàng, không bao giờ trả về 0.
Ví dụ. cho đôi:
private static final Ordering<Double> NoEqualOrder = Ordering.from(new Comparator<Double>() {
@Override
public int compare(Double d1, Double d2)
{
if (d1 < d2) {
return -1;
}
else {
return 1;
}
}
});
Bằng cách này, tôi nhận được các giá trị theo thứ tự khi tôi gọi .toArray () và cũng có các bản sao.
Những gì bạn muốn là một cây tìm kiếm nhị phân. Nó duy trì thứ tự được sắp xếp trong khi cung cấp quyền truy cập logarit cho các tìm kiếm, xóa và chèn (trừ khi bạn có một cây bị thoái hóa - sau đó là tuyến tính). Nó khá dễ thực hiện và thậm chí bạn có thể làm cho nó thực hiện giao diện Danh sách, nhưng sau đó việc truy cập chỉ mục trở nên phức tạp.
Cách tiếp cận thứ hai là có một ArrayList và sau đó thực hiện sắp xếp bong bóng. Bởi vì bạn đang chèn hoặc xóa một phần tử tại một thời điểm, thời gian truy cập để chèn và xóa là tuyến tính. Các tìm kiếm là hằng số truy cập logarit và chỉ mục (thời gian có thể khác nhau đối với LinkedList). Mã duy nhất bạn cần là 5, có thể là 6 dòng sắp xếp bong bóng.
Bạn có thể sử dụng Arraylist và Treemap, như bạn đã nói rằng bạn cũng muốn các giá trị lặp lại, sau đó bạn không thể sử dụng TreeSet, mặc dù nó cũng được sắp xếp, nhưng bạn phải xác định bộ so sánh.
Đối với Set, bạn có thể sử dụng Treeset. TreeSet sắp xếp các phần tử của nó trên cơ sở thứ tự tự nhiên hoặc bất kỳ thứ tự sắp xếp nào được chuyển đến So sánh cho đối tượng cụ thể đó. Đối với bản đồ, sử dụng TreeMap. TreeMap cung cấp việc sắp xếp các khóa. Để thêm một đối tượng làm khóa cho TreeMap, lớp đó sẽ triển khai giao diện có thể so sánh, từ đó buộc phải thực hiện so sánh với phương thức () có chứa định nghĩa của thứ tự sắp xếp. http://techmastertutorial.in/java-collection-impl.html
Sử dụng phương thức sort () để sắp xếp danh sách như dưới đây:
List list = new ArrayList();
//add elements to the list
Comparator comparator = new SomeComparator();
Collections.sort(list, comparator);
Để tham khảo xem liên kết: http://tutorials.jenkov.com/java-collections/sorting.html
Sử dụng TreeSet
mà đưa ra các yếu tố theo thứ tự sắp xếp. HOẶC sử dụng Collection.sort()
để phân loại bên ngoài với Comparator()
.
import java.util.TreeSet;
public class Ass3 {
TreeSet<String>str=new TreeSet<String>();
str.add("dog");
str.add("doonkey");
str.add("rat");
str.add("rabbit");
str.add("elephant");
System.out.println(str);
}
với Trình so sánh Java 8, nếu chúng tôi muốn sắp xếp danh sách thì đây là 10 thành phố đông dân nhất thế giới và chúng tôi muốn sắp xếp nó theo tên, theo báo cáo của Time. Osaka, Nhật Bản. ... Thành phố Mexico, Mexico. ... Bắc Kinh, Trung Quốc. ... São Paulo, Brazil. ... Mumbai, Ấn Độ. ... Thượng Hải, Trung Quốc. ... Delhi, Ấn Độ. ... Tokyo, Nhật Bản.
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortCityList {
/*
* Here are the 10 most populated cities in the world and we want to sort it by
* name, as reported by Time. Osaka, Japan. ... Mexico City, Mexico. ...
* Beijing, China. ... São Paulo, Brazil. ... Mumbai, India. ... Shanghai,
* China. ... Delhi, India. ... Tokyo, Japan.
*/
public static void main(String[] args) {
List<String> cities = Arrays.asList("Osaka", "Mexico City", "São Paulo", "Mumbai", "Shanghai", "Delhi",
"Tokyo");
System.out.println("Before Sorting List is:-");
System.out.println(cities);
System.out.println("--------------------------------");
System.out.println("After Use of List sort(String.CASE_INSENSITIVE_ORDER) & Sorting List is:-");
cities.sort(String.CASE_INSENSITIVE_ORDER);
System.out.println(cities);
System.out.println("--------------------------------");
System.out.println("After Use of List sort(Comparator.naturalOrder()) & Sorting List is:-");
cities.sort(Comparator.naturalOrder());
System.out.println(cities);
}
}
Sắp xếp một ArrayList theo tiêu chí do người dùng xác định.
Lớp mẫu
class Student
{
int rollno;
String name, address;
public Student(int rollno, String name, String address)
{
this.rollno = rollno;
this.name = name;
this.address = address;
}
public String toString()
{
return this.rollno + " " + this.name + " " + this.address;
}
}
Lớp sắp xếp
class Sortbyroll implements Comparator<Student>
{
public int compare(Student a, Student b)
{
return a.rollno - b.rollno;
}
}
Lớp chính
class Main
{
public static void main (String[] args)
{
ArrayList<Student> ar = new ArrayList<Student>();
ar.add(new Student(111, "bbbb", "london"));
ar.add(new Student(131, "aaaa", "nyc"));
ar.add(new Student(121, "cccc", "jaipur"));
System.out.println("Unsorted");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
Collections.sort(ar, new Sortbyroll());
System.out.println("\nSorted by rollno");
for (int i=0; i<ar.size(); i++)
System.out.println(ar.get(i));
}
}
Đầu ra
Unsorted
111 bbbb london
131 aaaa nyc
121 cccc jaipur
Sorted by rollno
111 bbbb london
121 cccc jaipur
131 aaaa nyc