웹사이트 검색

Java의 이진 트리에 대한 너비 우선 검색(BFS) 및 깊이 우선 검색(DFS)


Breadth-First Search와 Depth-First Search는 그래프와 트리를 순회하는 두 가지 기술입니다. 이 튜토리얼에서는 주로 트리의 BFS 및 DFS 순회에 중점을 둘 것입니다.

깊이 우선 검색(DFS)이란 무엇입니까?

알고리즘은 루트 노드에서 시작한 다음 역추적하기 전에 각 분기를 탐색합니다. 스택을 사용하여 구현됩니다. 종종 코드를 작성하는 동안 역추적을 위해 재귀 스택을 사용합니다. 재귀를 사용하면 왼쪽 및 오른쪽 하위 트리도 트리이고 동일한 속성을 공유한다는 사실을 활용할 수 있습니다.

이진 트리의 경우 세 가지 유형의 DFS 순회가 있습니다.

  1. 순서대로
  2. 선주문
  3. 주문 후

너비 우선 검색(BFS)이란 무엇입니까?

이 알고리즘도 루트 노드에서 시작하여 레벨별로 모든 노드를 방문합니다. 즉, 루트 이후 루트의 모든 직계 자식을 순회합니다. 루트의 모든 직계 자식이 순회된 후 자식으로 이동하는 식입니다. BFS를 구현하기 위해 대기열을 사용합니다.

이진 트리의 경우 BFS를 따르는 Level Order Traversal이 있습니다.

Java에서 BFS 및 DFS 구현

고려 중인 트리를 다음과 같이 하십시오.

TreeNode 클래스의 구조는 다음과 같습니다.

 static class TreeNode {
        int data;
        TreeNode left, right;

        public TreeNode(int key) {
            data = key;
            left = right = null;
        }
    }

1. 선주문 순회

이진 트리의 사전 순회에서는 먼저 루트를 순회한 다음 왼쪽 하위 트리, 마지막으로 오른쪽 하위 트리를 순회합니다. 왼쪽 및 오른쪽 하위 트리도 트리라는 사실로부터 이점을 얻기 위해 이 작업을 재귀적으로 수행합니다.

선주문 순회 알고리즘은 다음과 같습니다.

  1. 루트를 통과합니다.
  2. 왼쪽 하위 트리에서 preorder()를 호출합니다.
  3. 오른쪽 하위 트리에서 preorder()를 호출합니다.

위 트리의 선주문 순회는 다음과 같습니다.

0 1 3 4 2 

자바 코드는 다음과 같습니다.

 static void preorder(TreeNode TreeNode) {
        if (TreeNode == null)
            return;

        // Traverse root
        System.out.print(TreeNode.item + "->");
        // Traverse left
        preorder(TreeNode.left);
        // Traverse right
        preorder(TreeNode.right);
    }

2. 순서 순회

이진 트리의 순회는 먼저 왼쪽 하위 트리를 순회한 다음 루트를 순회하고 마지막으로 오른쪽 하위 트리를 순회합니다.

순서 순회 알고리즘은 다음과 같습니다.

  1. 왼쪽 하위 트리에서 inorder()를 호출합니다.
  2. 루트를 통과합니다.
  3. 오른쪽 하위 트리에서 inorder()를 호출합니다.

위 트리의 순회는 다음과 같습니다.

3 1 4 0 2 

자바 코드는 다음과 같습니다.

 static void inorder(TreeNode TreeNode) {
        if (TreeNode == null)
            return;

        // Traverse left
        inorder(TreeNode.left);
        // Traverse root
        System.out.print(TreeNode.item + "->");
        // Traverse right
        inorder(TreeNode.right);
    }

3. 사후 순회

이진 트리의 후위 순회는 먼저 왼쪽 하위 트리를 순회한 다음 오른쪽 하위 트리를 순회하고 마지막으로 루트를 순회합니다.

사후 순회 알고리즘은 다음과 같습니다.

  1. 왼쪽 하위 트리에서 postorder()를 호출합니다.
  2. 오른쪽 하위 트리에서 postorder()를 호출합니다.
  3. 루트를 통과합니다.

위 트리의 사후 순회는 다음과 같습니다.

3 4 1 2 0 

자바 코드는 다음과 같습니다.

 static void postorder(TreeNode TreeNode) {
        if (TreeNode == null)
            return;

        // Traverse left
        postorder(TreeNode.left);
        // Traverse right
        postorder(TreeNode.right);
        // Traverse root
        System.out.print(TreeNode.item + "->");
    }

4. 레벨 순서 순회

레벨 순서 순회는 대기열을 사용하여 방문할 노드를 추적합니다. 노드를 방문한 후 해당 자식이 대기열에 놓입니다. 순회할 새 노드를 얻으려면 대기열에서 요소를 꺼냅니다.

알고리즘은 다음과 같습니다.

  1. 빈 대기열 초기화
  2. 임시를 루트로 설정하여 시작
  3. 대기열이 비어 있지 않을 때까지 루프 실행\n
    1. 임시 데이터 인쇄
    2. 왼쪽에서 오른쪽 순서로 temp의 자식을 큐에 넣습니다.
    3. 대기열에서 노드를 제거하고 그 값을 temp에 할당합니다.

    위 트리의 레벨 순회는 다음과 같습니다.

    0 1 2 3 4
    

    자바 코드는 다음과 같습니다.

     static void printLevelOrder(TreeNode root) {
           Queue<TreeNode> queue = new LinkedList<TreeNode>();
           queue.add(root);
           while (!queue.isEmpty()) {
               TreeNode temp = queue.poll();
               System.out.print(temp.data + " ");
    
               /*add left child to the queue */
               if (temp.left != null) {
                   queue.add(temp.left);
               }
    
               /*add right right child to the queue */
               if (temp.right != null) {
                   queue.add(temp.right);
               }
           }
       }
    

    Java에서 BFS 및 DFS의 완전한 코드 구현

    전체 Java 코드는 다음과 같습니다.

    package com.JournalDev;
    import java.util.LinkedList;
    import java.util.Queue;
    
    public class Main {
        static class TreeNode {
            int data;
            TreeNode left, right;
    
            public TreeNode(int key) {
                data = key;
                left = right = null;
            }
        }
    
        static void preorder(TreeNode TreeNode) {
            if (TreeNode == null)
                return;
    
            // Traverse root
            System.out.print(TreeNode.data + " ");
            // Traverse left
            preorder(TreeNode.left);
            // Traverse right
            preorder(TreeNode.right);
        }
    
        static void inorder(TreeNode TreeNode) {
            if (TreeNode == null)
                return;
    
            // Traverse left
            inorder(TreeNode.left);
            // Traverse root
            System.out.print(TreeNode.data + " ");
            // Traverse right
            inorder(TreeNode.right);
        }
    
        static void postorder(TreeNode TreeNode) {
            if (TreeNode == null)
                return;
    
            // Traverse left
            postorder(TreeNode.left);
            // Traverse right
            postorder(TreeNode.right);
            // Traverse root
            System.out.print(TreeNode.data + " ");
        }
       static void printLevelOrder(TreeNode root) {
           Queue<TreeNode> queue = new LinkedList<TreeNode>();
           queue.add(root);
           while (!queue.isEmpty()) {
               TreeNode tempNode = queue.poll();
               System.out.print(tempNode.data + " ");
    
               /*add left child to the queue */
               if (tempNode.left != null) {
                   queue.add(tempNode.left);
               }
    
               /*add right right child to the queue */
               if (tempNode.right != null) {
                   queue.add(tempNode.right);
               }
           }
       }
    
        public static void main(String args[])
                
        {
            TreeNode root = new TreeNode(0);
            root.left = new TreeNode(1);
            root.right = new TreeNode(2);
            root.left.left = new TreeNode(3);
            root.left.right = new TreeNode(4);
            System.out.println("Inorder traversal");
            inorder(root);
    
            System.out.println("\nPreorder traversal ");
            preorder(root);
    
            System.out.println("\nPostorder traversal");
           postorder(root);
    
            System.out.println("\nLevelorder traversal");
            printLevelOrder(root);
    
        }
    
    } 
    
    
    Output : 
    
    Inorder traversal
    3 1 4 0 2 
    Preorder traversal 
    0 1 3 4 2 
    Postorder traversal
    3 4 1 2 0 
    Levelorder traversal
    0 1 2 3 4 
    
    

    결론

    이 튜토리얼은 이진 트리의 BFS 및 DFS 순회에 관한 것입니다. C++에서 DFS 구현을 얻으려면 이 자습서를 참조하십시오.