Jika Anda hanya ingin mengetahui apakah setnya sama, equals
metode on AbstractSet
diimplementasikan secara kasar seperti di bawah ini:
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);
}
Perhatikan bagaimana ini mengoptimalkan kasus umum di mana:
- kedua objek itu sama
- objek lainnya bukanlah satu set sama sekali, dan
- ukuran kedua set berbeda.
Setelah itu, containsAll(...)
akan kembali false
segera setelah menemukan elemen di himpunan lain yang juga tidak ada di himpunan ini. Tetapi jika semua elemen ada di kedua set, itu perlu menguji semuanya.
Oleh karena itu, kinerja kasus terburuk terjadi ketika dua set objek yang sama tetapi tidak sama. Biaya tersebut biasanya O(N)
atau O(NlogN)
tergantung pada penerapannya this.containsAll(c)
.
Dan Anda akan mendapatkan kinerja kasus yang mendekati terburuk jika setnya besar dan hanya berbeda dalam persentase kecil elemen.
MEMPERBARUI
Jika Anda ingin menginvestasikan waktu dalam implementasi kumpulan kustom, ada pendekatan yang dapat meningkatkan kasus "hampir sama".
Idenya adalah Anda perlu menghitung sebelumnya dan menyimpan hash ke cache untuk seluruh set sehingga Anda bisa mendapatkan nilai kode hash set saat ini O(1)
. Kemudian Anda dapat membandingkan kode hash untuk dua set sebagai percepatan.
Bagaimana Anda bisa menerapkan kode hash seperti itu? Nah jika set hashcode-nya adalah:
- nol untuk satu set kosong, dan
- XOR dari semua kode hash elemen untuk himpunan yang tidak kosong,
maka Anda dapat dengan murah memperbarui kode hash cache set setiap kali Anda menambahkan atau menghapus elemen. Dalam kedua kasus, Anda cukup melakukan XOR kode hash elemen dengan kode hash set saat ini.
Tentu saja, ini mengasumsikan bahwa kode hash elemen stabil sementara elemen adalah anggota set. Ini juga mengasumsikan bahwa fungsi kode hash kelas elemen memberikan penyebaran yang baik. Itu karena ketika dua set kode hash sama, Anda masih harus kembali ke O(N)
perbandingan semua elemen.
Anda dapat mengambil ide ini lebih jauh ... setidaknya dalam teori.
PERINGATAN - Ini sangat spekulatif. Sebuah "eksperimen pikiran" jika Anda suka.
Misalkan kelas elemen set Anda memiliki metode untuk mengembalikan checksum crypto untuk elemen tersebut. Sekarang implementasikan checksum set dengan XOR checksum yang dikembalikan untuk elemen.
Apa yang dibeli ini untuk kita?
Nah, jika kita berasumsi bahwa tidak ada kesalahan yang terjadi, probabilitas bahwa dua elemen himpunan yang tidak sama memiliki checksum N-bit yang sama adalah 2 -N . Dan probabilitas 2 himpunan tidak sama memiliki checksum N-bit yang sama juga 2 -N . Jadi ide saya adalah Anda dapat menerapkan equals
sebagai:
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);
}
Berdasarkan asumsi di atas, ini hanya akan memberi Anda jawaban yang salah sekali dalam waktu 2 -N . Jika Anda membuat N cukup besar (misalnya 512 bit), kemungkinan jawaban yang salah dapat diabaikan (misalnya kira-kira 10 -150 ).
Kelemahannya adalah bahwa menghitung checksum kripto untuk elemen sangat mahal, terutama karena jumlah bit meningkat. Jadi, Anda benar-benar membutuhkan mekanisme yang efektif untuk membuat memo checksum. Dan itu bisa menjadi masalah.
Dan sisi negatif lainnya adalah bahwa probabilitas kesalahan yang bukan nol mungkin tidak dapat diterima tidak peduli seberapa kecil probabilitasnya. (Tetapi jika itu masalahnya ... bagaimana Anda menangani kasus di mana sinar kosmik membalik sedikit kritis? Atau jika secara bersamaan membalik bit yang sama dalam dua contoh sistem redundan?)