Java'da sıralı koleksiyon


161

Java'da yeni başlayan biriyim. Lütfen Java'da sıralanmış bir listeyi korumak için hangi koleksiyonların kullanılabileceğini / kullanılması gerektiğini önerin. Denedim Mapve Setaradıklarım onlar değildi.

Yanıtlar:


187

Bu çok geç geliyor, ancak JDK'da sıralı bir listeye sahip olmak için bir sınıf var. Adı "(diğer Sorted*arayüzlerle biraz bozuk )" java.util.PriorityQueue". Comparable<?>S veya a kullanarak sıralama yapabilir Comparator.

ListSıralanmış bir kullanma ile fark Collections.sort(...), bunun bir yığın veri yapısı kullanarak O (log (n)) ekleme performansı ile her zaman kısmi bir düzen sürdürmesidir, oysa sıralanmış bir ekleme ArrayListO (n) (yani, ikili arama ve taşıma kullanarak).

Ancak, a'nın aksine List, PriorityQueuedizine alınan erişimi ( get(5)) desteklemez , bir öbekteki öğelere erişmenin tek yolu bunları teker teker çıkarmaktır (dolayısıyla ad PriorityQueue).


4
imo bu cevap JDK yeteneğine sahip tek Koleksiyon işaret beri daha fazla oy hak ediyor
nimcap

96
Javadoc'tan: "Yöntem yineleyicisinde () sağlanan Yinelemenin, PriorityQueue öğelerinin belirli bir sırada geçiş yapacağı garanti edilmez."
Christoffer Hammarström

10
@giraff: bir öncelik kuyruğu, öncelik sırasını korumada çok etkili olan bir veri yapısıdır. Önden anket oluşturabilir ve veri öğelerini sıralı olarak alabilirsiniz. Ancak yığınlar dahili olarak toplam eleman sırasını korumaz (bu yüzden çok verimlidirler), bu yüzden anket işlemini yürütmeden elemanlara erişmenin bir yolu yoktur.
Martin Probst

2
@chrispy, veri yapınızla tam olarak ne yapmak istediğinize bağlıdır. Yığınlar, öğelerin bir listesini tutmanın ve bunları daha sonra düzenli bir şekilde almanın etkili bir yoludur - yineleyiciyi kullanmak işe yaramaz, ancak ondan anket yaparsanız verilerinizi düzenli olarak alırsınız. Alım yıkıcıdır, ancak birçok durumda bu hala iyi olabilir. Bence bu cevap iyi.
Martin Probst

4
@MartinProbst Lütfen, koleksiyonun beklenen sırada DEĞİL OLMADIĞINI açıkça belirtmek için cevabınızı düzeltin. Birçoğunun söylediği gibi, bu aşırı yanıltıcı!
Jorge Galvão

53

TreeMap ve TreeSet, içerikler üzerinde sıralanmış bir sırayla yineleme sağlar. Veya bir ArrayList kullanabilir ve sıralamak için Collections.sort () yöntemini kullanabilirsiniz. Tüm bu sınıflar java.util'de


27
Bununla birlikte bunun iki büyük dezavantajı var, birincisi bir Setin kopyaları olamaz. İkincisi, bir liste ve Collections.sort () kullanırsanız, sürekli olarak büyük listeleri sıralarsınız ve düşük performans verirsiniz. Tabii bir 'kirli' bayrak kullanabilirsiniz, ama aynı değil.
10'a

Bu, Java'da tekrarlara izin veren ve Set'e benzer performanslar veren bir seçeneğimiz olup olmadığı sorusuna getiriyor (Dengeli İkili Ağaç)
mankadnandan

32

Bir korumak istiyorsanız sıralı liste , olur sık değiştirmek , daha sonra bir ArrayList kullanmak ancak (sıralanmakta olan ek olarak, izin verir, yani bir yapıya bunun elemanları verimli endeksi ile başvurulabilir çiftleri ve) ne zaman bir öğe eklemek için gerekmez , belirli bir öğeyi eklediğiniz dizini belirlemek için her zaman Collections.binarySearch () öğesini kullanın. İkinci yöntem, listenizi sıralı olarak tutmak için eklemeniz gereken dizini belirtir.


11
n uçlar O (n ^ 2) olacaktır. Bir TreeSet size daha temiz kod ve O (n log n) verir. OTOH, bir dizinin nadiren ikili araması için daha hızlı olacak ve daha az bellek kullanacaktır (böylece daha az GC ek yükü).
Tom Hawtin - taktik

Kodu temiz tutmak ve yinelemelere izin vermek için, değerleri sıralı olarak ekleyen bir SortedList sınıfı oluşturmak yeterince kolay olacaktır.
Bay Parlak ve Yeni 宇 宇

Bu, @ TomHawtin-tackline tarafından belirtilen uyarı ile yaşayabiliyorsanız, en çok oylanan cevap imo'dan daha iyi bir cevaptır. Yineleyicinin beklendiği gibi çalışması çoğu durumda çok önemlidir.
DuneCat

Bu arada, Tom bu özel davranışta haklıdır: bir ağaç seti size daha verimli değişiklikler verecektir. Ancak bir ağaç kümesi bir liste değildir (en zor anlamda elemanların indeks tarafından referanslandırılması ve kopyalara izin verilmesi) ve poster bir liste istediklerini söyledi.
Neil Coffey

Teşekkür ederim Neil, bu kanlı harika oldu!
vikingsteve

31

Google Guava'nın TreeMultiset sınıfını kullanın . Guava'nın muhteşem bir koleksiyon API'sı var.

Listenin sıralamayı koruyan bir uygulamasının sağlanmasındaki bir sorun, add()yöntemin JavaDoc'larında verilen vaattir .



5
ListSonunda bir her zaman eklenmesi gerekliliğinden bahsettiğiniz için +1 .
Roland Illig

2
TreeMultiSet öğesinin yinelenen öğelere hala izin vermediğini unutmayın (CompareTo () öğesinin eşittir () denetimi değil 0 döndürür). Aynı önceliğe sahip birden fazla öğe ekleme eğilimindeyseniz, yalnızca ilk eklenen öğenin sayısını artırarak diğerini atar ve etkili bir Sayma Çantası uygulamasıdır.
bekce


12

Birkaç seçenek var. Yinelenen istemiyorsanız ve eklediğiniz nesneler karşılaştırılabilirse TreeSet'i öneririm.

Bunu yapmak için Collections sınıfının statik yöntemlerini de kullanabilirsiniz.

Daha fazla bilgi için bkz. Collections # sort (java.util.List) ve TreeSet .



5

Yaptığım tüm yöntemler ile dahili bir örneği olan uygulamak List olduğunu.

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

Sonra, yeni bir yöntem "putOrdered" uyguladım, eğer öğe yoksa ya da mevcut olması durumunda değiştirilirse uygun pozisyonda yerleştirilir.

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

Tekrarlanan öğelere izin vermek istiyorsanız, bunun yerine addOrdered öğesini (veya her ikisini birden) uygulayın.

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

Ekleme işlemlerinden kaçınmak isterseniz, "ekleme" ve "ayarlama" yöntemlerine de atma ve desteklenmeyen işlem özel durumu atabilirsiniz.

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

... ve ayrıca dahili listenizi değiştirebilecekleri için ListIterator yöntemlerine dikkat etmelisiniz. Bu durumda dahili listenin bir kopyasını döndürebilir veya tekrar bir istisna atabilirsiniz.

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

Sorun, bunun Listsözleşmeyi ihlal etmesidir . Belki sadece uygulamak daha iyi olur Collection. Ve ContactListsıralanırsa, daha verimli olmak için de contains()kullanılarak uygulanabilir binarySearch.
Marcono1234

5

İstediğiniz gibi sıralı bir listeyi uygulamanın en etkili yolu, aşağıdaki gibi dizine eklenebilir bir listeyi uygulamak olacaktır: Wikipedia: Dizine eklenebilir listeyi atlamak . O (log (n)) içinde ekleme / çıkarma yapılmasına izin verir ve aynı zamanda dizin oluşturulmuş erişime izin verir. Ayrıca kopyalara da izin verir.

Atla listesi oldukça ilginç ve diyebilirim ki, hafife alınmış veri yapısı. Ne yazık ki Java temel kitaplığında dizinli bir atlama listesi uygulaması yoktur, ancak açık kaynak uygulamalarından birini kullanabilir veya kendiniz uygulayabilirsiniz. ConcurrentSkipListSet ve ConcurrentSkipListMap gibi düzenli Skiplist uygulamaları vardır


4

TreeSet, yinelemelere izin vermedikleri ve öğeyi belirli bir konumda getirme yöntemi sağlamadığı için çalışmaz. PriorityQueue, liste için temel bir gereklilik olan belirli bir konumda öğelerin getirilmesine izin vermediğinden çalışmaz. Yinelenenlere gerek duymadıkça, Java'da O (logn) ekleme süresiyle sıralanmış bir listeyi korumak için kendi algoritmanızı uygulamanız gerektiğini düşünüyorum. Belki bir çözüm, anahtarın eşitleme yöntemini geçersiz kılan öğenin bir alt sınıfı olduğu bir TreeMap kullanıyor olabilir, böylece kopyalara izin verilir.


4

LambdaJ Kullanımı

Java 8'in önceki sürümlerini kullanıyorsanız, bu görevleri LambdaJ ile çözmeyi deneyebilirsiniz. Http://code.google.com/p/lambdaj/

Burada bir örnek var:

Sıralı Yinelemeli

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

LambdaJ ile sırala

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

Tabii ki, bu tür bir güzellik performansa (ortalama 2 kez) etki eder, ancak daha okunabilir bir kod bulabilir misiniz?

Java 8 ile lambda ifadesini kullanarak sıralama

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

Java 8 lambda ifadesi ile son örneğinizde, bir kişi nasıl tersine çevirebilir?
Rajat Shah

1
@RajatShah Sanırım bunu yapabilirsin-(p1.getAge().compareTo(p2.getAge()))
Federico Piazza

@RajatShah yardımcı olmaktan memnun
Federico Piazza

2

PriorityQueue ile ilgili sorun, basit bir dizi tarafından yedeklenmesidir ve öğeleri sırayla alan mantık, "kuyruk [2 * n + 1] ve kuyruk [2 * (n + 1)]" nesnesi tarafından yapılır. Sadece kafadan çekerseniz harika çalışır, ancak bir noktada .toArray'ı çağırmaya çalışıyorsanız işe yaramaz hale getirir.

Com.google.common.collect.TreeMultimap kullanarak bu sorunu gidermek, ama asla 0 döndüren bir Sipariş, sarılmış değerler için özel bir karşılaştırıcı sağlar.

ex. Çift Kişilik:

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

Bu şekilde değerleri .toArray () çağırdığımda sırayla alıyorum ve ayrıca yinelemeleri var.


1

İstediğiniz ikili bir arama ağacı. Arama, kaldırma ve eklemeler için logaritmik erişim sunarken sıralı düzeni korur (yozlaşmış bir ağacınız yoksa, o zaman doğrusaldır). Uygulamak oldukça kolaydır ve hatta List arabirimini uygulamasını sağlayabilirsiniz, ancak daha sonra dizin erişimi karmaşıklaşır.

İkinci yaklaşım, bir ArrayList ve sonra bir kabarcık sıralama uygulamasına sahip olmaktır. Bir kerede bir öğe eklediğiniz veya çıkardığınız için, ekleme ve kaldırma işlemlerinin erişim süreleri doğrusaldır. Aramalar logaritmik ve dizin erişim sabitidir (LinkedList için süreler farklı olabilir). İhtiyacınız olan tek kod 5, belki 6 satır kabarcık sıralamadır.


1

Arraylist ve Treemap'i kullanabilirsiniz, tekrarlanan değerleri istediğinizi de söylediğiniz gibi, TreeSet'i de sıralayabilirsiniz, ancak sıralanmış olsa da, karşılaştırıcı tanımlamanız gerekir.


1

Set için TreeSet'i kullanabilirsiniz. TreeSet öğelerini doğal bir sıralama veya söz konusu nesne için Karşılaştırılabilir'e aktarılan herhangi bir sıralama düzeni temelinde sıralar. Harita için TreeMap kullanın. TreeMap tuşların üzerinde sıralama sağlar. Bir nesneyi TreeMap'e anahtar olarak eklemek için bu sınıf, sıralama düzeninin tanımını içeren Compare () yöntemini uygulamaya zorlayan karşılaştırılabilir bir arabirim uygulamalıdır. 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

Java 8 Karşılaştırıcısı ile, listeyi sıralamak istiyorsak, Dünyanın en kalabalık 10 şehri buradayız ve Time tarafından bildirildiği gibi ada göre sıralamak istiyoruz. Osaka, Japonya. ... Mexico City, Meksika. ... Pekin, Çin. ... São Paulo, Brezilya. ... Mumbai, Hindistan. ... Şangay, Çin. ... Delhi, Hindistan. ... Tokyo, Japonya.

 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

ArrayList'i kullanıcı tanımlı ölçütlere göre sıralama.

Model Sınıfı

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

Sınıflandırma Sınıfı

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

Ana sınıf

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

Çıktı

 Unsorted
 111 bbbb london
 131 aaaa nyc
 121 cccc jaipur

 Sorted by rollno
 111 bbbb london
 121 cccc jaipur
 131 aaaa nyc
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.