Algorithm

BFS(Breadth First Search) & DFS(Depth First Search)

주인장 꼬비 2022. 9. 24. 18:56

BFS

/**
 * 2 ways of traversing a tree.
 * - Breadth First Search (BFS)
 * - Depth First Search (DFS)
 *
 * BFS (Steps - Iteratively)
 * - Create a queue(this can be an array) and a variable to store the values of nodes visited.
 * - Place the root node in the queue.
 * - Loop as long as there is anything in the queue.
 * > Dequeue a node from the queue and push the value of the node into the variable that stores the nodes.
 * > if there is a left property on the node dequeued - add it to the queue.
 * > If there is a right property on the node dequeued - add it to the queue.
 * - Return the variable that stores the values.
 *
 *
 */

class Node {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  insert(value) {
    const newNode = new Node(value);
    if (!this.root) {
      this.root = newNode;
      return this;
    }

    let current = this.root;
    while (true) {
      if (value === current.value) return undefined;
      if (current.value < newNode.value) {
        if (!current.right) {
          current.right = newNode;
          return this;
        }
        current = current.right;
      } else {
        if (!current.left) {
          current.left = newNode;
          return this;
        }
        current = current.left;
      }
    }
  }

  find(value) {
    if (!this.root) return false;

    let current = this.root;
    let found = false;

    while (current && !found) {
      if (value < current.value) {
        current = current.left;
      } else if (value > current.value) {
        current = current.right;
      } else {
        found = true;
      }
    }
    if (!found) return undefined;
    return current;
  }

  BFS() {
    const data = [];
    const queue = [];
    let node = this.root;
    queue.push(node);
    while (queue.length) {
      node = queue.shift();
      data.push(node.value);
      if (node.left) queue.push(node.left);
      if (node.right) queue.push(node.right);
    }
    return data;
  }
}

const tree = new BinarySearchTree();
tree.insert(10);
tree.insert(6);
tree.insert(15);
tree.insert(3);
tree.insert(8);
tree.insert(20);
console.log(tree.BFS());

 

DFS

/**
 * 2 ways of traversing a tree.
 * - Breadth First Search (BFS)
 * - Depth First Search (DFS)
 *
 * DFS
 * - InOrder : traverse from the left subtree to the root then to the right subtree.
 * - PreOrder : traverse from the root to the left subtree then to the right subtree.
 * - PostOrder : traverse from the left subtree to the right subtree then to the root.
 *
 */

class Node {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  insert(value) {
    const newNode = new Node(value);
    if (!this.root) {
      this.root = newNode;
      return this;
    }

    let current = this.root;
    while (true) {
      if (value === current.value) return undefined;
      if (current.value < newNode.value) {
        if (!current.right) {
          current.right = newNode;
          return this;
        }
        current = current.right;
      } else {
        if (!current.left) {
          current.left = newNode;
          return this;
        }
        current = current.left;
      }
    }
  }

  /**
   * DFS - PreOrder (Steps - Recursively)
   * - Create a variable to store the values of nodes visited
   * - Store the root of the BST in a variable called current.
   * - Write a helper function which accepts a node
   * > - Push the value of the node to the variable that stores the values.
   * > - If the node has a left property, call the helper function with the left property on the node.
   * > - If the node has a right property, call the helper function with the right property on the node.
   */
  DFSPreOrder() {
    const data = [];
    let current = this.root;

    function traverse(node) {
      data.push(node.value);
      if (node.left) traverse(node.left);
      if (node.right) traverse(node.right);
    }

    traverse(current);
    return data;
  }

  /**
   * DFS - PostOrder (Steps - Recursively)
   * - Create a variable to store the values of nodes visited
   * - Store the root of the BST in a variable called current.
   * - Write a helper function which accepts a node
   * > - If the node has a left property, call the helper function with the left property on the node.
   * > - If the node has a right property, call the helper function with the right property on the node.
   * > - Push the value of the node to the variable that stores the values.
   * > - Invoke the helper function with the current variable.
   * - Return the array of values.
   */
  DFSPostOrder() {
    const data = [];
    let current = this.root;

    function traverse(node) {
      if (node.left) traverse(node.left);
      if (node.right) traverse(node.right);
      data.push(node.value);
    }

    traverse(current);
    return data;
  }

  /**
   * DFS - InOrder (Steps - Recursively)
   * - Create a variable to store the values of nodes visited
   * - Store the root of the BST in a variable called current.
   * - Write a helper function which accepts a node
   * > - If the node has a left property, call the helper function with the left property on the node.
   * > - Push the value of the node to the variable that stores the values.
   * > - If the node has a right property, call the helper function with the right property on the node.
   * - Invoke the helper function with the current variable.
   * - Return the array of values.
   */
  DFSInOrder() {
    const data = [];
    let current = this.root;

    function traverse(node) {
      if (node.left) traverse(node.left);
      data.push(node.value);
      if (node.right) traverse(node.right);
    }

    traverse(current);
    return data;
  }
}

function prettyLog(title, result) {
  console.log();
  console.log(title);
  console.log(result);
  console.log();
}

const tree = new BinarySearchTree();
tree.insert(10);
tree.insert(6);
tree.insert(15);
tree.insert(3);
tree.insert(8);
tree.insert(20);
prettyLog("DFS-PreOrder", tree.DFSPreOrder());
prettyLog("DFS-PostOrder", tree.DFSPostOrder());
prettyLog("DFS-InOrder", tree.DFSInOrder());

 

 

Q. BFS(너비 우선 탐색) 와 DFS(깊이 우선 탐색)는 언제 사용되는가?

 

Q. BFS(너비 우선 탐색) 와 DFS(깊이 우선 탐색) 중 어떤 것을 사용해야 하는가? 

트리에 따라 다르다. (시간복잡도는 같으나 공간복잡도가 다르다.)

 

완전히 넓게 펴진 상태로 아래까지 뻗어 나가는 트리

BFS -> 모든 노드를 저장하기 위해 Queue 를 사용해야 한다. (공간복잡도가 크다.)

DFS -> BFS와 달리 모든 노드를 저장할 필요가 없다. (공간복잡도가 작다.)

 

한쪽으로 치우쳐져 아래까지 뻗어 나가는 트리

BFS -> 메모리에서 사용되는 공간이 거의 없다. (큐에 한개 이상의 요소가 들어가지 않기 때문)

DFS -> 처리하고 있는 레벨 위의 모든 레벨들이 다 메모리에 저장되어야 해서 메모리 사용을 많이 한다.

 

Q. DFS에서 어떤 종류를 언제 사용해야 하는가?

InOrder (정위) : 트리의 모든 노드를 기본 순서로 가져온다. (순서대로 작업할때 유용)

PreOrder (전위) : 트리를 복사하거나 평탄화해서 저장하는 경우 유용하다.

InOrder 의 경우 재구성을 하고자 할 때, 트리의 루트가 무엇인지 잘 모름

(파일이나 DB같은 곳에 저장했다가 연쇄 구조로 다시 만들어낼 때 유용하다.)

 

 

 

정리

- 트리는 비선형 데이터 구조이며, 하나의 루트와 많은 자식 노드들로 구성되어 있다.

- BT(Binary Tree)는 아무런 종류의 값을 가질 수 있지만, 각 노드는 최대 2개의 자식을 가질 수 있다.

- BST (Binary Search Tree)는 BT의 특별한 종류의 트리이다. 부모의 왼쪽에 있는 모든 노드는 부모보다 작고, 오른쪽에 있는 모든 노드는 크다. -> BST는 비교가 가능한 데이터 종류에만 사용할 수 있다.

 

 

 

 

본 내용은 작성자가 (Udemy) JavaScript 알고리즘 & 자료구조 마스터클래스 강의를 듣고 정리 및 메모한 내용입니다.  오역 및 오개념이 있을 수 있으니 바로잡기 위해 문제가 있는 경우 댓글 남겨주시면 매우 감사하겠습니다.

https://www.udemy.com/course/best-javascript-data-structures/

 

JavaScript (JS) Algorithms and Data Structures Masterclass

정렬, 리스트, 힙 스택을 포함한 12개의 알고리즘과 10개 이상 자료구조 학습으로 기술 면접 완벽하게 대비!

www.udemy.com

 

'Algorithm' 카테고리의 다른 글

Dynamic Programming (기초 개념)  (0) 2022.12.03
백준 문제 추천  (0) 2022.10.30
BST (Binary Search Tree)  (0) 2022.09.24
Tree (트리 구조)  (0) 2022.09.22
Queue  (0) 2022.09.22