Java

[자바스터디 5주차] 과제

임요환 2023. 6. 1. 15:51

과제(Optional)

  • int 값을 가지고 있는 이진 트리를 나타내는 Node라는 클래스를 정의하세요
  • int value, Node left, right를 가지고 있어야 합니다
  • BinaryTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요
  • DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요

이진 트리(binary tree)

  • 자식노드가 최대 두 개인 노드들로 구성된 트리
  • 정이진트리, 완전이진트리, 균형이진트리 등

이진 탐색 트리(binary search tree)

  • 효율적인 탐색, 삽입 및 삭제 연산을 가능
  • 이진 탐색 특성에 따라 키가 정렬되어 있어 트리 내에서 요소를 찾는 것이 용이합
  • 데이터베이스, 검색 엔진, 다양한 알고리즘 및 데이터 구조와 같이 효율적인 탐색이 필요한 응용 프로그램에서 일반적으로 사용됨
  • 정렬된 데이터 저장 및 효율적인 검색 사이의 균형을 제공함

이진 탐색 트리 데이터 구조

  1. BST의 각 노드는 키 값을 가지며, 트리 내에 있는 두 노드는 동일한 키 값을 가지지 않음
  2. 노드의 왼쪽 서브트리에 있는 키 값은 해당 노드의 키 값보다 작음
  3. 노드의 오른쪽 서브트리에 있는 키 값은 해당 노드의 키 값보다 큼
  4. 노드의 왼쪽 서브트리와 오른쪽 서브트리는 모두 이진 탐색 트리임

이진 트리 순회

  • 전위(pre-order) 순회 = 루트로 부터 시작하여 왼쪽, 오른쪽을 순차적으로 순회하는 방법
    • A -> B -> C -> D -> E -> F -> G
  • 중위(in-order) 순회 = 왼쪽 자식 노드를 방문한 뒤 부모노드, 우측노드를 순차적으로 순회하는 방법
    • C -> B -> D -> A -> F -> E -> G
  • 후위(post-order) 순회 = 좌측노드, 우측노드 그리고 부모노드를 순차적으로 순회하는 방법
    • C -> D -> B -> F -> G -> E -> A

BFS(Breadth-First Search)

  • 루트노드에서 시작해서 인접한 노드를 먼저 탐색하는 방법
  • 장점
    • 노드의 수가 적고 깊이가 얕은 경우 빠르게 동작
    • 깊은 우선 탐색(DFS)보다 단순 검색 속도가 빠름
    • 너비를 우선 탐색하기에 답이 되는 경로가 여러개인 경우에도 최단경로임을 보장
    • 최단경로가 존재한다면 어느 한 경로가 무한히 깊어진다해도 최단경로를 반드시 찾아냄
  • 단점
    • 노드의 수가 많아지면 탐색해야하는 노드가 많아짐
    • 재귀호출을 이용하는 DFS와는 달리 큐에 다음에 탐색할 노드를 저장하기 때문에 저장공간이 많이 필요함

DFS(Depth-First Search)

  • 한 노드에 대해 탐색할 수 있는 깊이까지 먼저 탐색한 뒤 다음 탐색을 이어가는 방법
  • 장점
    • 현 경로상의 노드만을 기억하면 되므로 저장공간이 많이 필요하지 않음
    • 목표노드가 같은 단계에 있을 경우 결과를 빠르게 구할 수 있음
  • 단점
    • 결과 값이 없는 경로에 깊이 빠질 가능성 존재
    • 결과 값이 다수 존재할 경우 해당 값이 최단 경로라는 보장이 없음
public class Node {
    int key;
    Node left, right;

    public Node(int item) {
        key = item;
        left = right = null;
    }
}

public class BinarySearchTree {
    Node root;

    BinarySearchTree() {
        root = null;
    }

    void insert(int key) {
        root = insertRec(root, key);
    }

    Node insertRec(Node root, int key) {
        if (root == null) {
            root = new Node(key);
            return root;
        }

        if (key < root.key)
            root.left = insertRec(root.left, key);
        else if (key > root.key)
            root.right = insertRec(root.right, key);

        return root;
    }

    void deleteKey(int key) {
        root = deleteRec(root, key);
    }

    Node deleteRec(Node root, int key) {
        if (root == null)
            return root;

        if (key < root.key)
            root.left = deleteRec(root.left, key);
        else if (key > root.key)
            root.right = deleteRec(root.right, key);
        else {
            if (root.left == null)
                return root.right;
            else if (root.right == null)
                return root.left;

            root.key = minValue(root.right);

            root.right = deleteRec(root.right, root.key);
        }

        return root;
    }

    int minValue(Node root) {
        int minValue = root.key;
        while (root.left != null) {
            minValue = root.left.key;
            root = root.left;
        }
        return minValue;
    }

    void inorder() {
        inorderRec(root);
        System.out.println("종료");
    }

    void inorderRec(Node root) {
        if (root != null) {
            inorderRec(root.left);
            System.out.print(root.key + " -> ");
            inorderRec(root.right);
        }
    }

    void postorder() {
        postorderRec(root);
        System.out.println("종료");
    }

    void postorderRec(Node root) {
        if (root != null) {
            postorderRec(root.left);
            postorderRec(root.right);
            System.out.print(root.key + " -> ");
        }
    }

    void preorder() {
        preorderRec(root);
        System.out.println("종료");
    }

    void preorderRec(Node root) {
        if (root != null) {
            System.out.print(root.key + " -> ");
            preorderRec(root.left);
            preorderRec(root.right);
        }
    }

    void bfs(Node searchNode) {
        if (root == null)
            return;

        Queue<Node> queue = new LinkedList<>();
        queue.add(root);

        while (!queue.isEmpty()) {
            Node node = queue.poll();
            System.out.print(node.key + " -> ");

            if (node.key == searchNode.key)
                break;

            if (node.left != null)
                queue.add(node.left);

            if (node.right != null)
                queue.add(node.right);
        }

        System.out.println("종료");
    }

    void dfs(Node searchNode) {
        if (root == null)
            return;

        Stack<Node> stack = new Stack<>();
        stack.push(root);

        while (!stack.isEmpty()) {
            Node node = stack.pop();
            System.out.print(node.key + " -> ");

            if (node.key == searchNode.key)
                break;

            if (node.right != null)
                stack.push(node.right);

            if (node.left != null)
                stack.push(node.left);
        }

        System.out.println("종료");
    }

}