Sadece setlerin eşit olup olmadığını bilmek istiyorsanız, equals
yöntem AbstractSet
aşağıdaki gibi kabaca uygulanır:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return containsAll(c);
}
Aşağıdaki durumlarda yaygın durumları nasıl optimize ettiğini not edin:
- iki nesne aynı
- diğer nesne hiç bir küme değildir ve
- iki setin boyutları farklıdır.
Bundan sonra , diğer kümede de bu kümede olmayan bir öğe bulur bulmaz containsAll(...)
dönecektir false
. Ancak tüm öğeler her iki sette de mevcutsa, hepsini test etmesi gerekecektir.
Bu nedenle en kötü durum performansı, iki küme eşit olduğunda ancak aynı nesneler olmadığında ortaya çıkar. Bu maliyet tipik olarak O(N)
veya O(NlogN)
uygulanmasına bağlıdır this.containsAll(c)
.
Ve setler büyükse ve elementlerin sadece küçük bir yüzdesinde farklılık gösteriyorsa, en kötü duruma yakın performans elde edersiniz.
GÜNCELLEME
Özel bir set uygulamasına zaman ayırmaya istekliysen, "neredeyse aynı" durumu iyileştirebilecek bir yaklaşım var.
Buradaki fikir, setin mevcut hashcode değerini içinde alabilmeniz için tüm set için bir hash'i önceden hesaplamanız ve önbelleğe almanız gerektiğidir O(1)
. Daha sonra iki setin hashcode'unu ivme olarak karşılaştırabilirsiniz.
Böyle bir karma kodu nasıl uygulayabilirsin? Peki, set hashcode şöyle olsaydı:
- boş bir küme için sıfır ve
- Boş olmayan bir küme için tüm öğe karma kodlarının XOR'u,
daha sonra, bir öğeyi her eklediğinizde veya çıkardığınızda kümenin önbelleğe alınmış karma kodunu ucuza güncelleyebilirsiniz. Her iki durumda da, elemanın hashcode'unu mevcut set hashcode ile XOR.
Tabii ki, bu, eleman karma kodlarının kararlı olduğunu ve elemanların kümelerin üyesi olduğunu varsayar. Ayrıca, öğe sınıflarının hashcode işlevinin iyi bir yayılma sağladığını varsayar. Bunun nedeni, iki set hashcode aynı olduğunda, yine de O(N)
tüm öğelerin karşılaştırmasına geri dönmeniz gerektiğidir .
Bu fikri biraz daha ileri götürebilirsin ... en azından teoride.
UYARI - Bu oldukça spekülatiftir. İsterseniz bir "düşünce deneyi".
Set element sınıfınızın, element için bir kripto sağlama toplamı döndürmek için bir metodu olduğunu varsayalım. Şimdi, öğeler için döndürülen sağlama toplamlarını XORing yaparak kümenin sağlama toplamlarını uygulayın.
Bu bize ne kazandırır?
Biz hiçbir şeyin sinsi oluyor varsayalım buysa, herhangi iki eşitsiz seti elemanları aynı N-bitlik sağlama olması ihtimali 2 -N . Ve olasılık 2 eşit olmayan setleri de 2 aynı N-bit sağlama almaktadır sahip -N . Yani benim fikrim şu şekilde uygulayabilirsiniz equals
:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection c = (Collection) o;
if (c.size() != size())
return false;
return checksums.equals(c.checksums);
}
Yukarıdaki varsayımlar altında, bu size yalnızca 2- N seferinde bir kez yanlış cevap verecektir . N'yi yeterince büyük yaparsanız (ör. 512 bit), yanlış yanıt olasılığı önemsiz hale gelir (ör. Kabaca 10-150 ).
Olumsuz yanı, özellikle bit sayısı arttıkça, öğeler için kripto sağlama toplamlarını hesaplamanın çok pahalı olmasıdır. Dolayısıyla, sağlama toplamlarını ezberlemek için gerçekten etkili bir mekanizmaya ihtiyacınız var. Ve bu sorunlu olabilir.
Ve diğer dezavantajı, sıfır olmayan bir hata olasılığının, olasılık ne kadar küçük olursa olsun kabul edilemez olabileceğidir . (Ama durum böyleyse ... kozmik ışının kritik bir biti döndürdüğü durumu nasıl ele alırsınız? Veya yedek bir sistemin iki örneğinde aynı biti aynı anda döndürürse?)