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.

B4 tangan
sumber

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

Martin Probst
sumber
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

Michael Borgwardt
sumber
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.

Neil Coffey
sumber
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.

jtb
sumber
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

Anda menginginkan implementasi SortedSet , yaitu TreeSet .

cletus
sumber
10
Belum tentu; set tidak dapat memiliki nilai duplikat. Itu tergantung pada persyaratan OP.
Zach Langley
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.

BenM
sumber
10

Jika Anda hanya ingin mengurutkan daftar, gunakan segala jenis Daftar dan gunakan Collections.sort () . Jika Anda ingin memastikan elemen dalam daftar itu unik dan selalu diurutkan, gunakan SortedSet .

Guillaume
sumber
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();
}
Carlos Verdes
sumber
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

vladich
sumber
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.

Giuseppe
sumber
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()));
Federico Piazza
sumber
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.

Martin Klosi
sumber
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.

Jakub Zaverka
sumber
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.


sumber
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

Avi Tyagi
sumber
0

Gunakan metode sort () untuk mengurutkan daftar seperti di bawah ini:

List list = new ArrayList();

//add elements to the list

Comparator comparator = new SomeComparator();

Collections.sort(list, comparator);

Untuk referensi, lihat tautan: http://tutorials.jenkov.com/java-collections/sorting.html

Shashank Mungantiwar
sumber
0

Gunakan TreeSetyang memberi elemen dalam urutan diurutkan. ATAU gunakan Collection.sort()untuk penyortiran eksternal Comparator().

Hari
sumber
TreeSet tidak memungkinkan duplikasi elemen. Terkadang ini adalah fitur yang diinginkan, yang lain tidak. Mengingat OP mencoba set, saya kira untuk tidak
usr-local-ΕΨΗΕΛΩΝ
Jangan kejam, tunjukkan TreeMap juga: docs.oracle.com/javase/10/docs/api/java/util/TreeMap.html
Haakon Løtveit
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);    
}
Deepica SAYA
sumber
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);

    }

}
Vipul Gulhane
sumber
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
skpaik
sumber