Java'da herhangi bir Sıralı Küme uygulaması var mı?


102

Herhangi biri Objective-C'ye aşina ise NSOrderedSet, Set olarak hareket eden ve öğelerine bir Array'inkiler olarak erişilebilen bir koleksiyon vardır.

Java'da buna benzer bir şey var mı?

Adında bir koleksiyon olduğunu duydum LinkedHashMap, ancak bir set için buna benzer bir şey bulamadım.


C ++ 'da benzer bir sorun üzerinde çalışıyorum. NSOrderedSet ile, öğelere yerleştirdiğimiz sırayla erişebilir miyiz?
Vinay

C ++ 'da işlevselliğin üstüne nasıl geçileceğini biliyor musunuz? i, e SET gibi davranır ve bir Dizi'nin öğeleri olarak erişilebilir mi?
Vinay

Yanıtlar:


123

LinkedHashSet sınıfına bir göz atın

Java belgesinden :

Tahmin edilebilir yineleme sırasına sahip Set arayüzünün karma tablosu ve bağlantılı liste uygulaması . Bu uygulama HashSet'ten farklıdır, çünkü tüm girişleri boyunca çalışan çift bağlantılı bir liste bulundurur. Bu bağlantılı liste, elemanların kümeye eklenme sırası olan yineleme sıralamasını tanımlar (ekleme sırası) . Kümeye bir öğe yeniden eklenirse ekleme siparişinin etkilenmeyeceğini unutmayın . (S.add (e), s.contains (e) çağrılmadan hemen önce true döndürdüğünde çağrılırsa, bir e öğesi bir s kümesine yeniden eklenir.).


Çok teşekkür ederim. Önemsiz görünüyor LinkedHashMapama bir şekilde bulamadım.
Uko


33

Her Kümenin bir yineleyicisi () vardır. Normal bir HashSet'in yineleyicisi oldukça rastgeledir, bir TreeSet bunu sıralama düzenine göre yapar, bir LinkedHashSet yineleyicisi ekleme sırasına göre yineler.

Bununla birlikte, LinkedHashSet'teki bir öğeyi değiştiremezsiniz. Birini kaldırıp başka bir tane ekleyebilirsiniz, ancak yeni öğe orijinalin yerine olmayacaktır. Bir LinkedHashMap'te, mevcut bir anahtar için bir değeri değiştirebilirsiniz, ardından değerler yine orijinal sırada olacaktır.

Ayrıca, belirli bir konuma yerleştiremezsiniz.

Belki yinelenenleri eklemekten kaçınmak için açık bir kontrol içeren bir ArrayList kullanmalısınız.


Belirli bir pozisyonda eleman ayarlayabilmek / alabilmek ve onları sırayla elde edebilmek istiyorum. Bunu LinkedHashSetyapması gereken dikişler . Cevabınız için teşekkürler
Uko

12

Java standart API belgesine bir göz atın . Hemen yanında LinkedHashMapbir LinkedHashSet. Ancak bunlardaki sıranın, öğelerin doğal sırası değil, ekleme sırası olduğuna dikkat edin. Ve yalnızca bu sırayla yineleme yapabilirsiniz, rastgele erişim yapamazsınız (yineleme adımlarını sayma dışında).

Ayrıca ve SortedSettarafından uygulanan bir arayüz de vardır . Her ikisi de, öğelerinin doğal sırasına göre veya a yinelemeye izin verir , ancak rasgele erişime veya ekleme sırasına izin vermez .TreeSetConcurrentSkipListSetComparator

Hem indekse göre verimli erişime sahip olan hem de belirlenen kriterleri verimli bir şekilde uygulayabilen bir veri yapısı için bir atlama listesine ihtiyacınız vardır, ancak Java Standard API'de bu işlevselliğe sahip bir uygulama yoktur, ancak birini bulmanın kolay olduğundan eminim internette.


Yorumunuzu yanlış anlıyor olabilirim, ancak Java 1.6'dan beri atlama listelerine dayalı birkaç varsayılan koleksiyon (örneğin ConcurrentSkipListSet vb.) Olduğu izlenimini edindim .
TacticalCoder

@ user988052: evet, ancak bunlar indekse göre rastgele erişim sağlamıyor (benim atlama listeleri anlayışım bunun mümkün olduğunu söylüyor), ki bu Uko'nun istediği gibi görünüyor.
Michael Borgwardt

@MichaelBorgwardt Java 6 ve sonrası, bir çift Atlama Listesi uygulaması içerir: ConcurrentSkipListMapve ConcurrentSkipListSet. Her ikisi de doğal düzene veya Karşılaştırıcıya dayalı bir sıralama sağlar. Tartıştığınız giriş sırasını veya rasgele erişimi sağlayıp sağlamadıklarını anlamıyorum.
Basil Bourque

@BasilBourque: İyi keşif ve düzenlemeler için teşekkürler. OP indekse göre erişim istedi ve şimdi ona baktığıma ve düşündüğüme göre, atlama listelerinin de aslında bu kabiliyete sahip olmadığını düşünüyorum ...
Michael Borgwardt

5

java.util.TreeSetBu araçları kullanmayı deneyin SortedSet.

Belgeden alıntı yapmak için:

"Öğeler, hangi kurucunun kullanıldığına bağlı olarak, doğal sıralamaları kullanılarak veya set oluşturma zamanında sağlanan bir Karşılaştırıcı tarafından sıralanır"

Ekle, kaldır ve içerir öğesinin bir zaman maliyeti günlüğüne (n) sahip olduğuna dikkat edin.

Setin içeriğine bir Dizi olarak erişmek istiyorsanız, bunu şu şekilde dönüştürebilirsiniz:

YourType[] array = someSet.toArray(new YourType[yourSet.size()]); 

Bu dizi, TreeSet ile aynı kriterlere göre sıralanır (doğal veya karşılaştırıcıya göre) ve çoğu durumda bu, Arrays.sort () yapmak yerine bir avantaja sahip olacaktır.


1
ArrayList ei'deki gibi sıralamaya ihtiyacım var, eğer ilk öğeyi cve sonra öğeyi koyarsam a, bir koleksiyon üzerinde ca
yinelediğimde


1

treeet sıralı bir kümedir , ancak bir öğe dizini aracılığıyla erişemezsiniz, sadece yineleyin veya başa / sona gidin.


TreeSet ile daha fazla maliyete maruz kalacaksınız. LinkedHashSet'in maliyeti daha düşüktür.
Carlos

0

Atlama listesinin ucuz bir şekilde uygulanmasından bahsediyorsak, büyük O açısından merak ediyorum, bu işlemin maliyeti nedir:

YourType [] array = someSet.toArray (new YourType [yourSet.size ()]);

Demek istediğim, her zaman tam bir dizi yaratımına takılır, bu yüzden O (n):

java.util.Arrays#copyOf

1
Bu, yineleyicinin performans özelliklerine size()ve temeldeki kümenin yöntemine bağlıdır. Yineleme genellikle O(n), boyut genellikle nerede olduğu O(1)dışında ConcurrentSkipListSetolur O(n).
Ian Roberts


0

Ayrıca BiMap, Google Guava'daki gibi İki Yönlü Haritadan bazı yardımcı programlar da edinebilirsiniz.

A ile BiMap, bir Tamsayıyı (rastgele dizin erişimi için) diğer herhangi bir nesne türüne oldukça verimli bir şekilde eşleyebilirsiniz. BiMaps bire birdir, bu nedenle herhangi bir tamsayının kendisiyle ilişkilendirilmiş en fazla bir öğesi vardır ve herhangi bir öğenin ilişkili bir tamsayı vardır. Akıllıca iki HashTableörnekle desteklenmiştir , bu nedenle neredeyse iki kat bellek kullanır, ancak Listişleme açısından bir gelenekten çok daha etkilidir, çünkü contains()(zaten var olup olmadığını kontrol etmek için bir öğe eklendiğinde çağrılır) sabit bir zamandır. ve HashSet's gibi paralel uyumlu çalışma , Listuygulaması ÇOK yavaştır.


0

Benzer bir problemim vardı. Tam olarak sıralı bir sete ihtiyacım yoktu, daha çok hızlı indexOf/ contains. Orada hiçbir şey bulamadığım için kendim bir tane uyguladım. İşte kod, her ikisini de uygular Setve Listtüm toplu liste işlemleri ArrayListsürümler kadar hızlı olmasa da .

feragatname: test edilmedi

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.Collection;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import static java.util.Objects.requireNonNull;

/**
 * An ArrayList that keeps an index of its content so that contains()/indexOf() are fast. Duplicate entries are
 * ignored as most other java Set's do.
 */
public class IndexedArraySet<E> extends ArrayList<E> implements Set<E> {

    public IndexedArraySet() { super(); }

    public IndexedArraySet(Iterable<E> c) {
        super();
        addAll(c);
    }

    private HashMap<E, Integer> indexMap = new HashMap<>();

    private void reindex() {
        indexMap.clear();
        int idx = 0;
        for (E item: this) {
            addToIndex(item, idx++);
        }
    }

    private E addToIndex(E e, int idx) {
        indexMap.putIfAbsent(requireNonNull(e), idx);
        return e;
    }

    @Override
    public boolean add(E e) {
        if(indexMap.putIfAbsent(requireNonNull(e), size()) != null) return false;
        super.add(e);
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return addAll((Iterable<? extends E>) c);
    }
    public boolean addAll(Iterable<? extends E> c) {
        boolean rv = false;
        for (E item: c) {
            rv |= add(item);
        }
        return rv;
    }

    @Override
    public boolean contains(Object e) {
        return indexMap.containsKey(e);
    }

    @Override

    public int indexOf(Object e) {
        if (e == null) return -1;
        Integer i = indexMap.get(e);
        return (i == null) ? -1 : i;
    }

    @Override
    public int lastIndexOf(Object e) {
        return indexOf(e);
    }

    @Override @SuppressWarnings("unchecked")
    public Object clone() {
        IndexedArraySet clone = (IndexedArraySet) super.clone();
        clone.indexMap = (HashMap) indexMap.clone();
        return clone;
    }

    @Override
    public void add(int idx, E e) {
        if(indexMap.putIfAbsent(requireNonNull(e), -1) != null) return;
        super.add(idx, e);
        reindex();
    }

    @Override
    public boolean remove(Object e) {
        boolean rv;
        try { rv = super.remove(e); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public void clear() {
        super.clear();
        indexMap.clear();
    }

    @Override
    public boolean addAll(int idx, Collection<? extends E> c) {
        boolean rv;
        try {
            for(E item : c) {
                // check uniqueness
                addToIndex(item, -1);
            }
            rv = super.addAll(idx, c);
        } finally {
            reindex();
        }
        return rv;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        boolean rv;
        try { rv = super.removeAll(c); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        boolean rv;
        try { rv = super.retainAll(c); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        boolean rv;
        try { rv = super.removeIf(filter); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public void replaceAll(final UnaryOperator<E> operator) {
        indexMap.clear();
        try {
            int duplicates = 0;
            for (int i = 0; i < size(); i++) {
                E newval = requireNonNull(operator.apply(this.get(i)));
                if(indexMap.putIfAbsent(newval, i-duplicates) == null) {
                    super.set(i-duplicates, newval);
                } else {
                    duplicates++;
                }
            }
            removeRange(size()-duplicates, size());
        } catch (Exception ex) {
            // If there's an exception the indexMap will be inconsistent
            reindex();
            throw ex;
        }

    }

    @Override
    public void sort(Comparator<? super E> c) {
        try { super.sort(c); }
        finally { reindex(); }
    }
}
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.