Saya perlu menghitung median berjalan:
Input: , k , vektor ( x 1 , x 2 , ... , x n ) .
Output: vektor , di mana y i adalah median dari ( x i , x i + 1 , ... , x i + k - 1 ) .
(Tidak ada kecurangan dengan perkiraan; Saya ingin memiliki solusi yang tepat. Elemen adalah bilangan bulat besar.)
Ada algoritma sepele yang memelihara pohon pencarian ukuran ; total waktu berjalan adalah O ( n log k ) . (Di sini "pohon pencarian" mengacu pada beberapa struktur data efisien yang mendukung penyisipan, penghapusan, dan kueri median dalam waktu logaritmik.)
Namun, ini agak bodoh bagi saya. Kami akan secara efektif mempelajari semua statistik pesanan dalam semua jendela ukuran , bukan hanya median. Selain itu, ini tidak terlalu menarik dalam praktiknya, terutama jika k besar (pohon pencarian besar cenderung lambat, overhead dalam konsumsi memori adalah non-sepele, efisiensi cache sering buruk, dll).
Bisakah kita melakukan sesuatu yang jauh lebih baik?
Adakah batas bawah (misalnya, apakah algoritma trivial asimtotik optimal untuk model perbandingan)?
Sunting: David Eppstein memberikan batas bawah yang bagus untuk model perbandingan! Saya bertanya-tanya apakah mungkin untuk melakukan sesuatu yang sedikit lebih pintar daripada algoritma sepele?
Sebagai contoh, dapatkah kita melakukan sesuatu di sepanjang baris ini: membagi vektor input ke bagian-bagian berukuran ; mengurutkan setiap bagian (melacak posisi asli setiap elemen); dan kemudian menggunakan vektor disortir piecewise untuk menemukan median berjalan secara efisien tanpa struktur data tambahan? Tentu saja ini masih O ( n log k ) , tetapi dalam praktiknya sortasi array cenderung jauh lebih cepat daripada mempertahankan pohon pencarian.
Sunting 2: Saeed ingin melihat beberapa alasan mengapa saya pikir penyortiran lebih cepat daripada operasi pencarian pohon. Berikut ini adalah tolok ukur yang sangat cepat, untuk , n = 10 8 :
- ≈ 8s: masing-masing menyortir vektor dengan elemen k
- ≈ 10d: menyortir vektor dengan elemen
- ≈ 80an: penyisipan & penghapusan dalam tabel hash dengan ukuran k
- ≈ 390an: penyisipan & penghapusan di pohon pencarian seimbang ukuran k
Tabel hash ada hanya untuk perbandingan; itu tidak ada gunanya langsung dalam aplikasi ini.
Singkatnya, kami memiliki hampir faktor 50 perbedaan dalam kinerja operasi pohon pencarian penyortiran vs seimbang. Dan segalanya menjadi lebih buruk jika kita meningkatkan .
(Detail teknis: Data = bilangan bulat 32-bit acak. Komputer = laptop modern tipikal. Kode tes ditulis dalam C ++, menggunakan rutin perpustakaan standar (std :: sort) dan struktur data (std :: multiset, std :: unsorted_multiset) Saya menggunakan dua kompiler C ++ yang berbeda (GCC dan Dentang), dan dua implementasi berbeda dari library standar (libstdc ++ dan libc ++) .Secara tradisional, std :: multiset telah diimplementasikan sebagai pohon merah-hitam yang sangat dioptimalkan.)
sumber
Jawaban:
Inilah batas bawah dari penyortiran. Diberikan set input dengan panjang n yang akan diurutkan, buat input untuk masalah median Anda yang sedang berjalan yang terdiri dari n - 1 salinan angka lebih kecil dari minimum S , kemudian S sendiri, lalu n - 1 salinan angka lebih besar dari maksimum S , dan atur k = 2 n - 1 . Median berjalan dari masukan ini adalah sama dengan urutan diurutkan S .S n n−1 S S n−1 S k=2n−1 S
Jadi dalam model perbandingan perhitungan, diperlukan waktu . Mungkin jika input Anda adalah bilangan bulat dan Anda menggunakan algoritma pengurutan bilangan bulat yang dapat Anda lakukan dengan lebih baik.Ω(nlogn)
sumber
Sunting: Algoritma ini sekarang disajikan di sini: http://arxiv.org/abs/1406.1717
Ya, untuk mengatasi masalah ini, cukup melakukan operasi berikut:
Sangat kasar, idenya adalah ini:
Untuk setiap :i
Berikut adalah contoh penerapan dan tolok ukur:
sumber
sumber