Data Structure - tree / binary search tree / tree traversal JS 21.04.16


Tree

일방향 그래프의 한 구조. 즉, 데이터가 바로 아래에 하나 이상의 데이터에 단방향으로 연결되는 계층적 자료구조 (나무를 거꾸로 놓은 듯한 모습 === 뿌리)

  • root Node : 시작 Node
  • node : root에 간선(edge)으로 단방향 연결된 데이터
  • Parent Node & Child Node 관계 : 상위 Node와 하위 Node
  • leaf Node : 자식이 없는 Node (나무의 잎과 비슷)

  • level : 노드와 노드의 간격
  • height : root 부터 가장 안쪽에 있는 node까지의 level
  • depth : 특정 노드부터 시작하여 root까지의 레벨
  • sibling : 같은 level에 있는 node의 관계
  • sub-tree : root로 부터 뻗어나온 큰 Tree 내부에 Tree 모양을 갖춘 작은 Tree

Tree 실사용 예제 : 디렉토리(폴더) 구조, 월드컵 토너먼트 대진표, 가계도(족보), 조직도 등.

class Tree {
  constructor(value) {
		// constructor로 만든 객체는 트리의 Node가 됩니다.
    this.value = value;
    this.children = [];
  }
  // tree = new Tree(1)
  // tree = { value : 1, children : [{ value : 2, children : [] }, { value : 3, children : [] }] }

	// 트리의 삽입 메서드를 만듭니다.
  insertNode(value) {
		// 값이 어떤 이름으로 만들어지고 어느 위치에 붙는지 떠올리는 것이 중요합니다.
		// TODO: 트리에 붙게 될 childNode를 만들고, children에 넣어야 합니다.
    const childNode = new Tree(value);
    this.children.push(childNode);
  }

  // 트리 안에 인자로 받은 value가 포함되어 있는지 확인하는 메서드
  contains(value) {
    // base case
    if (this.value === value) {
      return true;
    }
	// TODO: 값을 찾을 때까지 children 배열을 순회하며 childNode를 탐색.(재귀 필요)
    // recursive case
    for (let t of this.children) {
      if(t.contains(value)) {
        return true;
      }
    }	
	// 전부 탐색했음에도 불구하고 찾지 못했다면 false를 반환합니다.
    return false;
  }
}

BST (Binary Search Tree) : 이진 탐색 트리 및 순회 방법

이진 트리(Binary Tree) : 자식 노드가 최대 두 개인 노드들로 구성된 트리 (노드는 왼쪽 자식과 오른쪽 자식으로 분류). 모든 왼쪽 자식들은 루트나 부모보다 작은 값, 모든 오른쪽 자식들은 루트나 부모보다 큰 값인 특징.

  • 전위 순회(pre order) : 우선순위 : 뿌리->왼쪽 자식->오른쪽 자식 순

  • 중위 순회(in order) : 우선순위 : 왼쪽자식-> 뿌리-> 오른쪽 자식

  • 후위 순회(post order) : 우선순위 : 왼쪽자식->오른쪽 자식-> 뿌리

class BinarySearchTree {
  constructor(value) {
		// constructor로 만든 객체는 이진 탐색 트리의 Node가 됩니다.
    this.value = value;
    this.left = null;
    this.right = null;
  }

	// 이진 탐색 트리의 삽입하는 메서드를 만듭니다.
  insert(value) {
		// 입력값을 기준으로, 현재 노드의 값보다 크거나 작은 것에 대한 조건문이 있어야 합니다.
		// 보다 작다면, Node의 왼쪽이 비어 있는지 확인 후 값을 넣습니다.
    if (value < this.value) {
      if (this.left === null) {
        this.left = new BinarySearchTree(value);
      } else { // this.left가 빈 값이 아니라면
				// TODO: 비어 있지 않다면 해당 노드로 이동하여 처음부터 다시 크거나 작은 것에 대한 조건을 물어보아야 할 것입니다.
				// TIP: 재귀함수를 사용합니다.
        this.left.insert(value);
      }
		// 보다 크다면, Node의 오른쪽이 비어 있는지 확인 후 값을 넣습니다.
    } else if (value > this.value) {
      if (this.right === null) {
        this.right = new BinarySearchTree(value);
      } else {
				// TODO: 비어 있지 않다면 해당 노드로 이동하여 처음부터 다시 크거나 작은 것에 대한 조건을 물어보아야 할 것입니다.
				// TIP: 재귀함수를 사용합니다.
        this.right.insert(value);
      }
		//그것도 아니라면, 입력값이 트리에 들어 있는 경우입니다.
    } else {
      // 아무것도 하지 않습니다.
    }
  }
  // 앞서 구현했던 트리에 비해 이진 탐색 트리는 입력 값에 따라 위치가 정해지므로 입력값과 트리 노드의 값의 크기를 비교

	// 이진 탐색 트리 안에 해당 값이 포함되어 있는지 확인하는 메서드를 만듭니다.
  contains(value) {
		// TODO: 값이 포함되어 있다면 true를 반환하세요.
    if (value === this.value) {
      return true;
    }
		// 입력값을 기준으로 현재 노드의 값보다 작은지 판별하는 조건문이 있어야 합니다.
    if (value < this.value) {
			// TODO: 현재 노드의 왼쪽이 비어 있지 않고, 노드의 값이 입력값과 일치하면 true를 반환합니다.
      if( this.left !== null && this.left.value === value) {
        return true;
      }
			// TODO:일치하지 않다면 왼쪽 노드로 계속 이동하여 다시 탐색합니다. 
      // if(this.left.contains()) {
      //   return true;
      // }
      this.left.contains()
    }
		// 입력값을 기준으로 현재 노드의 값보다 큰지 판별하는 조건문이 있어야 합니다.
    if (value > this.value) {
			// TODO: 현재 노드의 오른쪽이 비어 있지 않고, 노드의 값이 입력값과 일치하면 true를 반환합니다.
      if( this.left !== null && this.right.value === value) {
        return true;
      }
			// TODO:일치하지 않다면 오른쪽 노드로 계속 이동하여 다시 탐색합니다. 
      // if(this.right.contains()) {
      //   return true;
      // }
      this.right.contains()
    }
		// 없다면 false를 반환합니다.
    return false;
  }

	/*
	트리의 순회에 대해 구현을 합니다.
  지금 만드려고 하는 이 순회 메서드는 단지 순회만 하는 것이 아닌, 함수를 매개변수로 받아 콜백 함수에 값을 적용시킨 것을 순회해야 합니다.
  전위 순회를 통해 어떻게 탐색하는지 이해를 한다면 중위와 후위 순회는 쉽게 다가올 것입니다.
	*/

	// 전위 순회 : 뿌 왼 오 (우선순위 : 뿌리->왼쪽 자식->오른쪽 자식 순)
  preorder(callback) {
		callback(this.value);
    if (this.left) {
      this.left.preorder(callback);
    };
    if (this.right) {
      this.right.preorder(callback);
    };
  }

	// 중위 순회 : 왼 뿌 오 (우선순위 : 왼쪽자식-> 뿌리-> 오른쪽 자식)
  inorder(callback) {
		if (this.left) {
      this.left.inorder(callback);
    }
    callback(this.value)
    if (this.right) {
      this.right.inorder(callback);
    }
  }

	// 후위 순회 : 우선순위 : 왼쪽자식->오른쪽 자식-> 뿌리
  postorder(callback) {
		if (this.left) {
      this.left.postorder(callback);
    }
    if (this.right) {
      this.right.postorder(callback);
    }
    callback(this.value);
  }
}
트리의 종류
  • Binary tree : 부모 노드가 자식 노드를 최대 2개씩만 갖고있는 트리.(노드의 값 대소 관계 구분 없이)

  • Binary search tree : left child와 그 이하 노드들의 데이터가 현재 노드(부모 노드)의 데이터 보다 작아야 하고, right child와 그 이하 노드들의 데이터가 현재 노드(부모 노드)의 데이터 보다 커야한다.

  • Ternary tree : 자식 노드를 2개 이상 갖고 있는 트리

  • Balanced : left, right 노드의 갯수가 정확하게 일치해야 할 필요는 없음. unbalanced처럼 지나치게 한쪽으로 치우치지 않았다면 balanced tree.

  • Unbalanced : 한쪽으로 지나치게 치우친 tree.

  • Complete binary tree : 마지막 레벨을 제외한 모든 서브트리의 레벨이 같아야 하고, 마지막 레벨은 왼쪽부터 채워져 있어야 함.

  • Full binary tree : 자식 노드가 아예 없거나, 최대 둘뿐인 tree. 자식을 하나만 가진 노드가 없어야 한다.

  • Perfect binary tree : 자식이 아예 없거나 2개씩만 갖는 Full binary tree와 달리, Perfect binary tree는 완벽한 피라미드 형태로, 빈공간 없이 모든 노드가 2개의 자식을 갖고있는 tree.

  • 힙(Heap) : https://devlog-wjdrbs96.tistory.com/43

// binarySearch 함수
// 파라미터 - target : 찾으려는 타겟, dataArray : 데이터 배열
function binarySearch(target, dataArray) {
    // 최소값
    let low = 0;
    // 최대값 
    let high = dataArray.length - 1;
    // 최대값이 최소값 보다 크면 반복
    while (low <= high) {
        // 중간값 구하기
        let mid = Math.floor((high + low) / 2);
        // dataArray의 중간값
        let guess = dataArray[mid];
        // 만약 추정한게 target과 같다면 
        if (guess === target) {
            // 추정 값 리턴
            return guess;
            // 그렇지 않고 추정 값이 target보다 크다면
        } else if (guess > target) {
            // 최대 값은 = 중간값 -1;
            high = mid - 1;
        } else {
            // 추정값이 target보다 작다면
            // 최소값은 = 중간값 +1;
            low = mid + 1;
        }
    }
    // 찾으려는 target이 없다면 
    return undefined;
}





© 2020.11. by creamer

Powered by CREAMer