İlk Derinlik Arama (DFS) ve Genişlik İlk Arama (BFS) ne zaman kullanılır? [kapalı]


345

DFS ve BFS arasındaki farkları anlıyorum, ancak birini diğerinin üzerinde kullanmanın daha pratik olduğunu bilmek isterim?

Herkes DFS'nin BFS'yi nasıl koyacağına dair herhangi bir örnek verebilir mi?


4
Belki soruyu DFS ve BFS'nin tüm terimlerinden bahsedebilirsiniz - insanlar bu kısaltmaları bilmiyor olabilir.
Hans-Peter Störr




Not BFS ve DFS'in bazı uygulama senaryoları bahseder
Yossarian42

Yanıtlar:


353

Bu büyük ölçüde arama ağacının yapısına ve çözümlerin sayısına ve konumuna (yani aranan öğeler) bağlıdır.

  • Bir çözümün ağacın kökünden uzak olmadığını biliyorsanız, genişlik ilk arama (BFS) daha iyi olabilir.
  • Ağaç çok derinse ve çözümler nadirse, önce derinlik araması (DFS) çok uzun zaman alabilir, ancak BFS daha hızlı olabilir.

  • Ağaç çok genişse, bir BFS'nin çok fazla belleğe ihtiyacı olabilir, bu yüzden tamamen pratik olmayabilir.

  • Çözeltiler sık ​​sık ancak ağacın derinliklerinde ise, BFS pratik olmayabilir.

  • Arama ağacı çok derinse, yine de derinlik ilk araması (DFS) için arama derinliğini kısıtlamanız gerekir (örneğin yinelemeli derinleşme ile).

Ancak bunlar sadece temel kurallardır; muhtemelen denemeniz gerekecek.


4
AFAIK özyineleme genellikle yinelemeden daha fazla belleğe ihtiyaç duyar.
Marek Marczak

3
@MarekMarczak Ne söylemek istediğini pek göremiyorum. BFS'yi yineleme olarak alırsanız - çözüm alanı kolayca numaralandırılamıyorsa, n + 1'inci seviyeyi sıralamak için arama ağacının n'inci seviyesini bellekte saklamanız gerekebilir.
Hans-Peter Störr

11
@MarekMarczak DFS'nin yinelemeli sürümü bir yığın kullanır. Özyineleme ve Yineleme tamamen ayrı bir konudur.
Clint Deygoo

Akla gelen başka bir durum: Bir grafiğin "sonsuz" olduğu bir durumda BFS yararlıdır (gerekli). Diyelim ki, her yöne kadar sonsuzluğa uzanan bir satranç tahtası. DFS asla geri dönmeyecektir. Koşulun tatmin edici olması halinde BFS'nin aradığını bulması garanti edilir.
ThePartyTurtle

157

Derinlik öncelikli arama

Derinlik ilk aramaları genellikle oyunların simülasyonlarında (ve gerçek dünyadaki oyun benzeri durumlar) kullanılır. Tipik bir oyunda birkaç olası eylemden birini seçebilirsiniz. Her seçim, her biri daha fazla seçeneğe yol açan daha fazla seçeneğe yol açar ve böylece sürekli genişleyen ağaç şeklindeki bir olasılık grafiğine dönüşür.

resim açıklamasını buraya girin

Örneğin satranç, tic-tac-toe gibi oyunlarda, hangi hamleyi yapacağınıza karar verirken, zihinsel olarak bir hamle, sonra rakibinizin olası cevaplarını, sonra cevaplarınızı vb. Hangi hareketin en iyi sonuca götürdüğünü görerek ne yapacağınıza karar verebilirsiniz.

Bir oyun ağacındaki sadece bazı yollar kazanmanıza yol açar. Bazıları rakibinizin kazanmasına yol açar, böyle bir sona ulaştığınızda, önceki bir düğüme yedeklemeniz veya geri gitmeniz ve farklı bir yol denemeniz gerekir. Bu şekilde, başarılı bir sonuca sahip bir yol bulana kadar ağacı keşfedersiniz. Sonra bu yol boyunca ilk hareketi yaparsınız.


Genişlik ilk arama

Önce genişlik araması ilginç bir özelliğe sahiptir: İlk olarak başlangıç ​​noktasından bir kenar uzaktaki tüm köşeleri, sonra iki kenar uzaktaki tüm köşeleri vb. Bulur. Başlangıç ​​tepe noktasından belirli bir tepe noktasına en kısa yolu bulmaya çalışıyorsanız bu yararlıdır. Bir BFS başlatırsınız ve belirtilen tepe noktasını bulduğunuzda, şu ana kadar izlediğiniz yolun düğüme giden en kısa yol olduğunu bilirsiniz. Daha kısa bir yol olsaydı, BFS zaten bulmuş olurdu.

Genişlik ilk arama BitTorrent gibi eşler arası ağlarda komşu düğümleri, yakındaki yerleri bulmak için GPS sistemleri, belirtilen mesafedeki insanları bulmak için sosyal ağ siteleri ve benzeri şeyleri bulmak için kullanılabilir.


113

Http://www.programmerinterview.com/index.php/data-structures/dfs-vs-bfs/ adresinden Güzel Açıklama

BFS örneği

İşte bir BFS'nin nasıl görüneceğine bir örnek. Bu, QUEUE'yu ITERATIVE yaklaşımıyla kullanacağımız Düzey Sipariş Ağacı Geçişi gibi bir şeydir (çoğunlukla RECURSION DFS ile sonuçlanır). Sayılar, bir BFS'de düğümlere erişilme sırasını temsil eder:

resim açıklamasını buraya girin

Önce derinlemesine aramada, kökten başlarsınız ve aradığınız düğüm bulunana veya bir yaprak düğüme (çocuksuz bir düğüm) ulaşana kadar ağacın dallarından birini mümkün olduğunca takip edersiniz. Bir yaprak düğümüne çarparsanız, araştırılmamış çocuklarla en yakın atada aramaya devam edersiniz.

DFS örneği

İşte bir DFS'nin nasıl görüneceğine bir örnek. Bence ikili ağaçta post order traversal önce Yaprak seviyesinden çalışmaya başlayacaktır. Sayılar, DFS'de düğümlere erişilme sırasını temsil eder:

resim açıklamasını buraya girin

DFS ve BFS arasındaki farklar

BFS ve DFS'yi karşılaştırarak, DFS'nin en büyük avantajı, BFS'den daha düşük bellek gereksinimlerine sahip olmasıdır, çünkü tüm alt işaretçilerin her düzeyde depolanması gerekmez. Verilere ve aradığınız şeye bağlı olarak, DFS veya BFS avantajlı olabilir.

Örneğin, eğer biri ağaçta hayatta olan birini arıyorsa, bir aile ağacı göz önüne alındığında, o kişinin ağacın dibinde olacağını varsaymak güvenli olacaktır. Bu, bir BFS'nin bu son seviyeye ulaşması çok uzun zaman alacağı anlamına gelir. Bununla birlikte, bir DFS hedefi daha hızlı bulacaktır. Ancak, çok uzun zaman önce ölen bir aile üyesi arıyor olsaydı, o kişi ağacın tepesine daha yakın olurdu. Daha sonra, bir BFS genellikle bir DFS'den daha hızlı olacaktır. Bu nedenle, her ikisinin de avantajları verilere ve aradığınız şeye bağlı olarak değişir.

Bir diğer örnek Facebook; Arkadaşların Arkadaşlarına Öneriler. BFS'yi kullanabileceğimiz öneriler için derhal arkadaşlara ihtiyacımız var. En kısa yolu bulabilir veya döngüyü tespit edebilir (özyineleme kullanarak) DFS kullanabiliriz.


"İkili ağaçta post order traversal" nedir?
Kyle Delaney

8
DFS en kısa yolu BFS'den daha iyi buluyor mu? Bence tam tersi. Bence BFS en kısa yolu buluyor. Öyle değil mi?
Naveen Gabriel

1
Eğer kaynağa kredi verirdi daha fazla takdir olurdu. Karşılaştırma kısmı, Narasimha Karumanchi'nin "Java ile Kolaylaştırılan Veri Yapıları" ndan alınmıştır.
learntogrow-growtolearn 18:17

Tabii bunu güncelleyebilirsiniz, ama burada kimse takdir beklemiyor. Sadece benim gibi fakir teknisyene yardım etmek istiyorum.
Kanagavelu Sugumar

1
@KyleDelaney bir ağaçtan geçebileceğiniz üç emir vardır - ön sipariş, inorder ve postorder. Sırasıyla önek infix ve postfix gösterimlerine karşılık gelirler. Ağacı aşağı doğru hareket ettirdiğinizde ve sonra geri döndüğünüzde, bir düğümü ilk kez ziyaret ettiğinizde ön sipariş olan bir düğüm seçerseniz, ikinci kez düzensizse, son kez postorder ise. Aslında ağacı bu şekilde serileştirebilirsiniz ve kullandığınız sırayı hatırladığınız sürece ağacı serileştirmeden yeniden oluşturabilirsiniz.
Dave

43

Genişlik İlk Arama genellikle ağacın derinliği değiştiğinde en iyi yaklaşımdır ve ağacın sadece bir kısmını çözüm bulmak için aramanız gerekir. Örneğin, bir başlangıç ​​değerinden son bir değere en kısa yolu bulmak, BFS kullanmak için iyi bir yerdir.

Derinlik İlk Arama, tüm ağacı aramanız gerektiğinde yaygın olarak kullanılır. Uygulamak (özyineleme kullanarak) BFS'den daha kolaydır ve daha az durum gerektirir: BFS tüm 'sınır'ı depolamanızı gerektirirken, DFS yalnızca geçerli öğenin üst düğümlerinin listesini saklamanızı gerektirir.


26

DFS, BFS'den daha fazla yer tasarrufu sağlar, ancak gereksiz derinliklere gidebilir.

İsimleri ortaya çıkıyor: eğer büyük bir genişlik (yani büyük dallanma faktörü), ancak çok sınırlı derinlik (örn. Sınırlı sayıda "hamle") varsa, DFS BFS için daha fazla tercih edilebilir.


IDDFS'de

DFS'nin alan verimliliğini birleştiren daha az bilinen bir varyantın olduğu, ancak (cummülatif olarak) BFS'nin seviye sırası ziyaretinin, yinelenen derinleşen ilk derinlik araştırması olduğu belirtilmelidir . Bu algoritma bazı düğümleri yeniden ziyaret eder, ancak yalnızca sabit bir asimtotik fark faktörüne katkıda bulunur.


1
Her zaman daha fazla yer tasarruflu değildir. Örneğin bir yol grafiği düşünün.
RB

16

Bu soruya bir programcı olarak yaklaştığınızda, bir faktör göze çarpıyor: özyineleme kullanıyorsanız, derinlik ilk aramanın uygulanması daha kolaydır , çünkü henüz keşfedilecek düğümleri içeren ek bir veri yapısını korumanız gerekmez.

Düğümlerde “önceden ziyaret edilmiş” bilgileri saklıyorsanız, ilk önce yönlendirilmemiş bir grafik için derinlemesine arama yapın:

def dfs(origin):                               # DFS from origin:
    origin.visited = True                      # Mark the origin as visited
    for neighbor in origin.neighbors:          # Loop over the neighbors
        if not neighbor.visited: dfs(next)     # Visit each neighbor if not already visited

“Zaten ziyaret edilmiş” bilgileri ayrı bir veri yapısında saklıyorsanız:

def dfs(node, visited):                        # DFS from origin, with already-visited set:
    visited.add(node)                          # Mark the origin as visited
    for neighbor in node.neighbors:            # Loop over the neighbors
        if not neighbor in visited:            # If the neighbor hasn't been visited yet,
            dfs(node, visited)                 # then visit the neighbor
dfs(origin, set())

Bunu, ne olursa olsun, henüz ziyaret edilmemiş düğümlerin listesi için ayrı bir veri yapısı tutmanız gereken ilk genişlik aramasıyla karşılaştırın.



5

BFS için Facebook örneğini düşünebiliriz. Diğer diğer arkadaşlar profilinden FB profilinden arkadaş ekleme önerisi alıyoruz. Diyelim ki A-> B, B-> E ve B-> F iken, A, E ve F için öneri alacak. İkinci seviyeye kadar okumak için BFS kullanıyor olmalılar. DFS daha çok, kaynaktan hedefe olan verilerimize dayanarak bir şeyi tahmin etmek istediğimiz senaryolara dayanmaktadır. Daha önce de belirtildiği gibi satranç veya sudoku. Burada farklı olan şey, DFS'nin en kısa yol için kullanılması gerektiğine inanıyorum, çünkü DFS önce tüm yolu kaplayacak, sonra en iyisine karar verebiliriz. Ancak BFS'nin açgözlülük yaklaşımını kullanacağı gibi, en kısa yolu gibi görünebilir, ancak nihai sonuç farklı olabilir. Anlayışımın yanlış olup olmadığını bana bildirin.


Şimdi yorumum biraz geç. Ancak en kısa yolu bulmak için BFS kullanılmalıdır. Ancak, "DFS daha çok kaynağından hedefe sahip olduğumuz verilere dayanarak bir şey tahmin etmek istediğimiz senaryolara dayanıyor" dediniz harika bir şey! Kudos !!
Oskarzito

4

Bazı algoritmalar çalışmak için DFS'nin (veya BFS'nin) belirli özelliklerine bağlıdır. Örneğin, 2 bağlantılı bileşenleri bulmak için Hopcroft ve Tarjan algoritması, DFS tarafından karşılaşılan her ziyaret edilen düğümün kökten şu anda araştırılan düğüme giden yolda olmasından yararlanır.


4

Aşağıdakiler, sorduğunuz sorulara kapsamlı bir cevaptır.

Basit bir ifadeyle:

Genişlik İlk Arama (BFS) algoritması, "Genişlik" adından, bir düğümün tüm komşularını düğümün dış kenarlarından keşfeder, daha sonra, daha önce belirtilen komşuların görülmemiş komşularını, dış kenarlarından ve benzeri şeylere kadar keşfeder. orijinal kaynaktan erişilebilen düğümler ziyaret edilir (ziyaret edilmemiş düğümler vb. varsa devam edebilir ve başka bir orijinal kaynak alabiliriz). Bu nedenle, kenarların ağırlıkları eşitse, bir düğümden (orijinal kaynak) başka bir düğüme (varsa) en kısa yolu bulmak için kullanılabilir.

Derinlik İlk Arama (DFS) algoritması, "Derinlik" adından, en son bulunan x düğümünde görülmemiş komşuları dış kenarlarından keşfeder. X düğümünden ziyaret edilmemiş bir komşu yoksa, algoritma, orijinal düğümden erişilebilen tüm düğümler ziyaret edilinceye kadar düğümün keşfedildiği düğümün (dış kenarlarından) keşfedilmemiş komşularını keşfetmek için geri döner. (ziyaret edilmemiş düğümler vb. varsa devam edebilir ve başka bir kaynak alabiliriz).

Hem BFS hem de DFS eksik olabilir. Örneğin, bir düğümün dallanma faktörü sonsuzsa veya kaynakların (bellek) desteklemesi için çok büyükse (örneğin, bir sonraki keşfedilecek düğümleri depolarken), o zaman aranan anahtar bir mesafede olsa bile BFS tamamlanmaz orijinal kaynaktan birkaç kenar. Bu sonsuz dallanma faktörü, keşfedilecek belirli bir düğümden sonsuz seçimlerden (komşu düğümler) kaynaklanabilir. Derinlik sonsuzsa veya kaynakların (bellek) desteklemesi için çok büyükse (örneğin, bir sonraki keşfedilecek düğümleri saklarken), o zaman aranan anahtar orijinal kaynağın üçüncü komşusu olsa bile DFS tamamlanmaz. Bu sonsuz derinlik, algoritmanın keşfettiği her düğüm için, daha önce görülmemiş en az yeni bir seçimin (komşu düğüm) olduğu bir durumdan kaynaklanabilir.

Bu nedenle, BFS ve DFS'nin ne zaman kullanılacağı sonucuna varabiliriz. Varsayalım yönetilebilir sınırlı dallanma faktörü ve yönetilebilir sınırlı derinlikle uğraşıyoruz. Aranan düğüm sığsa, yani orijinal kaynaktan bazı kenarlardan sonra erişilebiliyorsa, BFS kullanmak daha iyidir. Öte yandan, aranan düğüm derinse, yani orijinal kaynaktan çok fazla kenardan sonra ulaşılabilirse, DFS kullanmak daha iyidir.

Örneğin, bir sosyal ağda, belirli bir kişinin benzer ilgi alanlarına sahip olan insanları aramak istiyorsak, bu kişiden BFS'yi özgün bir kaynak olarak uygulayabiliriz, çünkü çoğunlukla bu insanlar doğrudan arkadaşları veya arkadaşlarının arkadaşları olacaktır. veya iki kenar uzakta. Öte yandan, belirli bir kişinin tamamen farklı çıkarlarına sahip olan insanları aramak istiyorsak, bu kişiden DFS'yi özgün bir kaynak olarak uygulayabiliriz, çünkü çoğunlukla bu insanlar ondan çok uzakta olacak, yani arkadaş arkadaşının arkadaşı .... yani çok fazla kenar.

BFS ve DFS uygulamaları, her birinde arama mekanizması nedeniyle de değişebilir. Örneğin, BFS (dallanma faktörünün yönetilebilir olduğu varsayılarak) veya DFS'yi (derinliğin yönetilebilir olduğu varsayılarak), yalnızca bir düğümden diğerine ulaşılabilirliği, bu düğümün nerede olabileceğine dair hiçbir bilgiye sahip olmadığından kontrol etmek istediğimizde kullanabiliriz. Ayrıca her ikisi de (varsa) bir grafiğin topolojik sıralaması gibi aynı görevleri çözebilir. BFS, bir düğümden (orijinal kaynak) diğerine birim ağırlık kenarları olan en kısa yolu bulmak için kullanılabilir. Oysa DFS, döngüsel olmayan bir grafikteki iki düğüm arasındaki en uzun yolu keşfetmek gibi, derinlemesine gitme doğası nedeniyle tüm seçenekleri tüketmek için kullanılabilir. Ayrıca DFS, bir grafikte döngü tespiti için kullanılabilir.

Sonunda sonsuz derinlik ve sonsuz dallanma faktörünüz varsa, Yinelemeli Derinleşme Araması (IDS) kullanabiliriz.


2

DFS ve BFS özelliklerine göre. Örneğin, en kısa yolu bulmak istediğimizde. biz genellikle bfs kullanın, 'en kısa' garanti edemez. ancak dfs sadece bu noktadan gelebileceğimizi garanti edebilir, bu noktaya ulaşabilir, 'en kısa' garanti edemez.


2

Bence hangi sorunlarla karşılaştığınıza bağlı.

  1. grafik üzerinde en kısa yol -> bfs
  2. olası tüm sonuçlar -> dfs
  3. grafik üzerinde arama (ağaç tedavi, grafik olarak da martix) -> dfs ....

Listeden önce boş bir satır eklerseniz, cevap çok daha iyi görünecektir.
montonero

1

Derinlik-İlk Aramalar düğümler işlenirken bir yığın kullandığından, DFS ile geri izleme sağlanır. Önce Genişlik Aramaları, hangi düğümlerin işlendiğini takip etmek için yığın değil sıra kullandığından, BFS ile geri izleme sağlanmaz.


1

Ağaç genişliği çok büyük ve derinliği düşük olduğunda, özyineleme yığını taşmayacağından DFS'yi kullanın.


0

Bu, bazı durumlarda BFS'nin DFS'den daha iyi olduğunu göstermek için iyi bir örnektir. https://leetcode.com/problems/01-matrix/

Doğru uygulandığında, her iki çözüm de mevcut +1 hücresinden daha uzak mesafedeki hücreleri ziyaret etmelidir. Ancak DFS verimsizdir ve aynı hücreyi tekrar tekrar ziyaret ederek O (n * n) karmaşıklığına neden olur.

Örneğin,

1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
0,0,0,0,0,0,0,0,

0

Bu, kullanıldığı duruma bağlıdır. Bir grafik üzerinde gezinme sorunumuz olduğunda, bunu bir amaçla yaparız. Ağırlıksız bir grafikte en kısa yolu bulma veya bir grafiğin iki taraflı olup olmadığını bulma sorunu olduğunda, BFS kullanabiliriz. Döngü algılama problemleri veya geri izleme gerektiren herhangi bir mantık için DFS kullanabiliriz.

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.