Dijkstra'nın algoritması neden azaltma anahtarı kullanıyor?


95

Dijkstra'nın algoritması bana şu şekilde öğretildi

while pqueue is not empty:
    distance, node = pqueue.delete_min()
    if node has been visited:
        continue
    else:
        mark node as visited
    if node == target:
        break
    for each neighbor of node:
         pqueue.insert(distance + distance_to_neighbor, neighbor)

Ancak algoritma ile ilgili bazı okumalar yapıyorum ve gördüğüm birçok sürüm, ekleme yerine azaltma anahtarını kullanıyor.

Bu neden ve iki yaklaşım arasındaki farklar nelerdir?


14
Düşürücü- Lütfen bu sorunun ne olduğunu açıklayabilir misiniz? Bence gayet adil ve pek çok kişi (ben dahil) ilk olarak OP'nin Dijkstra versiyonunu azaltma tuşu versiyonu yerine tanıttı.
templatetypedef

Yanıtlar:


71

Düğümleri yeniden yerleştirmek yerine azaltma anahtarını kullanmanın nedeni, öncelik kuyruğundaki düğüm sayısını küçük tutmak, böylece toplam öncelik kuyruğu sayısını küçük tutmak ve her bir öncelik kuyruğu bakiyesinin maliyetini düşük tutmaktır.

Dijkstra'nın düğümleri yeni öncelikleriyle öncelik sırasına yeniden yerleştiren algoritmasının bir uygulamasında, grafikteki her bir m kenarı için öncelik sırasına bir düğüm eklenir. Bu, öncelik kuyruğunda m kuyruğa alma işlemleri ve kuyruktan çıkarma işlemleri olduğu anlamına gelir ve toplam çalışma süresi O e + m T d ) verir, burada T e , öncelik kuyruğuna kuyruğa girmek için gereken süredir ve T d olan öncelik kuyruğundan çıkmak için gereken süre.

Dijkstra algoritmasının azaltma anahtarını destekleyen bir uygulamasında, düğümleri tutan öncelik sırası içindeki düğümlerle başlar ve algoritmanın her adımında bir düğümü kaldırır. Bu, toplam yığın kuyruk sayısının n olduğu anlamına gelir. Her bir düğüm, kendisine gelen her kenar için potansiyel olarak bir kez çağrılan bir azaltma anahtarına sahip olacaktır, bu nedenle yapılan toplam azaltma anahtarı sayısı en fazla m'dir. Bu, (n T e + n T d + m T k ) , burada T k , azaltma tuşunu çağırmak için gereken süredir.

Peki bunun çalışma zamanı üzerinde nasıl bir etkisi var? Bu, hangi öncelik sırasını kullandığınıza bağlıdır. İşte farklı öncelik sıralarını ve farklı Dijkstra algoritma uygulamalarının genel çalışma zamanlarını gösteren hızlı bir tablo:

Queue          |  T_e   |  T_d   |  T_k   | w/o Dec-Key |   w/Dec-Key
---------------+--------+--------+--------+-------------+---------------
Binary Heap    |O(log N)|O(log N)|O(log N)| O(M log N)  |   O(M log N)
Binomial Heap  |O(log N)|O(log N)|O(log N)| O(M log N)  |   O(M log N)
Fibonacci Heap |  O(1)  |O(log N)|  O(1)  | O(M log N)  | O(M + N log N)

Gördüğünüz gibi, çoğu öncelik kuyruğu türlerinde, asimptotik çalışma zamanında gerçekten bir fark yoktur ve azaltma anahtarı sürümünün daha iyi sonuç vermesi olası değildir. Ancak, öncelik kuyruğunun Fibonacci yığın uygulamasını kullanırsanız , aslında Dijkstra'nın algoritması, azaltma anahtarını kullanırken asimptotik olarak daha verimli olacaktır.

Kısacası, azaltma anahtarı ve iyi bir öncelik kuyruğu kullanmak, Dijkstra'nın asimptotik çalışma zamanını, kuyruğa alma ve kuyruktan çıkarma yapmaya devam ederseniz mümkün olanın ötesine düşürebilir.

Bu noktanın yanı sıra, Gabow'un En Kısa Yollar Algoritması gibi bazı daha gelişmiş algoritmalar, Dijkstra'nın algoritmasını bir alt program olarak kullanır ve büyük ölçüde azaltma anahtarı uygulamasına dayanır. Geçerli mesafelerin aralığını önceden biliyorsanız, bu gerçeğe dayanarak süper verimli bir öncelik sırası oluşturabileceğiniz gerçeğini kullanırlar.

Bu yardımcı olur umarım!


1
+1: Yığını hesaba katmayı unutmuştum. Ekleme sürümünün yığınının kenar başına bir düğüme sahip olması nedeniyle, yani O (m), erişim sürelerinin O (log m) olması gerekmez mi, bu da toplam çalışma süresi O (m log m) olur? Demek istediğim, normal bir grafikte m, n ^ 2'den büyük değildir, dolayısıyla bu, O (m log n) 'ye indirgenir, ancak iki düğümün farklı ağırlıklarda birden çok kenarla birleştirilebildiği bir grafikte, m sınırsızdır (tabii ki , iki düğüm arasındaki minimum yolun yalnızca minimum kenarları kullandığını ve bunu normal bir grafiğe indirgediğini iddia edebiliriz, ancak nonce için ilginç).
rampion

2
@ rampion- Bir noktanız var, ancak genel olarak algoritmayı çalıştırmadan önce paralel kenarların azaltıldığını varsaydığım için O (log n) ve O (log m) değerlerinin çok önemli olacağını düşünmüyorum. Genellikle m'nin O (n ^ 2) olduğu varsayılır.
templatetypedef

28

2007'de, azaltma anahtarı sürümü ile ekleme sürümü kullanımı arasındaki yürütme süresindeki farklılıkları inceleyen bir makale vardı. Bkz. Http://www.cs.utexas.edu/users/shaikat/papers/TR-07-54.pdf

Temel sonuçları çoğu grafik için azaltma tuşunu kullanmak değildi. Özellikle seyrek grafikler için, azaltmasız anahtar, azaltma anahtarı sürümünden önemli ölçüde daha hızlıdır. Daha fazla ayrıntı için kağıda bakın.


7
cs.sunysb.edu/~rezaul/papers/TR-07-54.pdf bu kağıt için çalışan bir bağlantıdır.
eleanora

UYARI: bağlantılı yazıda bir hata var. Sayfa 16, işlev B.2: if k < d[u]olmalıdır if k <= d[u].
Xeverous

2

Dijkstra'yı uygulamanın iki yolu vardır: biri azaltma anahtarını destekleyen bir yığın, diğeri bunu desteklemeyen bir yığın kullanır.

Her ikisi de genel olarak geçerlidir, ancak ikincisi genellikle tercih edilir. Aşağıda, grafiğimizin köşe sayısını belirtmek için 'm' ve kenar sayısını belirtmek için 'n' kullanacağım:

Mümkün olan en kötü durum karmaşıklığını istiyorsanız, azaltma anahtarını destekleyen bir Fibonacci yığını ile devam edersiniz: güzel bir O (m + nlogn) elde edersiniz.

Ortalama durumu önemsiyorsanız, bir İkili yığın da kullanabilirsiniz: O (m + nlog (m / n) logn) elde edersiniz. Kanıt burada , 99/100. Sayfalar. Grafik yoğunsa (m >> n), hem bu hem de önceki grafik O (m) eğilimindedir.

Onları gerçek grafiklerde çalıştırırsanız ne olacağını bilmek istiyorsanız , Mark Meketon'un cevabında önerdiği gibi bu makaleyi kontrol edebilirsiniz .

Deney sonuçlarının göstereceği şey, "daha basit" bir yığının çoğu durumda en iyi sonuçları vereceğidir.

Aslında, bir azaltma anahtarı kullanan uygulamalar arasında Dijkstra, basit bir İkili yığın veya bir Eşleme yığını kullanırken, Fibonacci yığını kullandığından daha iyi performans gösterir. Bunun nedeni, Fibonacci yığınlarının daha büyük sabit faktörleri içermesi ve gerçek azaltma anahtarı işlemlerinin sayısının, en kötü durumun tahmin ettiğinden çok daha küçük olma eğiliminde olmasıdır.

Benzer nedenlerden dolayı, bir azaltma anahtarı işlemini desteklemesi gerekmeyen bir yığın, daha az sabit faktörlere sahiptir ve aslında en iyi performansı gösterir. Özellikle grafik seyrekse.

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.