En düşük karşılaştırma sayısıyla iki sıralı diziyi birleştirme algoritması


24

Verilen, n ve m ile T türündeki a , b dizileridir . İki diziyi yeni bir dizide birleştiren bir algoritma arıyorum (en fazla n + m boyutunda).

Ucuz bir karşılaştırma işleminiz varsa, bu oldukça basittir. Dizilerden biri veya her ikisi de tamamen geçinceye kadar, en düşük ilk elemanı olan diziyi alın, sonra kalan elemanları ekleyin. Bunun gibi bir şey /programming/5958169/how-to-merge-two-sorted-arrays-into-a-sorted-array

Ancak, iki öğeyi karşılaştırırken durum değişir, bir öğeyi kaynak diziden hedef diziye kopyalamaktan çok daha pahalıdır . Örneğin, bir karşılaştırmanın oldukça pahalı olabileceği bir dizi büyük rasgele hassas tamsayıya veya dizgelere sahip olabilirsiniz. Dizileri yaratmanın ve öğeleri kopyalamanın ücretsiz olduğunu ve maliyetleri karşılayan tek şeyin öğeleri karşılaştırmak olduğunu farz edin.

Bu durumda, iki diziyi minimum sayıda öğe karşılaştırmasıyla birleştirmek istiyorsunuz . Basit birleştirme algoritmasından çok daha iyisini yapabileceğiniz bazı örnekler:

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

Veya

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

Gibi basit birleştirme algoritması en uygun olacağı bazı durumlar vardır

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

Bu nedenle, algoritmalar ideal olarak incelikle bozunmalı ve dizilerin birleştirilmesi veya en azından önemli ölçüde daha kötü olmaması durumunda maksimum n + m-1 karşılaştırması yapmalıdır.

Büyük boyut farkına sahip listeler için oldukça iyi yapılması gereken şeylerden biri, daha küçük dizinin öğelerini daha büyük diziye eklemek için ikili arama kullanmak olacaktır. Ancak, her iki listenin de aynı boyutta ve serpiştirilmiş olması durumunda, bu incelikle bozulmaz.

Elemanlar için mevcut olan tek şey (toplam) bir sıralama işlevidir, bu nedenle karşılaştırmaları daha ucuz yapan herhangi bir şema mümkün değildir.

Herhangi bir fikir?

Scala'da bu bit ile geldim . Karşılaştırma sayısında en iyisi olduğuna inanıyorum, ancak kanıtlama yeteneğimin ötesinde. En azından literatürde bulduğum şeylerden çok daha basit.

Orijinal gönderimden bu yana, bunun nasıl çalıştığı hakkında bir blog yazısı yazdım .


2
Karşılaştırma yapmanın "basit birleştirme algoritması" ndan daha az yolu yoktur. Kenar davalarını ilk bahsettiğiniz gibi ele almaya çalışabilirsiniz, ancak bu ortalama durumu daha da kötüleştirecektir.
Mephy

5
@Mephy: Bizi aydınlatın ve bize resmi bir kanıt verin, lütfen. Veya yapamıyorsanız, yorumunuzu silmeyi (veya en azından ayrıntılandırmayı) düşünün.
Doktor Brown

4
@DocBrown resmi bir kanıtım olsaydı, bir yorum yapardım, bir cevap verirdim. Her neyse, oldukça açık bir doğrusal problem, çünkü doğrusaldan daha iyi bir çözüm bulmaya çalışmak en azından doğrusal zamana ihtiyaç duyacaktır.
Mephy

4
@Mephy: Aşağıdaki cevabı okumak için zaman ayırmanızı ve yazdıklarınız hakkında iki kez düşünmenizi öneririm.
Doc Brown

4
@Mephy Belli olan şeylerin çoğu ("O (n ^ 2) 'den daha az çarpma işlemi yapamazsınız", "" hangi kapıyı seçersem değiştirirsem bir fiyat kazanma şansımı artırmayacağım " ," O (n log n) 'den küçük değil. ", ..) yanlıştır. Örneğin, kısa listede ikili arama yaklaşımı kullanmak ortalama durumu makul derecede iyileştirmelidir.
Voo

Yanıtlar:


31

Normal birleştirme sıralama algoritması - normalde birleştirme adımı normalde n + m -1 karşılaştırması uygular; burada bir liste n boyutundadır ve diğer liste m boyutundadır. Bu algoritmayı kullanmak, iki sıralama listesini birleştirmek için en basit yaklaşımdır.

Karşılaştırmalar çok pahalıysa, iki şey yapabilirsiniz - ya karşılaştırma sayısını en aza indirirsiniz ya da karşılaştırma maliyetini en aza indirirsiniz.

Karşılaştırma maliyetinin en aza indirilmesine odaklanalım. Siz ve sadece, karşılaştırmakta olduğunuz verilerin nicelendirilip ölçülmeyeceğine karar verebilirsiniz. Bunları niceleyebilirseniz, ki bu da siparişi tutan bir karma yöntemi uygulama şeklidir. Örneğin, Verileriniz Ad ile Karşılaştırılıyorsa, İlk Adınız, ... ... ilk adınızı "Klaehn, Ruediger" adından alabilir ve veri elementini "Kl.Ru" olarak azaltabilir / ölçebilirsin. "Packer," "Pa.Th" sırasını koruduğunuzda - artık daha düşük değerleri karşılaştırarak daha ucuz bir karşılaştırma algoritması uygulayabilirsiniz. Fakat başka bir "Kl.Ru" bulursanız, şimdi yakın bir değere sahipsiniz ve şimdi bu unsurları karşılaştırarak daha pahalı bir yaklaşıma geçebilirsiniz.

Bu nicelenmiş değeri verilerinizden çıkarabilirseniz, karşılaştırmaktan daha hızlı bir şekilde yaparsanız, ilk yaptığınız şey budur, ilk önce nicelenmiş değeri veya karma değeri karşılaştırırsınız. Lütfen bu değerin yalnızca bir kez hesaplanması gerektiğini, böylece veri öğesini oluştururken hesaplayabileceğinizi unutmayın.

Karşılaştırmalarınızı en aza indirgemek için başka bir yoldan da bahsettim.

Bu konuyla ilgili 10 sayfalık tam bir kitap olan TAOCP- Volume 3-Sorting and Search, (sayfa 177-207, bölüm 5.3.2) adlı klasik kitabı inceledim. N + m-1 karşılaştırmalarından daha hızlı olan algoritmalara iki referans buldum.

Birincisi, Hwang-Lin birleştirme algoritması ve ikincisi Glenn K Manacher tarafından yapılan bir iyileştirme - ikisi de TAOCP tarafından ve ayrıca, n ve m uzunluklarındaki özel şartlarda, gerekli karşılaştırmaların alt sınırına yaklaşan Christen tarafından yapılan bir algoritma olarak gösterildi. listelerden

Manacher'ın algoritması, ACM Vol. 26 434-440. Sayfalardaki 3 Numara: "Algoritmayı Birleştiren" "Hwan-Lin" için Önemli Gelişmeler. m maddeli liste ve n maddeli liste farklı uzunluklarda olabilir, ancak m <= n içerdikleri elementlerin sayısına göre sıralanmaları gerekir.

Hwang-Lin algoritması, daha küçük listelerden ayrı olarak birleştirme listelerini kırar ve her bir alt listenin ilk öğesini karşılaştırarak listeleri sıralar ve alt listedeki bazı öğelerin karşılaştırılması gerekip gerekmediğine karar verir. İlk liste ikinci listeden daha küçükse, şans yüksektir, daha uzun listenin ardışık elemanları karşılaştırılmadan sonuç listesine aktarılabilir. Eğer küçük ist'in ilk elemanı bölünmüş büyük listenin ilk elemanından büyükse, alt listenin önündeki tüm elemanlar kıyaslanmadan kopyalanabilir.

Bölüm 2'deki Hwang ve Lin'in (Vega, Frieze, Santha) birleşme aloritmasının ortalama vaka analizini HL-Algoritmasının bir takma kodunu bulabilirsiniz. Benim tarifimden çok daha iyi. Ve neden daha az karşılaştırma olduğunu görebiliyorsunuz - algoritma, dizini bulmak için öğeyi daha kısa listeden nereye eklemek için ikili bir arama kullanıyor.

Listeler, son örneğinizdeki gibi birleştirilmezse, çoğu durumda daha küçük ve kalan daha büyük bir listeye sahip olmalısınız. Bu, HL algoritmasının daha iyi performans göstermeye başlamasıdır.


Bu konudaki yorumunuz için teşekkür ederim - cevabımı kontrol ettim ve Knuth'un bu konuda 10 sayfa harcadığını gördüm. Sonra JACM'yi kitaplığımdan alıp daha ileriye baktım. Cevabımı geliştireceğim. - Aşağı oylamaya gerek yok. Karma (niceleyici) algoritması, birçok veri setine uygulanabilen basit bir fikirdir - ancak yalnızca sordu, veriye uygulanabilir olup olmadığına karar veren tek kişidir.
packer

4
Yanıtınızı geliştirdikten sonra, oyunuzu düşüren herkes sizi tekrar affetme şansına sahip olacak ;-)
Doc Brown

Boyutların çok farklı olması durumunda standart birleştirme işleminin optimal olmadığını belirtmek için +1.
Florian F

1

İki dizinin N ve M elementlerine, N ≥ M'ye ve tüm elementlerin farklı olduğunu varsayalım.

Sıralanan dizi N'nin x'i, ardından M'nin y'sini veya tam tersini içermesi durumunda, x ve y'nin karşılaştırılması gerekir, aksi takdirde hangi sıraya ait olduğunu bilemeyiz. (A, b, c diyen başka elementlerin zinciri olamaz ki burada x <a <b <c <y olduğunu biliyoruz, çünkü x ve y arasında element yok. Dolayısıyla x ve y karşılaştırılmalıdır. direkt olarak.

Eğer N> M ise, M'nin her bir elemanının önce ve sonra bir N elementinin takip edildiği bir diziye sahip olmak mümkündür; bu, en az 2M karşılaştırmaya ihtiyaç duyulduğu anlamına gelir - bunu yapabilen deterministik olmayan bir sıralama algoritması kullanıyor olsanız bile karşılaştırmak için hangi rakamların mükemmel bir tahmin. (Bunun anlamı: N büyük, M = 1 olduğunu varsayalım. İkili arama O (log2 N) adımlarını atar; deterministik olmayan bir algoritma ikinci dizinin bir elemanının hangi iki öğeye ait olduğunu tahmin eder ve iki karşılaştırma yapar. tahminini onayla).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.