Algoritma untuk menggabungkan dua array yang diurutkan dengan jumlah perbandingan minimum

24

Diberikan dua array yang diurutkan a , b tipe T dengan ukuran n dan m . Saya mencari algoritma yang menggabungkan dua array menjadi array baru (ukuran maksimum n + m).

Jika Anda memiliki operasi perbandingan yang murah, ini cukup sederhana. Cukup ambil dari array dengan elemen pertama terendah hingga satu atau kedua array benar-benar dilalui, lalu tambahkan elemen yang tersisa. Sesuatu seperti ini /programming/5958169/how-to-merge-two-sorted-arrays-into-a-sorted-array

Namun, situasinya berubah ketika membandingkan dua elemen jauh lebih mahal daripada menyalin elemen dari array sumber ke array target . Misalnya Anda mungkin memiliki array bilangan bulat presisi besar, atau string, di mana perbandingannya bisa sangat mahal. Anggap saja membuat array dan menyalin elemen adalah gratis, dan satu-satunya hal yang biayanya adalah membandingkan elemen.

Dalam hal ini, Anda ingin menggabungkan dua array dengan jumlah minimum perbandingan elemen . Berikut adalah beberapa contoh di mana Anda harus dapat melakukan jauh lebih baik daripada algoritma penggabungan sederhana:

a = [1,2,3,4, ... 1000]
b = [1001,1002,1003,1004, ... 2000]

Atau

a = [1,2,3,4, ... 1000]
b = [0,100,200, ... 1000]

Ada beberapa kasus di mana algoritma penggabungan sederhana akan optimal, seperti

a = [1,3,5,7,9,....,999]
b = [2,4,6,8,10,....,1000]

Jadi algoritma idealnya harus terdegradasi dengan anggun dan melakukan perbandingan maksimum n + m-1 jika array disisipkan, atau setidaknya tidak secara signifikan lebih buruk.

Satu hal yang harus dilakukan dengan cukup baik untuk daftar dengan perbedaan ukuran besar adalah menggunakan pencarian biner untuk memasukkan elemen-elemen dari array yang lebih kecil ke dalam array yang lebih besar. Tapi itu tidak akan menurunkan anggun jika kedua daftar memiliki ukuran yang sama dan disisipkan.

Satu-satunya hal yang tersedia untuk elemen adalah fungsi pemesanan (total), jadi skema apa pun yang membuat perbandingan lebih murah tidak mungkin.

Ada ide?

Saya telah menemukan bagian ini di Scala . Saya percaya itu optimal mengenai jumlah perbandingan, tetapi itu di luar kemampuan saya untuk membuktikannya. Setidaknya itu jauh lebih sederhana daripada hal-hal yang saya temukan dalam literatur.

Dan sejak posting asli, saya menulis posting blog tentang cara kerjanya.

Rüdiger Klaehn
sumber
2
Tidak ada cara untuk melakukan perbandingan lebih sedikit daripada di "algoritma penggabungan sederhana". Anda dapat mencoba menangani kasus tepi seperti yang pertama kali Anda sebutkan, tetapi ini akan memperburuk kasus rata-rata.
Mephy
5
@Mephy: tolong beri tahu kami dan berikan kami bukti resmi. Atau jika Anda tidak bisa, pertimbangkan untuk menghapus (atau setidaknya memperbaiki) komentar Anda.
Doc Brown
4
@DocBrown jika saya memiliki bukti formal, saya akan memberikan jawaban, bukan komentar. Bagaimanapun, ini adalah masalah linier yang cukup jelas, karena mencoba mencari solusi yang lebih baik daripada linear akan memerlukan setidaknya waktu linier.
Mephy
4
@Mephy: Saya sarankan Anda meluangkan waktu untuk membaca jawaban di bawah, dan berpikir dua kali tentang apa yang Anda tulis.
Doc Brown
4
@Mephy Sebagian besar hal-hal yang jelas ("Anda tidak dapat melakukan perkalian dalam waktu kurang dari O (n ^ 2)", "jika saya mengubah pintu mana yang saya pilih, saya tidak akan meningkatkan peluang saya untuk memenangkan harga" , "Anda bisa mengurutkan kurang dari O (n log n) ", ..) salah. Menggunakan pendekatan pencarian biner pada daftar yang lebih pendek misalnya dapat meningkatkan kasus rata-rata.
Voo

Jawaban:

31

Algoritme gabungan jenis normal - langkah menggabungkan dengan biasanya berlaku perbandingan n + m -1, di mana satu daftar berukuran n dan dan daftar lainnya berukuran m. Menggunakan algoritma ini adalah pendekatan paling sederhana untuk menggabungkan dua daftar yang diurutkan.

Jika perbandingannya terlalu mahal, Anda bisa melakukan dua hal - Anda meminimalkan jumlah perbandingan atau meminimalkan biaya perbandingan.

Mari kita fokus pada minimalisasi biaya perbandingan. Anda dan hanya Anda yang dapat memutuskan apakah data yang Anda bandingkan dapat dikuantifikasi atau tidak. Jika Anda bisa menghitungnya, yang merupakan bentuk penerapan metode hash, yang menjaga pemesanan. Misalnya, jika Data Anda dibandingkan dengan Nama, Lalu tname pertama, ... Anda dapat mengambil yang pertama ke Chars dari nama "Klaehn, Ruediger" dan mengurangi / mengukur elemen data Anda menjadi "Kl.Ru", jika Anda membandingkannya ke "Packer, The" Anda mempertahankan pemesanan "Pa.Th" - Anda sekarang dapat menerapkan algoritma perbandingan yang lebih murah, membandingkan nilai yang dikurangi. Tetapi jika Anda menemukan "Kl.Ru" yang lain, Anda sekarang memiliki nilai dekat, dan sekarang Anda mungkin beralih ke pendekatan yang lebih mahal membandingkan elemen-elemen ini.

Jika Anda dapat mengekstrak nilai kuantitatif ini dari data Anda, lebih cepat daripada membandingkannya, ini adalah hal pertama yang Anda lakukan, Anda membandingkan nilai kuantitatif atau hash terlebih dahulu. Harap diingat, bahwa nilai ini perlu dihitung hanya sekali, sehingga Anda dapat menghitungnya saat membuat elemen data.

Saya juga menyebutkan cara lain, untuk meminimalkan perbandingan Anda.

Saya telah melihat buku klasik TAOCP- Volume 3-Sorting and Searching, (hal.197-207, bagian 5.3.2) yang memiliki 10 halaman penuh tentang topik ini. Saya menemukan dua referensi untuk algoritma yang lebih cepat dari perbandingan n + m-1.

Pertama ada algoritma gabungan Hwang-Lin dan yang kedua merupakan peningkatan oleh Glenn K Manacher - keduanya dikutip oleh TAOCP serta algoritma oleh Christen, yang mendekati batas bawah dari perbandingan yang dibutuhkan, pada kondisi khusus pada panjang n dan m daftar.

Algoritma Manacher disajikan dalam Journal of ACM Vol. 26 Nomor 3 di halaman 434-440: "Peningkatan yang Signifikan pada" Algoritma Penggabungan "Hwan-Lin". daftar dengan item m dan daftar dengan item n dapat memiliki panjang yang berbeda, tetapi mereka juga harus ditentukan oleh jumlah elemen yang dikandungnya m <= n

Algoritma Hwang-Lin memecah daftar untuk bergabung, terpisah ke daftar yang lebih kecil dan mengurutkan daftar dengan membandingkan elemen pertama dari setiap sublist, dan untuk memutuskan apakah beberapa elemen dalam sublist perlu dibandingkan atau tidak. Jika daftar pertama lebih kecil dari daftar kedua, maka peluangnya tinggi, bahwa elemen berurutan dari daftar yang lebih panjang dapat ditransfer ke daftar yang dihasilkan tanpa perbandingan. Jika elemen pertama dari ist kecil lebih besar dari elemen pertama dari daftar yang lebih besar, semua elemen di depan sublist dapat disalin tanpa perbandingan.

Analisis kasus rata-rata dari aloritma penggabungan Hwang dan Lin (Vega, Frieze, Santha) di Bagian 2 Anda dapat menemukan pseudocode dari Algoritma HL. Yang jauh lebih baik daripada uraian saya. Dan Anda dapat melihat mengapa ada lebih sedikit perbandingan - algoritme menggunakan pencarian biner, untuk menemukan indeks, di mana memasukkan elemen dari daftar yang lebih pendek.

Jika daftar tidak disisipkan seperti dalam contoh terakhir Anda, Anda harus memiliki daftar yang lebih kecil dan tersisa dalam sebagian besar kasus. Ini adalah ketika algoritma HL mulai berkinerja lebih baik.

pembungkus
sumber
Terima kasih, atas komentar Anda tentang ini - saya memeriksa jawaban saya dan menemukan bahwa Knuth menghabiskan 10 halaman penuh untuk topik ini. Dan kemudian saya mengambil The JACM dari rak buku dan melihat ke sana lebih dulu. Saya akan meningkatkan jawaban saya. - Tidak perlu downvoting. Algoritma hash (quantizer) adalah ide sederhana, yang dapat diterapkan pada banyak dataset - tetapi hanya Guy yang bertanya, adalah satu-satunya yang memutuskan apakah itu berlaku untuk datanya atau tidak.
pembungkus
4
Setelah Anda meningkatkan jawaban Anda, semua orang yang menurunkan Anda akan mendapat kesempatan untuk meningkatkan semangat Anda lagi ;-)
Doc Brown
+1 untuk mencatat bahwa jika ukurannya sangat berbeda maka penggabungan standar tidak optimal.
Florian F
1

Asumsikan dua array memiliki elemen N dan M, N ≥ M, dan semua elemen berbeda.

Jika array yang diurutkan berisi elemen x dari N diikuti oleh elemen y dari M atau sebaliknya maka x dan y harus dibandingkan, jika tidak kita tidak akan tahu di mana urutannya. (Tidak mungkin ada rantai elemen lain mengatakan a, b, c di mana kita tahu bahwa x <a <b <c <y, misalnya, karena tidak ada elemen antara x dan y. Jadi x dan y pasti telah dibandingkan langsung.

Jika N> M maka dimungkinkan untuk memiliki array di mana setiap elemen M didahului dan diikuti oleh elemen N, yang berarti setidaknya diperlukan perbandingan 2M - bahkan jika Anda menggunakan algoritma pengurutan non-deterministik yang dapat membuat tebak sempurna angka mana yang harus dibandingkan. (Apa artinya: Asumsikan Anda memiliki N besar, M = 1. Pencarian biner mengambil langkah-langkah O (log2 N); algoritma non-deterministik akan menebak di antara dua elemen mana satu elemen dari array kedua berada, dan membuat dua perbandingan untuk konfirmasikan tebakannya).

gnasher729
sumber