너비 우선 대 깊이 우선


172

트리 / 그래프를 탐색 할 때 너비 우선과 깊이의 차이점은 무엇입니까? 모든 코딩 또는 의사 코드 예제가 좋습니다.


6
위키 백과를 확인 했습니까 ( 깊이 우선 , 너비 우선 )? 해당 페이지에는 많은 예쁜 그림과 함께 코드 예제가 있습니다.
rmeador

나도 그 생각을 가지고 있지만, 주어진 예제는 위키 백과에서 발견 된 것보다 약간 더 좋습니다 ....
jonnybazookatone

답변:


292

이 두 용어는 나무를 걷는 두 가지 방법을 구별합니다.

차이를 나타내는 것이 가장 쉬운 방법 일 것입니다. 나무를 생각해보십시오.

    A
   / \
  B   C
 /   / \
D   E   F

깊이 우선 탐색은 다음 순서로 노드를 방문합니다

A, B, D, C, E, F

계속 진행 하기 전에 한쪽 다리를 완전히 내려가십시오 .

우선 탐색은 다음 순서로 노드를 방문합니다

A, B, C, D, E, F

여기에서 우리는 모든 방법을 일 에 걸쳐 내려 가기 전에 각 수준.

(순서 순서에는 약간의 모호함이 있으며 트리의 각 레벨에서 "읽기"순서를 유지하는 것을 부정했습니다. 두 경우 모두 C 전후에 B에 도달 할 수 있으며 마찬가지로 F 전후에 E. 이것은 귀하의 신청에 따라 달라질 수 있습니다 ...)


의사 코드를 사용하여 두 종류의 순회를 모두 수행 할 수 있습니다.

Store the root node in Container
While (there are nodes in Container)
   N = Get the "next" node from Container
   Store all the children of N in Container
   Do some work on N

두 순회 순서의 차이점은의 선택에 Container있습니다.

  • 깊이 를 위해 먼저 스택을 사용하십시오. (재귀 구현은 콜 스택을 사용합니다 ...)
  • 대한 폭 우선 큐를 사용합니다.

재귀 구현은 다음과 같습니다

ProcessNode(Node)
   Work on the payload Node
   Foreach child of Node
      ProcessNode(child)
   /* Alternate time to work on the payload Node (see below) */

자식이없는 노드에 도달하면 재귀가 종료되므로 유한 한 비 주기적 그래프에서 종료됩니다.


이 시점에서 나는 여전히 약간의 속임수를 썼다. 약간의 영리함을 통해 다음 순서로 노드에서 작업 할 수도 있습니다 .

D, B, E, F, C, A

이것은 깊이 우선의 변형으로, 나무 위로 올라갈 때까지 각 노드에서 작업을 수행하지 않습니다. 그러나 나는 아이들을 찾기 위해 아래로 더 높은 노드를 방문 했습니다.

이 순회는 재귀 구현에서 매우 자연스럽고 (첫 번째 "작업"줄 대신 "교체 시간"줄 사용) 명시 적 스택을 사용하는 경우 에는 너무 어렵지 않지만 연습으로 남겨 두겠습니다.


@dmckee 감사합니다! "노드의 페이로드 작업"을 의미한다고 생각합니까?
batbrat

4
접두사 ( A, B, D, C, E, F-첫 번째로 제시된), 접두사 ( - D, B, A, E, C, F정렬에 사용-AVL 트리로 추가 한 다음 접두사 를 읽음) 또는 접미사 ( D, B, E, F, C, A대체 제시) 순회 를 얻도록 깊이 우선 버전을 수정할 수 있습니다 . 이름은 루트를 처리하는 위치에 따라 지정됩니다. infix는 이진 트리에만 실제로 의미가 있습니다. @ batbrat 그 이름은 ... 당신이 물어 본 이후 시간이 주어지면 아마 이미 알고있을 것입니다.
Theraot

@Theraot를 추가해 주셔서 감사합니다! 예, 이러한 종류의 순회에 대해 알고 왜 Infix가 이진 트리에만 적합한 지 알고 있습니다.
batbrat

공간이나 시간이 더 복잡한 솔루션을 결정하는 방법은 무엇입니까?
IgorGanapolsky

1
@IgorGanapolsky 원칙적으로 동일해야합니다 (결국 본질적으로 동일한 코드를 사용합니다). 더 흥미로운 질문은 캐시와 작업 세트에 어떤 영향을 미치는지에 대한 것이지만 트리의 형태에 따라 달라집니다.
dmckee --- 전

95

용어 이해하기 :

이 그림은 너비깊이 라는 단어 가 사용되는 상황에 대한 아이디어를 제공합니다 .

폭과 깊이 이해


깊이 우선 검색 :

깊이 우선 검색

  • 깊이 우선 검색 알고리즘은 가능한 한 빨리 시작점에서 멀어 지길 원하는 것처럼 작동합니다.

  • 일반적으로 a Stack를 사용 하여 막 다른 곳에 도달했을 때 어디로 가야하는지 기억합니다.

  • 따라야 할 규칙 : 첫 번째 정점 A를 Stack

    1. 가능하면 방문하지 않은 인접한 정점을 방문하여 방문한 것으로 표시 한 다음 스택에 밀어 넣습니다.
    2. 규칙 1을 따르지 않으면 가능하면 스택에서 꼭지점을 팝하십시오.
    3. 규칙 1 또는 규칙 2를 수행 할 수 없으면 완료된 것입니다.
  • 자바 코드 :

    public void searchDepthFirst() {
        // Begin at vertex 0 (A)
        vertexList[0].wasVisited = true;
        displayVertex(0);
        stack.push(0);
        while (!stack.isEmpty()) {
            int adjacentVertex = getAdjacentUnvisitedVertex(stack.peek());
            // If no such vertex
            if (adjacentVertex == -1) {
                stack.pop();
            } else {
                vertexList[adjacentVertex].wasVisited = true;
                // Do something
                stack.push(adjacentVertex);
            }
        }
        // Stack is empty, so we're done, reset flags
        for (int j = 0; j < nVerts; j++)
            vertexList[j].wasVisited = false;
    }
    
  • 응용 분야 : 깊이 우선 검색은 종종 게임 시뮬레이션 (실제 게임과 같은 상황)에 사용됩니다. 일반적인 게임에서는 몇 가지 가능한 동작 중 하나를 선택할 수 있습니다. 각 선택은 추가 선택으로 이어지고, 각 선택은 추가 선택으로 이어지고, 계속 확장되는 나무 모양의 가능성 그래프로 이어집니다.


너비 우선 검색 :

너비 우선 검색

  • 너비 우선 검색 알고리즘은 가능한 한 시작점에 가깝게 유지하기를 원합니다.
  • 이러한 종류의 검색은 일반적으로을 사용하여 구현됩니다 Queue.
  • 준수해야 할 규칙 : 정점 A를 현재 정점으로 시작
    1. 현재 정점에 인접한 다음 방문하지 않은 정점 (있는 경우)을 방문하여 표시 한 다음 대기열에 삽입합니다.
    2. 더 이상 방문하지 않은 정점이 없기 때문에 규칙 1을 수행 할 수 없으면 대기열에서 정점을 제거하고 (가능한 경우) 정점으로 만드십시오.
    3. 대기열이 비어있어 규칙 2를 수행 할 수 없으면 완료된 것입니다.
  • 자바 코드 :

    public void searchBreadthFirst() {
        vertexList[0].wasVisited = true;
        displayVertex(0);
        queue.insert(0);
        int v2;
        while (!queue.isEmpty()) {
            int v1 = queue.remove();
            // Until it has no unvisited neighbors, get one
            while ((v2 = getAdjUnvisitedVertex(v1)) != -1) {
                vertexList[v2].wasVisited = true;
                // Do something
                queue.insert(v2);
            }
        }
        // Queue is empty, so we're done, reset flags
        for (int j = 0; j < nVerts; j++) 
            vertexList[j].wasVisited = false;
    }
    
  • 응용 프로그램 : 너비 우선 검색은 먼저 시작점에서 한 모서리 떨어진 정점을 찾은 다음 두 모서리 떨어진 정점 등을 찾습니다. 시작 정점에서 주어진 정점까지의 최단 경로를 찾으려고 할 때 유용합니다.

너비 우선 검색 및 깊이 우선 검색을 이해하기에 충분해야합니다. 자세한 내용은 Robert Lafore의 훌륭한 데이터 구조 책에서 Graphs 장을 참조하십시오.


6
내가 10 번 더 투표권을 행사했으면 좋겠다.
snr

@snr 현상금을 수여;)
Snow

@ 눈에 지시 사항을 알려 주면 할 수 있습니다. 어떻게해야할지 모르겠습니다.
snr

@snr에게 감사합니다. 첫 현상금을 받게되어 기쁩니다. 고마워요
Yogesh Umesh Vaity

1
감사합니다 @ Snow, 나는 너희들이 내 대답이 유용하다는 것을 알게되어 기쁘다.
Yogesh Umesh Vaity

4

이 이진 트리가 주어지면 :

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

폭 우선 순회 :
왼쪽에서 오른쪽으로 각 레벨을 가로 질러 이동합니다.

"저는 G입니다. 제 아이들은 D입니다. 제 손자는 B, E, H, K입니다. 손자는 A, C, F입니다."

- Level 1: G 
- Level 2: D, I 
- Level 3: B, E, H, K 
- Level 4: A, C, F

Order Searched: G, D, I, B, E, H, K, A, C, F

깊이 우선 탐색 :
순회는 한 번에 전체 레벨을 가로 질러 수행되지 않습니다. 대신 순회는 먼저 나무의 깊이 (뿌리에서 잎으로)로 다이빙합니다. 그러나 단순히 위아래로하는 것보다 조금 더 복잡합니다.

세 가지 방법이 있습니다.

1) PREORDER: ROOT, LEFT, RIGHT.
You need to think of this as a recursive process:  
Grab the Root. (G)  
Then Check the Left. (It's a tree)  
Grab the Root of the Left. (D)  
Then Check the Left of D. (It's a tree)  
Grab the Root of the Left (B)  
Then Check the Left of B. (A)  
Check the Right of B. (C, and it's a leaf node. Finish B tree. Continue D tree)  
Check the Right of D. (It's a tree)  
Grab the Root. (E)  
Check the Left of E. (Nothing)  
Check the Right of E. (F, Finish D Tree. Move back to G Tree)  
Check the Right of G. (It's a tree)  
Grab the Root of I Tree. (I)  
Check the Left. (H, it's a leaf.)  
Check the Right. (K, it's a leaf. Finish G tree)  
DONE: G, D, B, A, C, E, F, I, H, K  

2) INORDER: LEFT, ROOT, RIGHT
Where the root is "in" or between the left and right child node.  
Check the Left of the G Tree. (It's a D Tree)  
Check the Left of the D Tree. (It's a B Tree)  
Check the Left of the B Tree. (A)  
Check the Root of the B Tree (B)  
Check the Right of the B Tree (C, finished B Tree!)  
Check the Right of the D Tree (It's a E Tree)  
Check the Left of the E Tree. (Nothing)  
Check the Right of the E Tree. (F, it's a leaf. Finish E Tree. Finish D Tree)...  
Onwards until...   
DONE: A, B, C, D, E, F, G, H, I, K  

3) POSTORDER: 
LEFT, RIGHT, ROOT  
DONE: A, C, B, F, E, D, H, K, I, G

사용법 (일명, 우리가 관심
을 갖는 이유) : 깊이 우선 탐색 방법에 대한 간단한 Quora 설명과 그 방법이 일반적으로 사용되는 방법을 정말 즐겼습니다
. "
"주문 순회는 [이진 검색 트리]의 사본을 만드는 데 사용됩니다. "
"사후 순회는 [이진 검색 트리]를 삭제하는 데 사용됩니다."
https://www.quora.com/What-is-the-use-of-pre-order-and-post-order-traversal-of-binary-trees-in-computing


2

코드를 바꾸는 것만으로 하나의 알고리즘 또는 다른 알고리즘을 얻을 수있는 방식으로 두 가지를 작성하는 것이 흥미로울 것이라고 생각합니다. .

저는 개인적으로 풍경을 범람하는 것으로 BFS를 해석하는 것을 좋아합니다. 저고도 지역은 먼저 침수 될 것이고, 그 후에 만 ​​고고도 지역은 따라 올 것입니다. 지리 책에서 볼 수 있듯이 가로 고도를 등각 선으로 생각하면 BFS가 물리학에서와 마찬가지로 동일한 등선 아래의 모든 영역을 동시에 채울 수 있습니다. 따라서 고도를 거리 또는 스케일 비용으로 해석하면 알고리즘에 대한 직관적 인 아이디어를 얻을 수 있습니다.

이를 염두에두고 광범위한 첫 번째 검색 뒤에있는 아이디어를 쉽게 적용하여 최소 스패닝 트리를 쉽게 찾고, 최단 경로 및 기타 여러 최소화 알고리즘을 찾을 수 있습니다.

나는 DFS에 대한 직관적 인 해석을 아직 보지 못했지만 (미로에 대한 표준 만 있지만 BFS만큼 강력하지 않고 범람하지는 않습니다), BFS는 위에서 설명한 것처럼 물리적 현상과 더 나은 상관 관계가있는 것처럼 보입니다. DFS는 합리적인 시스템 (예 : 체스 게임을하거나 미로로 나가는 것을 결정하는 사람이나 컴퓨터)의 선택 딜레마와 더 관련이 있습니다.

그래서 저에게있어 자연의 현상이 실제 전파 모델 (이동)과 가장 일치하는 것의 차이점이 있습니다.


1
비슷한 알고리즘으로 구현할 수 있습니다. DFS에는 스택을 사용하고 BFS에는 대기열을 사용하십시오. BFS의 문제점은 지금까지 본 모든 노드를 추적해야한다는 것입니다. 물리학에서의 DFS. 나는 대체 우주를 상상하고 당신은 생명을 가진 우주를 원하고, 모든 뿌리를 가진 아이들은 다른 빅뱅이고, 당신은 우주의 죽음으로가는 길을 간다. 당신은 마지막 분기로 돌아가서 모든 것이 고갈 될 때까지 또 다른 차례를 시도하고 다음 빅뱅으로 가서 새로운 우주를위한 새로운 물리 법칙을 설정합니다. 매우 직관적입니다. 좋은 문제는 체스 판에서 말과 함께 길을 찾는 것입니다.
juanmf
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.