Komputasi set perbedaan antara dua set besar

14

Aku punya dua set besar bilangan bulat dan . Setiap set memiliki sekitar satu juta entri, dan setiap entri adalah bilangan bulat positif dengan panjang maksimal 10 digit. AB

Apa algoritma terbaik untuk menghitung dan ? Dengan kata lain, bagaimana saya bisa secara efisien menghitung daftar entri yang tidak dalam dan sebaliknya? Apa yang akan menjadi struktur data terbaik untuk mewakili dua set ini, untuk membuat operasi ini efisien?ABBAAB

Pendekatan terbaik yang bisa saya lakukan adalah menyimpan dua set ini sebagai daftar yang diurutkan, dan membandingkan setiap elemen terhadap setiap elemen , secara linear. Bisakah kita berbuat lebih baik?AB

pengguna917279
sumber
Jika Anda ingin menyimpannya secara berbeda, Anda mungkin bisa mendapatkan hasil yang lebih baik.
Realz Slaw
Juga, jika Anda bersedia untuk mendapatkan hasilnya sebagai struktur data implisit; Anda bisa membuat struktur seperti itu yang meminta dua set untuk menjawab setiap pertanyaannya sendiri.
Realz Slaw
1
@ user917279 Satu poin besar adalah: Anda biasanya dapat menukar waktu persiapan / konstruksi, waktu permintaan, dan penggunaan memori satu sama lain. Apakah Anda jarang mengedit struktur, tetapi banyak bertanya? Sebaliknya? Apakah ingatan memprihatinkan atau tidak? Pertanyaan-pertanyaan semacam itu dapat dijawab dari sudut pandang praktis, dan menginformasikan pilihan konstruk "teoretis" yang "tepat".
Raphael
1
@Raphael Apakah Anda menyarankan seseorang bisa melakukan lebih baik daripada set yang terus-menerus konfluen (dalam hal kompleksitas) dengan menggunakan lebih banyak memori dan / atau menghabiskan lebih banyak waktu untuk persiapan. Saya hanya ingin tahu apakah Anda pikir itu mungkin. Saya tidak melihat tabel pencarian sebagai opsi untuk set input ukuran ini.
smossen
1
@ user917279 Jika Anda mempertimbangkan contoh dua set besar yang identik, maka setiap struktur data yang dibuat menggunakan hash-consing akan mendukung pengujian kesetaraan dalam O (1) karena struktur yang sama akan digabungkan ketika dibuat dan dengan demikian berbagi lokasi memori yang sama. Set yang terus-menerus gigih mengambil keuntungan dari hash-consing juga ketika dua struktur hampir sama. Kompleksitasnya adalah yang terbaik yang saya lihat sejauh ini untuk set yang dipesan.
mencium

Jawaban:

9

Jika Anda ingin menyimpan set dalam struktur data khusus, maka Anda mungkin bisa mendapatkan beberapa kompleksitas yang menarik.

I=O(min(|A|,|B|,|AΔB|))

Kemudian Anda dapat melakukan operasi set dan , masing-masing di perkiraan waktu. Jadi pada dasarnya, Anda mendapatkan ukuran minimum dari dua set, atau, ukuran perbedaan simetris, mana yang lebih kecil. Ini lebih baik daripada linear, jika perbedaan simetris kecil; yaitu. jika mereka memiliki persimpangan besar. Bahkan, untuk dua operasi set-perbedaan yang Anda inginkan, ini praktis peka-output, karena bersama-sama mereka membuat ukuran perbedaan simetris.AB,AB,ABAΔBO(Ilog|A|+|B|I)

Lihat Confluently Persistent Sets and Maps oleh Olle Liljenzin (2013) untuk informasi lebih lanjut.

Realz Slaw
sumber
Pohon-pohon di koran diperintahkan mencari pohon. Saya tidak akan menghitungnya sebagai struktur data yang tidak diurutkan.
smossen
@smossen cukup benar, saya mengeditnya.
Realz Slaw
6

Pemindaian linier adalah yang terbaik yang saya tahu bagaimana melakukannya, jika set diwakili sebagai daftar tertaut yang diurutkan. Waktu berjalan adalah .O(|A|+|B|)

Perhatikan bahwa Anda tidak perlu membandingkan setiap elemen terhadap setiap elemen B , berpasangan. Itu akan menyebabkan runtime O ( | A | × | B | ) , yang jauh lebih buruk. Sebagai gantinya, untuk menghitung perbedaan simetris dari dua set ini, Anda dapat menggunakan teknik yang mirip dengan operasi "penggabungan" di mergesort, yang dimodifikasi untuk menghilangkan nilai-nilai yang umum untuk kedua set.ABO(|A|×|B|)

Secara lebih rinci, Anda dapat membangun algoritme rekursif seperti berikut untuk menghitung , dengan asumsi A dan B direpresentasikan sebagai daftar tertaut dengan nilainya dalam urutan:ABAB

difference(A, B):
    if len(B)=0:
        return A # return the leftover list
    if len(A)=0:
        return B # return the leftover list
    if A[0] < B[0]:
        return [A[0]] + difference(A[1:], B)
    elsif A[0] = B[0]:
        return difference(A[1:], B[1:])  # omit the common element
    else:
        return [B[0]] + difference(A, B[1:])

Saya sudah mewakili ini dalam pseudo-Python. Jika Anda tidak membaca Python, A[0]adalah kepala dari daftar yang ditautkan A, A[1:]adalah sisa dari daftar, dan +mewakili gabungan daftar. Untuk alasan efisiensi, jika Anda bekerja dengan Python, Anda mungkin tidak ingin mengimplementasikannya persis seperti di atas - misalnya, mungkin lebih baik menggunakan generator, untuk menghindari membangun banyak daftar sementara - tetapi saya ingin menunjukkan kepada Anda ide-ide dalam bentuk sesederhana mungkin. Tujuan dari pseudo-code ini hanya untuk menggambarkan algoritma, bukan mengusulkan implementasi konkret.

Saya tidak berpikir itu mungkin untuk melakukan yang lebih baik, jika set Anda direpresentasikan sebagai daftar yang diurutkan dan Anda ingin hasilnya disediakan sebagai daftar yang diurutkan. Anda fundamental harus melihat setiap elemen dari dan B . Sketsa pembenaran informal: Jika ada elemen yang belum Anda lihat, Anda tidak bisa menampilkannya, jadi satu-satunya kasus di mana Anda dapat menghilangkan melihat elemen adalah jika Anda tahu elemen itu ada di A dan B , tetapi bagaimana Anda bisa tahu bahwa itu ada jika Anda belum melihat nilainya?ABAB

DW
sumber
fantastis, apakah kita memiliki opsi lain jika kendala bahwa set harus disimpan sebagai daftar diurutkan dihapus?
user917279
2

Jika A dan B memiliki ukuran yang sama, disjoint dan interleaved (mis. Angka ganjil dalam A dan angka genap di B), maka perbandingan berpasangan item dalam waktu linier mungkin optimal.

Jika A dan B berisi blok item yang berada tepat di salah satu dari A atau B, atau di keduanya, dimungkinkan untuk menghitung perbedaan set, penyatuan dan persimpangan dalam waktu sub linier. Sebagai contoh, jika A dan B berbeda dalam satu item, maka perbedaannya dapat dihitung dalam O (log n).

http://arxiv.org/abs/1301.3388

berbau
sumber
1
Dia mengatakan set tersebut dipesan, yang bisa berarti mereka disimpan sebagai daftar, mencari pohon atau yang lainnya. Jika data harus disimpan sebagai daftar, sangat tidak menarik untuk meminta "algoritma terbaik untuk menghitung AB" ketika tidak ada algoritma yang bisa melakukan lebih baik daripada memindai daftar dalam waktu linier (yang sudah ia temukan algoritma untuk).
smossen
1
astaga, Anda menautkan kertas yang sama dengan saya (saya, sama seperti Anda, lebih tepatnya) ...
beri
@smossen fantastis, untuk pengetahuan apa pun (?) yang saya miliki, saya mewakili mereka sebagai daftar diurutkan, tetapi dengan rendah hati akan menyambut saran lain juga.
user917279
2

nABab¯a,b

vzn
sumber
1010
1
R., melenceng. satu longdapat menyimpan 32 elemen atau 1 byte, 8 elemen. sehingga entri 1M hanya dapat disimpan dalam ~ 125K RAM! penyimpanan dapat secara signifikan lebih efisien daripada representasi lainnya tergantung pada bagaimana masalahnya diimplementasikan ...
vzn
Jadi Anda akan membutuhkan lebih dari 12MB untuk set OP tertarik. Itu pukulan semua cache (saat ini) dan akan mengerikan untuk set yang jarang. Secara khusus, membuat set kosong mendominasi semua operasi lain (untuk set yang jarang). Ngomong-ngomong Knuth mengatasi masalah ini di TAoCP.
Raphael
12MB? Hah? poster mengatakan dia hanya memiliki 2 set. poster tidak menentukan sparsity / density set-nya. ini ditunjukkan dalam jawaban saya. apakah Anda menganggap ia memiliki set yang jarang? tidak ada One Correct Answer, pendekatan ini ditunjukkan sebagai opsi alternatif yang mungkin berguna tergantung keadaan. itu tidak biasa digunakan dalam konteks ini ...
vzn
10101061010b1.15GB