DFS (Depth-First Search)와 BFS (Breadth-First Search)를 사용하는 것이 언제 실용적입니까? [닫은]


345

DFS와 BFS의 차이점을 이해하고 있지만 다른 것을 사용하는 것이 더 실용적인시기에 관심이 있습니까?

누구든지 DFS가 BFS를 능가하는 방법에 대한 예를들 수 있습니까?


4
어쩌면 DFS와 BFS에 대한 전체 용어를 질문에 언급 할 수 있습니다. 사람들은 이러한 약어를 알지 못할 수도 있습니다.
Hans-Peter Störr




참고 BFS 및 DFS의 일부 응용 시나리오에 대해 언급
Yossarian42

답변:


353

검색 트리의 구조와 솔루션의 수와 위치 (일명 검색된 항목)에 따라 크게 달라집니다.

  • 솔루션이 트리의 루트에서 멀지 않다는 것을 알고 있다면 너비 우선 검색 (BFS)이 더 좋습니다.
  • 트리가 매우 깊고 솔루션이 거의없는 경우 DFS (Depth First Search)는 시간이 오래 걸리지 만 BFS가 더 빠를 수 있습니다.

  • 트리가 매우 넓은 경우 BFS에 너무 많은 메모리가 필요할 수 있으므로 완전히 비현실적 일 수 있습니다.

  • 솔루션이 빈번하지만 트리의 깊은 곳에있는 경우 BFS는 실용적이지 않을 수 있습니다.

  • 검색 트리가 매우 깊으면 어쨌든 (예를 들어 반복 심화) 깊이 우선 검색 (DFS)에 대한 검색 깊이를 제한해야합니다.

그러나 이것들은 단지 경험 법칙입니다. 아마도 실험을해야 할 것입니다.


4
AFAIK 재귀는 일반적으로 반복보다 더 많은 메모리가 필요합니다.
Marek Marczak

3
@MarekMarczak 나는 당신이 무엇을 말하고 싶은지 모르겠습니다. BFS를 반복으로 사용하는 경우-솔루션 공간을 쉽게 열거 할 수없는 경우 n + 1 레벨을 열거하기 위해 검색 트리의 n 레벨 전체를 메모리에 저장해야 할 수도 있습니다.
Hans-Peter Störr

11
@MarekMarczak DFS의 반복 버전은 스택을 사용합니다. 재귀와 반복은 완전히 별개의 주제입니다.
클린트 Deygoo

염두에 두었던 또 다른 경우 : BFS는 그래프가 "무한대"인 경우 유용합니다 (필수). 예를 들어, 모든 방향으로 무한대로 확장되는 체스 판. DFS는 반환되지 않습니다. BFS는 조건이 만족스러운 경우 검색 대상을 찾도록 보장합니다.
ThePartyTurtle

157

깊이 우선 검색

깊이 우선 검색은 종종 게임 시뮬레이션 (실제 게임과 같은 상황)에 사용됩니다. 일반적인 게임에서는 몇 가지 가능한 동작 중 하나를 선택할 수 있습니다. 각 선택은 추가 선택으로 이어지고, 각 선택은 추가 선택으로 이어지고, 계속 확장되는 나무 모양의 가능성 그래프로 이어집니다.

여기에 이미지 설명을 입력하십시오

예를 들어, 체스, 틱택 토와 같은 게임에서 어떤 행동을할지 결정할 때는 정신적으로 움직임을 상상 한 다음 상대방의 가능한 반응과 반응 등을 상상할 수 있습니다. 어떤 움직임이 가장 좋은 결과를 가져 오는지를보고 무엇을해야할지 결정할 수 있습니다.

게임 트리의 일부 경로 만 승리로 이어집니다. 일부는 상대방의 승리로 이어지며, 그러한 결말에 도달하면 이전 노드로 백업하거나 역 추적하고 다른 경로를 시도해야합니다. 이러한 방식으로 성공적인 결론을 내릴 수있을 때까지 트리를 탐색합니다. 그런 다음이 경로를 따라 처음으로 이동하십시오.


너비 우선 검색

너비 우선 탐색에는 흥미로운 특성이 있습니다. 먼저 시작점에서 한 모서리 떨어진 모든 정점을 찾은 다음 두 모서리 떨어진 모든 정점을 찾습니다. 시작 정점에서 주어진 정점까지의 최단 경로를 찾으려고 할 때 유용합니다. BFS를 시작하고 지정된 정점을 찾으면 지금까지 추적 한 경로가 노드의 최단 경로임을 알 수 있습니다. 더 짧은 경로가 있으면 BFS가 이미 찾은 것입니다.

폭 우선 검색은 BitTorrent와 같은 피어 투 피어 네트워크, 인접 위치를 찾기위한 GPS 시스템, 지정된 거리에있는 사람을 찾기위한 소셜 네트워킹 사이트 등을 찾는 데 사용할 수 있습니다.


113

http://www.programmerinterview.com/index.php/data-structures/dfs-vs-bfs/의 멋진 설명

BFS의 예

다음은 BFS의 모습에 대한 예입니다. 이것은 TERUE를 ITERATIVE 접근법과 함께 사용하는 Level Order Tree Traversal과 같습니다 (대부분 RECURSION은 DFS로 끝납니다). 숫자는 노드가 BFS에서 액세스되는 순서를 나타냅니다.

여기에 이미지 설명을 입력하십시오

깊이 우선 검색에서는 루트에서 시작하여 찾고있는 노드를 찾거나 리프 노드 (자식이없는 노드)에 도달 할 때까지 가능한 한 나무의 가지 중 하나를 따릅니다. 리프 노드에 충돌하면 미 탐지 자식이있는 가장 가까운 조상에서 검색을 계속합니다.

DFS의 예

다음은 DFS의 모습에 대한 예입니다. 이진 트리의 포스트 오더 순회는 먼저 리프 레벨에서 작업을 시작한다고 생각합니다. 숫자는 DFS에서 노드에 액세스하는 순서를 나타냅니다.

여기에 이미지 설명을 입력하십시오

DFS와 BFS의 차이점

BFS와 DFS를 비교할 때 DFS의 큰 장점은 모든 하위 포인터를 각 레벨에 저장할 필요가 없기 때문에 BFS보다 메모리 요구 사항이 훨씬 적다는 것입니다. 데이터와 찾고있는 내용에 따라 DFS 또는 BFS가 유리할 수 있습니다.

예를 들어, 가계도에서 아직 살아있는 나무에서 누군가를 찾고 있다면 그 사람이 나무 아래에 있다고 가정하는 것이 안전합니다. 이것은 BFS가 마지막 레벨에 도달하는 데 시간이 오래 걸린다는 것을 의미합니다. 그러나 DFS는 목표를 더 빨리 찾을 수 있습니다. 그러나 아주 오래 전에 죽은 가족을 찾고 있다면 그 사람은 나무 꼭대기에 더 가깝습니다. 그러면 BFS는 일반적으로 DFS보다 빠릅니다. 따라서 데이터와 찾고있는 내용에 따라 장점이 달라집니다.

또 다른 예는 Facebook입니다. 친구의 친구에 대한 제안. BFS를 사용할 수있는 곳을 제안하려면 즉시 친구가 필요합니다. DFS를 사용할 수있는 가장 짧은 경로를 찾거나 순환을 감지 (재귀 사용) 할 수 있습니다.


"이진 트리에서 포스트 오더 순회"란 무엇입니까?
Kyle Delaney

8
DFS가 BFS보다 최단 경로를 더 잘 찾습니까? 나는 그것이 다른 방법이라고 생각합니다. 나는 BFS가 가장 짧은 길을 찾는다고 생각합니다. 그렇지 않습니까?
Naveen Gabriel

1
소스에 크레딧을 주었으면 더 감사했을 것입니다. 비교 부분은 Narasimha Karumanchi의 "Java에서 쉽게 데이터 구조 만들기"에서 가져옵니다.
learntogrow-growtolearn 4

물론 나는 그것을 업데이트 할 수 있지만 여기에서 아무도 감사하지 않을 것으로 예상합니다. 저처럼 가난한 기술자를 돕고 싶습니다.
Kanagavelu Sugumar

1
@KyleDelaney 사전 주문, 주문 및 주문 후 트리를 통과 할 수있는 세 가지 주문이 있습니다. 접두사 접두사와 접미사 표기법에 각각 해당합니다. 트리를 탐색 한 다음 백업 할 때 노드를 처음 방문 할 때 노드를 사전 주문한 경우, 두 번째로 주문한 경우, 마지막으로 주문한 노드 인 경우 마지막 주문한 경우. 실제로이 방법으로 트리를 직렬화 할 수 있으며, 사용한 순서를 기억하는 한 직렬화에서 트리를 재 구축 할 수 있습니다.
Dave

43

너비 우선 검색은 일반적으로 트리의 깊이가 다를 수있는 가장 좋은 방법이며 솔루션의 트리 부분 만 검색하면됩니다. 예를 들어 시작 값에서 최종 값까지의 최단 경로를 찾는 것이 BFS를 사용하기에 좋은 장소입니다.

깊이 우선 검색은 전체 트리를 검색해야 할 때 일반적으로 사용됩니다. BFS보다 (재귀를 사용하여) 구현하는 것이 더 쉽고 상태가 덜 필요합니다. BFS에서는 전체 '프론티어'를 저장해야하지만 DFS에서는 현재 요소의 부모 노드 목록 만 저장하면됩니다.


26

DFS는 BFS보다 공간 효율적이지만 불필요한 깊이로 이동할 수 있습니다.

그들의 이름은 밝힙니다 : 큰 폭 (즉, 큰 분기 인자)이 있지만 깊이가 매우 제한적인 경우 (예 : 제한된 "이동 수") DFS가 BFS보다 선호 될 수 있습니다.


IDDFS에서

DFS의 공간 효율을 결합한 덜 알려진 변형이 있지만 (누적) BFS의 레벨 순서 방문은 반복 심화 깊이 우선 검색 입니다. 이 알고리즘은 일부 노드를 다시 방문하지만 점근 적 차이의 일정한 요인에만 기여합니다.


1
더 공간 효율적일 필요는 없습니다. 예를 들어 경로 그래프를 고려하십시오.
RB

16

프로그래머 로서이 질문에 접근 할 때 한 가지 요소가 눈에.니다. 재귀를 사용 하는 경우 아직 탐색 할 노드가 포함 된 추가 데이터 구조를 유지할 필요가 없기 때문에 깊이 우선 검색 을 구현하는 것이 더 간단 합니다.

노드에 "이미 방문한"정보를 저장하는 경우 방향이없는 그래프에 대한 깊이 우선 검색은 다음과 같습니다.

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

"이미 방문한"정보를 별도의 데이터 구조에 저장하는 경우 :

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())

이것을 우선 검색과 비교하면 아직 방문하지 않은 노드 목록에 대해 별도의 데이터 구조를 유지해야합니다.



5

BFS의 경우 Facebook 예제를 고려할 수 있습니다. 다른 친구 프로필의 FB 프로필에서 친구를 추가하라는 제안을받습니다. A-> B, B-> E 및 B-> F라고 가정하면 A는 E 및 F에 대한 제안을 받게됩니다. 두 번째 레벨까지 읽으려면 BFS를 사용해야합니다. DFS는 소스에서 대상까지의 데이터를 기반으로 무언가를 예측하려는 시나리오를 기반으로합니다. 이미 체스 또는 스도쿠에 대해 언급했듯이. 여기서 내가 다른 점은 DFS가 전체 경로를 먼저 다루고 최선을 결정할 수 있기 때문에 DFS를 최단 경로로 사용해야한다고 생각합니다. 그러나 BFS는 탐욕스러운 접근 방식을 사용하므로 최단 경로처럼 보일 수 있지만 최종 결과는 다를 수 있습니다. 내 이해가 잘못되었는지 알려주세요.


이제 내 의견이 약간 늦었습니다. 그러나 가장 짧은 경로를 찾으려면 BFS를 사용해야합니다. 그러나 "DFS는 소스에서 대상까지의 데이터를 기반으로 무언가를 예측하려는 시나리오를 기반으로합니다."라는 말은 훌륭합니다. 명성!!
Oskarzito

4

일부 알고리즘은 작동하는 DFS (또는 BFS)의 특정 속성에 따라 다릅니다. 예를 들어, 2 개의 연결된 구성 요소를 찾기위한 Hopcroft 및 Tarjan 알고리즘은 DFS가 이미 방문한 각 노드가 루트에서 현재 탐색 된 노드까지의 경로에 있다는 사실을 이용합니다.


4

다음은 귀하가 요구하는 것에 대한 포괄적 인 답변입니다.

간단히 말해서 :

이름 "Breadth"에서 너비 우선 탐색 (BFS) 알고리즘은 노드의 바깥 쪽 가장자리를 통해 노드의 모든 이웃을 발견 한 다음, 바깥 쪽 가장자리를 통해 이전에 언급 한 이웃의 방문하지 않은 이웃을 모두 발견합니다. 원래 소스에서 도달 할 수있는 노드를 방문합니다 (방문되지 않은 노드 등이 남아있는 경우 계속해서 다른 오리지널 소스를 사용할 수 있음). 따라서 에지의 가중치가 균일 한 경우 노드 (원본 소스)에서 다른 노드로의 최단 경로 (있는 경우)를 찾는 데 사용할 수 있습니다.

"Depth"라는 이름의 DFS (Depth First Search) 알고리즘은 가장 최근에 발견 된 노드 x의 방문하지 않은 이웃을 바깥 쪽 가장자리를 통해 발견합니다. 노드 x에서 미 방문 이웃이없는 경우, 알고리즘 x은 노드 x가 발견 된 노드의 바깥 쪽을 통해 노드의 미 방문 이웃을 발견하기 위해 추적합니다. (방문되지 않은 노드 등이 남아 있으면 다른 원본 소스를 계속 사용할 수 있습니다).

BFS와 DFS 모두 불완전 할 수 있습니다. 예를 들어 노드의 분기 계수가 무한하거나 자원 (메모리)이 지원하기에 매우 큰 경우 (예 : 다음에 발견 할 노드를 저장하는 경우) 검색된 키가 멀리 떨어져 있어도 BFS가 완료되지 않습니다 오리지널 소스에서 약간의 가장자리. 이 무한 분기 요소는 주어진 노드에서 발견 할 무한 선택 (이웃 노드) 때문일 수 있습니다. 깊이가 무한하거나 자원 (메모리)이 지원하기에 매우 큰 경우 (예 : 다음에 발견 할 노드를 저장하는 경우), 검색된 키가 원래 소스의 세 번째 이웃 일 수 있지만 DFS는 완료되지 않습니다. 이 무한 깊이는 알고리즘이 발견 한 모든 노드에 대해 이전에 방문하지 않은 새로운 선택 (이웃 노드)이있는 상황으로 인해 발생할 수 있습니다.

따라서 BFS 및 DFS 사용시기를 결정할 수 있습니다. 관리 가능한 제한 분기 요소와 관리 가능한 제한 깊이를 처리한다고 가정합니다. 검색된 노드가 얕 으면 (예 : 원본 소스에서 일부 가장자리 이후에 도달 할 수있는 경우) BFS를 사용하는 것이 좋습니다. 반면에, 검색된 노드가 원래 소스로부터 많은 에지 후에 도달 할 수있는 경우 DFS를 사용하는 것이 좋습니다.

예를 들어, 소셜 네트워크에서 특정 사람과 비슷한 관심사를 가진 사람들을 검색하려는 경우이 사람들의 BFS를 오리지널 소스로 적용 할 수 있습니다. 대부분의 사람들은 그의 직접적인 친구 또는 친구의 친구입니다. 또는 두 개의 가장자리. 반면에 특정인과 완전히 다른 관심사를 가진 사람들을 검색하려면이 사람의 DFS를 오리지널 소스로 적용 할 수 있습니다. 왜냐하면 대부분이 사람들은 그와 매우 거리가 멀기 때문입니다. .... 즉 가장자리가 너무 많습니다.

BFS 및 DFS의 응용 프로그램은 각 검색 기능에 따라 달라질 수 있습니다. 예를 들어, 노드가있을 수있는 정보가없는 한 노드에서 다른 노드로의 도달 가능성을 확인하려는 경우 BFS (분기 요소를 관리 할 수 ​​있다고 가정) 또는 DFS (깊이를 관리 할 수 ​​있다고 가정)를 사용할 수 있습니다. 또한 두 가지 모두 그래프의 토폴로지 정렬과 같은 동일한 작업을 해결할 수 있습니다 (있는 경우). BFS를 사용하여 노드 (오리지널 소스)에서 다른 노드까지 단위 가중치 가장자리가있는 최단 경로를 찾을 수 있습니다. 반면에 DFS는 비순환 그래프에서 두 노드 사이의 가장 긴 경로를 찾는 것과 같이 심도있는 특성으로 인해 모든 선택을 다 사용하는 데 사용될 수 있습니다. 또한 DFS는 그래프에서 사이클 감지에 사용될 수 있습니다.

결국 우리는 무한 깊이와 무한 분기 요소가 있다면 IDS (Iterative Deepening Search)를 사용할 수 있습니다.


2

DFS 및 BFS의 속성에 따라 예를 들어 가장 짧은 경로를 찾고 싶을 때. 우리는 일반적으로 bfs를 사용하여 '최단'을 보장 할 수 있습니다. 그러나 dfs는 우리 가이 시점에서 올 수 있음을 보장 할 수 있으며 그 시점을 달성 할 수 있으며 '최단'을 보장 할 수는 없습니다.


2

나는 그것이 당신이 직면 한 문제에 달려 있다고 생각합니다.

  1. 간단한 그래프에서 가장 짧은 경로-> bfs
  2. 가능한 모든 결과-> dfs
  3. 그래프에서 검색 (트리로 처리, 그래프로 martix)-> dfs ....

목록 앞에 빈 줄을 추가하면 대답이 훨씬 좋아집니다.
montonero

1

깊이 우선 검색은 노드가 처리 될 때 스택을 사용하므로 DFS와 함께 역 추적이 제공됩니다. 너비 우선 검색은 스택이 아닌 대기열을 사용하여 처리되는 노드를 추적하므로 BFS에서는 역 추적 기능이 제공되지 않습니다.


1

트리 폭이 매우 크고 깊이가 낮은 경우 재귀 스택이 오버플로되지 않으므로 DFS를 사용하십시오.


0

이는 특정 경우에 BFS가 DFS보다 낫다는 것을 보여주는 좋은 예입니다. https://leetcode.com/problems/01-matrix/

올바르게 구현되면 두 솔루션 모두 현재 셀 +1보다 먼 거리의 셀을 방문해야합니다. 그러나 DFS는 비효율적이며 동일한 셀을 반복적으로 방문하여 O (n * n) 복잡성을 초래합니다.

예를 들어

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

사용되는 상황에 따라 다릅니다. 그래프를 통과하는 데 문제가있을 때마다 어떤 목적 으로든 사용합니다. 비가 중 그래프에서 최단 경로를 찾는 데 문제가 있거나 그래프가 이분법인지 확인하는 경우 BFS를 사용할 수 있습니다. 사이클 감지 문제 나 역 추적이 필요한 로직의 경우 DFS를 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.