Koleksi yang disortir di Jawa


161

Saya seorang pemula di Jawa. Harap sarankan koleksi mana yang dapat / harus digunakan untuk memelihara daftar yang disortir di Jawa. Saya sudah mencoba Mapdan Set, tetapi bukan itu yang saya cari.

Jawaban:


187

Ini datang sangat terlambat, tetapi ada kelas di JDK hanya untuk tujuan memiliki daftar yang diurutkan. Namanya (agak tidak sesuai dengan Sorted*antarmuka lainnya ) " java.util.PriorityQueue". Itu dapat mengurutkan Comparable<?>atau menggunakan Comparator.

Perbedaannya dengan Listpenggunaan yang diurutkan Collections.sort(...)adalah bahwa ini akan mempertahankan urutan parsial setiap saat, dengan kinerja penyisipan O (log (n)), dengan menggunakan struktur data tumpukan, sedangkan memasukkan dalam urutan ArrayListakan menjadi O (n) (yaitu, menggunakan pencarian biner dan pindah).

Namun, tidak seperti a List, PriorityQueuetidak mendukung akses yang diindeks ( get(5)), satu-satunya cara untuk mengakses item di heap adalah dengan mengeluarkannya, satu per satu (dengan demikian namanya PriorityQueue).


4
imo jawaban ini pantas mendapat lebih banyak suara karena menunjukkan satu-satunya Koleksi yang memiliki kemampuan di JDK
nimcap

96
Dari Javadoc: "Iterator yang disediakan dalam metode iterator () tidak dijamin untuk melintasi elemen PriorityQueue dalam urutan tertentu."
Christoffer Hammarström

10
@ giraff: antrian prioritas hanya itu, struktur data yang sangat efisien dalam menjaga antrian prioritas. Anda bisa polling dari depan dan mendapatkan item data dalam urutan diurutkan. Namun tumpukan tidak mempertahankan urutan total elemen secara internal (itu sebabnya mereka sangat efisien), sehingga tidak ada cara mengakses elemen dalam rangka tanpa menjalankan operasi polling.
Martin Probst

2
@ Chrispy itu sedikit tergantung pada apa yang ingin Anda lakukan dengan struktur data Anda. Tumpukan adalah cara yang efisien untuk mempertahankan daftar item dan mengambilnya secara berurutan nanti - menggunakan iterator tidak berfungsi, tetapi jika Anda memilihnya, Anda akan mendapatkan data Anda secara berurutan. Pengambilan adalah destruktif, tetapi itu masih bisa ok dalam banyak kasus. Jadi saya pikir jawaban ini bagus.
Martin Probst

4
@MartinProbst Harap perbaiki jawaban Anda dengan JELAS menunjukkan bahwa koleksi tersebut TIDAK DAPAT DIANDERASI dalam urutan yang diharapkan. Seperti yang dikatakan banyak orang, ini sangat menyesatkan!
Jorge Galvão

53

TreeMap dan TreeSet akan memberi Anda iterasi atas konten dalam urutan diurutkan. Atau Anda bisa menggunakan ArrayList dan menggunakan Collections.sort () untuk mengurutkannya. Semua kelas itu ada di java.util


27
Ada dua kelemahan utama untuk ini, yang pertama adalah bahwa suatu Set tidak dapat memiliki duplikat. Yang kedua adalah bahwa jika Anda menggunakan daftar dan Collections.sort (), Anda cenderung terus menyortir daftar besar dan memberikan kinerja yang buruk. Tentu Anda bisa menggunakan bendera 'kotor', tetapi tidak sama persis.
Jeach

Itu menimbulkan pertanyaan apakah kita memiliki opsi di Jawa yang memungkinkan duplikat dan juga memberikan pertunjukan yang mirip dengan Set (Balanced Binary Tree)
mankadnandan

32

Jika Anda ingin mempertahankan daftar yang disortir yang akan sering Anda ubah (yaitu struktur yang, selain disortir, memungkinkan duplikat dan yang unsur-unsurnya dapat direferensikan secara efisien berdasarkan indeks), kemudian gunakan ArrayList tetapi ketika Anda perlu memasukkan elemen. , selalu gunakan Collections.binarySearch () untuk menentukan indeks tempat Anda menambahkan elemen yang diberikan. Metode yang terakhir memberi tahu Anda indeks yang harus Anda sisipkan agar daftar Anda tetap terurut.


11
n sisipan akan menjadi O (n ^ 2). TreeSet akan memberi Anda kode pembersih dan O (n log n). OTOH, untuk modifikasi yang jarang, pencarian biner dari sebuah array akan lebih cepat dan menggunakan lebih sedikit memori (jadi lebih sedikit GC overhead).
Tom Hawtin - tackline

Untuk menjaga kode tetap bersih dan masih memungkinkan untuk duplikat akan cukup mudah untuk membuat kelas SortedList yang memasukkan nilai dalam urutan diurutkan.
Mr. Shiny dan New New 宇

Ini adalah jawaban yang jauh lebih baik daripada jawaban yang paling populer, imo, jika Anda dapat hidup dengan peringatan yang disebutkan oleh @ TomHawtin-tackline. Bahwa iterator berfungsi seperti yang diharapkan sangat penting untuk sebagian besar kasus.
DuneCat

Kebetulan, Tom benar dalam perilaku tertentu: satu set pohon akan memberi Anda modifikasi yang lebih efisien. Tetapi satu set pohon bukanlah daftar (dalam arti ketat memiliki elemen direferensikan oleh indeks dan memungkinkan duplikat) dan poster mengatakan mereka menginginkan daftar.
Neil Coffey

Terima kasih Neil, itu benar-benar luar biasa!
vikingsteve

31

Gunakan kelas TreeMultiset Google Guava . Jambu memiliki API koleksi spektakuler.

Salah satu masalah dengan menyediakan implementasi Daftar yang mempertahankan urutan diurutkan adalah janji yang dibuat dalam JavaDocs dari add()metode ini.


Kudos untuk saran multiset
darthtrevino

5
+1 untuk menyebutkan persyaratan yang Listselalu ditambahkan di akhir.
Roland Illig

2
Perhatikan bahwa TreeMultiSet masih tidak mengizinkan elemen duplikat (elemen yang membandingkanTo () mengembalikan 0, tidak sama dengan () memeriksa). Jika Anda cenderung menambahkan lebih dari satu item dengan prioritas yang sama, itu hanya akan meningkatkan jumlah yang ditambahkan pertama, membuang yang lain dan secara efektif menjadi implementasi Tas Penghitung yang baik.
bekce


12

Ada beberapa opsi. Saya menyarankan TreeSet jika Anda tidak ingin duplikat dan objek yang Anda sisipkan sebanding.

Anda juga dapat menggunakan metode statis dari kelas Koleksi untuk melakukan ini.

Lihat Urut Koleksi # (java.util.List) dan TreeSet untuk info lebih lanjut.



5

Apa yang saya lakukan adalah mengimplementasikan Daftar yang memiliki instance internal dengan semua metode yang didelegasikan.

 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);
}

Setelah itu, saya telah menerapkan metode baru "putOrdered" yang menyisipkan di posisi yang tepat jika elemen tidak ada atau ganti kalau-kalau ada.

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);
    }
}

Jika Anda ingin mengizinkan elemen yang berulang ulang, implementasikan saja addOrdered saja (atau keduanya).

public void addOrdered(Contact contact) {
    int index=Collections.binarySearch(this.list,contact);
    if(index<0){
        index= -(index+1);
    }
    list.add(index, contact);
}

Jika Anda ingin menghindari penyisipan, Anda juga dapat membuang dan tidak mendukung operasi pada metode "tambah" dan "set".

public boolean add(Contact object) {
    throw new UnsupportedOperationException("Use putOrdered instead");
}

... dan juga Anda harus berhati-hati dengan metode ListIterator karena mereka dapat mengubah daftar internal Anda. Dalam hal ini Anda dapat mengembalikan salinan daftar internal atau kembali melemparkan pengecualian.

public ListIterator<Contact> listIterator() {
    return (new ArrayList<Contact>(list)).listIterator();
}

Masalahnya adalah ini melanggar Listkontrak. Mungkin akan lebih baik hanya menerapkan Collection. Dan jika ContactListdiurutkan, maka contains()dapat diimplementasikan menggunakan binarySearchjuga agar lebih efisien.
Marcono1234

5

Cara paling efisien untuk mengimplementasikan daftar yang disortir seperti yang Anda inginkan adalah dengan mengimplementasikan skiplist yang dapat diindeks seperti di sini: Wikipedia: Daftar yang dapat diindeks . Itu akan memungkinkan untuk memasukkan / menghapus dalam O (log (n)) dan akan memungkinkan untuk memiliki akses yang diindeks pada saat yang sama. Dan itu juga akan memungkinkan duplikat.

Skiplist sangat menarik dan, bisa saya katakan, struktur data yang diremehkan. Sayangnya tidak ada implementasi skiplist yang diindeks di perpustakaan berbasis Java, tetapi Anda dapat menggunakan salah satu dari implementasi open source atau mengimplementasikannya sendiri. Ada implementasi Skiplist reguler seperti ConcurrentSkipListSet dan ConcurrentSkipListMap


4

TreeSet tidak akan berfungsi karena mereka tidak memperbolehkan duplikat plus mereka tidak menyediakan metode untuk mengambil elemen pada posisi tertentu. PriorityQueue tidak akan berfungsi karena tidak memungkinkan mengambil elemen pada posisi tertentu yang merupakan persyaratan dasar untuk daftar. Saya pikir Anda perlu menerapkan algoritma Anda sendiri untuk mempertahankan daftar yang diurutkan di Jawa dengan waktu penyisipan O (logn), kecuali jika Anda tidak memerlukan duplikat. Mungkin solusi bisa menggunakan TreeMap di mana kuncinya adalah subclass dari item yang menimpa metode equals sehingga duplikat diperbolehkan.


4

Menggunakan LambdaJ

Anda dapat mencoba menyelesaikan tugas-tugas ini dengan LambdaJ jika Anda menggunakan versi sebelumnya ke java 8. Anda dapat menemukannya di sini: http://code.google.com/p/lambdaj/

Di sini Anda memiliki contoh:

Urutkan berulang

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());
        }
}); 

Sortir dengan LambdaJ

List<Person> sortedByAgePersons = sort(persons, on(Person.class).getAge()); 

Tentu saja, memiliki keindahan semacam ini berdampak pada kinerja (rata-rata 2 kali), tetapi dapatkah Anda menemukan kode yang lebih mudah dibaca?

Sortir dengan java 8 menggunakan ekspresi lambda

Collections.sort(persons, (p1, p2) -> p1.getAge().compareTo(p2.getAge()));
//or
persons.sort((p1, p2) -> p1.getAge().compareTo(p2.getAge()));

Dalam contoh terakhir Anda dengan ekspresi java 8 lambda, bagaimana cara membalikkan urutan?
Rajat Shah

1
@RajatShah Saya kira Anda bisa melakukannya-(p1.getAge().compareTo(p2.getAge()))
Federico Piazza

@RajatShah senang membantu
Federico Piazza

2

Masalah dengan PriorityQueue adalah didukung oleh array sederhana, dan logika yang mengatur elemen dilakukan oleh "antrian [2 * n +1]] dan antrian [2 * (n +1)]" thingie. Ini berfungsi dengan baik jika Anda hanya menarik dari kepala, tetapi membuatnya tidak berguna jika Anda mencoba memanggil.

Saya mengatasi masalah ini dengan menggunakan com.google.common.collect.TreeMultimap, tapi saya menyediakan pembanding khusus untuk nilai-nilai, yang dibungkus dengan Pemesanan, yang tidak pernah mengembalikan 0.

ex. untuk Double:

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;
        }
    }
});

Dengan cara ini saya mendapatkan nilai-nilai secara berurutan ketika saya memanggil .toArray (), dan juga memiliki duplikat.


1

Yang Anda inginkan adalah pohon pencarian biner. Ia memelihara urutan yang diurutkan sambil menawarkan akses logaritmik untuk pencarian, pemindahan dan penyisipan (kecuali jika Anda memiliki pohon yang mengalami kemunduran - maka itu linear). Ini cukup mudah diimplementasikan dan Anda bahkan dapat membuatnya mengimplementasikan antarmuka Daftar, tetapi kemudian akses indeks menjadi rumit.

Pendekatan kedua adalah memiliki ArrayList dan kemudian implementasi semacam gelembung. Karena Anda memasukkan atau menghapus satu elemen pada suatu waktu, waktu akses untuk penyisipan dan pemindahan adalah linear. Pencarian bersifat logaritmik dan akses indeks konstan (waktu dapat berbeda untuk LinkedList). Satu-satunya kode yang Anda butuhkan adalah 5, mungkin 6 baris semacam gelembung.


1

Anda dapat menggunakan Arraylist dan Treemap, seperti yang Anda katakan Anda ingin nilai berulang juga maka Anda tidak dapat menggunakan TreeSet, meskipun itu diurutkan juga, tetapi Anda harus mendefinisikan komparator.


1

Untuk Set Anda dapat menggunakan TreeSet. TreeSet memesan elemen-elemennya berdasarkan pemesanan alami atau urutan penyortiran apa pun yang diteruskan ke Comparable untuk objek tertentu itu. Untuk peta gunakan TreeMap. TreeMap menyediakan kunci penyortiran. Untuk menambahkan objek sebagai kunci ke TreeMap bahwa kelas harus mengimplementasikan antarmuka yang sebanding yang pada gilirannya memaksa untuk menerapkan membandingkan ke () metode yang berisi definisi urutan penyortiran. http://techmastertutorial.in/java-collection-impl.html




0
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);    
}

0

dengan Java 8 Comparator, jika kita ingin mengurutkan daftar maka Berikut adalah 10 kota terpadat di dunia dan kami ingin mengurutkannya berdasarkan nama, seperti dilansir oleh Time. Osaka, Jepang. ... Kota Meksiko, Meksiko. ... Beijing, Cina. ... São Paulo, Brasil. ... Mumbai, India. ... Shanghai, Cina. ... Delhi, India. ... Tokyo, Jepang.

 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);

    }

}

0

Mengurutkan ArrayList sesuai dengan kriteria yang ditentukan pengguna.

Kelas Model

 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; 
     } 
 } 

Kelas Penyortiran

 class Sortbyroll implements Comparator<Student> 
 {         
     public int compare(Student a, Student b) 
     { 
         return a.rollno - b.rollno; 
     } 
 } 

Kelas Utama

 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)); 
     } 
 } 

Keluaran

 Unsorted
 111 bbbb london
 131 aaaa nyc
 121 cccc jaipur

 Sorted by rollno
 111 bbbb london
 121 cccc jaipur
 131 aaaa nyc
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.