Tree

신창용·2023년 1월 13일

Tree의 정의

자료구조 Tree는 이름 그대로 나무의 형태를 가지고 있다.
정확히는 나무를 거꾸로 뒤짚어 놓은 듯한 모습을 가지고 있다.
그래프의 여러 구조 중 단방향 그래프의 한 구조로, 하나의 뿌리로부터 가지가 사방으로 뻗은 형태가 나무와 닮아 있다고 해서 트리구조라고 부른다.

마치 가계도와 흡사해 보이는 이 트리 구조는 데이터가 바로 아래에 있는 하나 이상의 데이터에 한 개의 경로와 하나의 방향으로만 연결된 계층적 자료구조이다.
데이터를 순차적으로 나열시킨 선현 구조가 아니라, 하나의 데이터 아래에 여러 개의 데이터가 존재할 수 있는 비선형 구조이다.

비선형 구조: 비선형 구조는 하나의 자료 뒤에 여러개의 자료가 존재할 수 있는 형태입니다.
트리 구조는 계층적으로 표현이 되고, 아래로만 뻗어나가기 때문에 사이클이 없다.
여기서 사이클이란 시작 노드에서 출발해 다른 노드를 거쳐 시작 노드로 돌아올 수 있다면 사이클이 존재한다고 표현한다.
따라서 트리는 사이클이 없는 하나의 연결 그래프 라고 할 수 있다.

Tree의 구조와 특징


트리 구조는 루트라는 하나의 꼭짓점 데이터를 시작으로 여러 개의 데이터를 간선으로 연결한다.
각 데이터를 노드라고 하며, 두 개의 노드가 상하 계층으로 연결되면 부모/자식 관계를 가진다.
위 그림에서 A는 B와 C의 부모 노드이고, B와 C는 A의 자식 노드이다.
자식이 없는 노드는 나무의 잎과 같다고 하여 리프 노드라고 부른다.

깊이(depth)

트리 구조에서는 루트로부터 하위 계층의 특정 노드까지의 깊이를 표현할 수 있다.
루트 노드는 지면에 있는 것처럼 깊이가 0이다.
위 그림에서 루트 A depth는 0이고, B와 C의 깊이는 1이다.
D,E,F,G의 깊이는 2이다.

레벨(Level)

트리 구조에서 같은 깊이를 가지고 있는 노드를 묶어서 레벨로 표현할 수 있다.
depth가 0인 루트 A의 level은 1이다.
depth가 1인 B와 C의 level은 2d이다.
D,E,F,G의 레벨은 3이다. 같은 레벨에 나란히 있는 노드를 형제 노드라고 한다.

높이(Height)

트리 구조에서 리프 노드를 기준으로 루트까지의 높이를 표현할 수 있다.
리프 노드와 직간접적으로 연결된 노드의 높이를 표현하며, 부모 노드는 자식 노드의 가장 높은 height 값에 +1한 값을 높이로 가진다.
트리 구조의 높이를 표현할 때에는 각 리프 노드의 높이를 0으로 놓는다.
위 그림에서 H, I, E, F, J의 높이는 0이다. D와 G의 높이는 1입니다. B와 C의 높이는 2입니다. 이때 B는 D의 height + 1 을, C는 G의 height + 1 을 높이로 가집니다. 따라서, 루트 A의 높이는 3이다.

서브 트리(Sub tree)

트리 구조의 root에서 뻗어 나오는 큰 트리의 내부에, 트리 구조를 갖춘 작은 트리를 서브 트리 라고 부른다.
(D,H,I)로 이루어진 작은 트리도 서브 트리이고, (B,D,E)나 (C,F,G,J)도 서브 트리이다.

  • 자료구조는 자료의 집합을 구조화하고, 이를 표현하는 데에 초점이 맞춰져 있다.
    우리는 이미 자료구조를 알게 모르게 많이 접했다. 사람이 사용하기에 편리하려고, 사용하기 좋으려고 만들어진 것이 자료구조이다.

용어정리

  • 노드(Node) : 트리 구조를 이루는 모든 개별 데이터
  • 루트(Root) : 트리 구조의 시작점이 되는 노드
  • 부모 노드(Parent node) : 두 노드가 상하관계로 연결되어 있을 때 상대적으로 루트에서 가까운 노드
  • 자식 노드(Child node) : 두 노드가 상하관계로 연결되어 있을 때 상대적으로 루트에서 먼 노드
  • 리프(Leaf) : 트리 구조의 끝 지점이고, 자식 노드가 없는 노드

Tree의 예


이진 트리(Binary tree)

먼저 이진 트리는 자식 노드가 최대 두 개인 노드들로 구성된 트리이다.
이 두 개의 자식 노드는 왼쪽 자식 노드와 오른쪽 자식 노드로 나눌 수 있다.

이진 트리는 자료의 삽입,삭제 방법에 따라 정 이진 트리, 완전 이진 트리, 포화 이진 트리로 나뉜다.

이진 트리 특징

  • 정 이진 트리(Full binary tree) : 각 노드가 0개 혹은 2개의 자식 노드를 갖는다.
  • 포화 이진 트리(Perfect binary tree) : 정 이진 트리이면서 완전 이진 트리인 경우이다. 모든 리프 노드의 레벨이 동일하고, 모든 레벨이 가득 채워져 있는 트리이다.
  • 완전 이진 트리(Complete binary tree) : 마지막 레벨을 제외한 모든 노드가 가득 차 있어야 하고, 마지막 레벨의 노드는 전부 차 있지 않아도 되지만 왼쪽이 채워져야 한다.

이러한 이진 트리는 이진 탐색 트리와 이진 힙 구현에 사용되며, 효율적인 검색과 정렬을 위해 사용된다.

이진 탐색 트리(Binary Search Tree)

이진 탐색 트리란 이진 탐색과 연결 리스트를 결합한 이진트리를 말한다.
이진 탐색의 효율적인 탐색 능력을 유지하면서도, 빈번한 자료 입력과 삭제를 가능하게끔 고안됐다.

이진탐색트리는 아래와 같은 특징을 가지고 있다.

  • 각 노드에 중복되지 않는 키(Key)가 있다.
  • 루트노드의 왼쪽 서브 트리는 해당 노드의 키보다 작은 키를 갖는 노드들로 이루어져 있다.
  • 루트노드의 오른쪽 서브 트리는 해당 노드의 키보다 큰 키를 갖는 노드들로 이루어져 있다.
  • 좌우 서브트리도 모두 이진 탐색 트리여야 한다.

즉 이진 탐색 트리는 모든 왼쪽 자식의 값이 루트나 부모보다 작고, 모든 오른쪽 자식의 값이 루트나 부모보다 작고, 모든 오른쪽 자식의 값이 루트나 부모보다 큰 값을 가지는 특징이 있다.

이진 탐색 트리는 균형 잡힌 트리가 아닐 때, 입력되는 값의 순서에 따라 한쪽으로 노드들이 몰리게 될 수 있다.
균형이 잡히지 않은 트리는 탐색하는 데 시간이 더 걸리는 경우도 있기 때문에 해결해야 할 문제이다.
이 문제를 해결하기 위해 삽입과 삭제ㅏ다 트리의 구조를 재조정하는 과정을 거치는 알고리즘을 추가할 수 있다.

이진 탐색 트리 특징

이진 탐색 트리는 기존 이진 트리보다 탐색이 빠르다는 장점이 있다.
이진 탐색 트리의 연산은 트리의 높이가 h라면 o의 복잡도를 가지게 된다.이와 같은 효율적인 연산이 가능한 이유는 탐색 과정에 있다.

이진 탐색 트리의 탐색은 아래와 같은 과정을 거친다.

  • 루트 노드의 키와 찾고자 하는 값을 비교한다. 만약 찾고자 하는 값이라면 탐색을 종료한다.
  • 찾고자 하는 값이 루트 노드의 키보다 작다면 왼쪽 서브 트리로 탐색을 진행한다.
    찾고자 하는 값이 루트 노드의 키보다 크다면 오른쪽 서브 트리로 탐색을 진행한다.

이 과정을 찾고자 하는 값을 찾을 때까지 반복해 진행한다.
만약 값을 찾지 못한다면 그대로 연산을 종료하게 된다.
이러한 과정을 거치면 최대 트리의 높이(h)만큼 탐색을 진행한다.

만약 이와 같은 트리에서 5라는 값을 찾고자 하면 제일 처음에는 루트 노드와 값을 비교하게 된다.
루트 노드가 여기서는 10이므로 루트 노드보다 작기 때문에, 왼쪽 서브 트리로 탐색을 시작한다.
이후 마주친 노드는 7이고, 찾고자 하는 값은 5이므로 다시 7을 기준으로 왼쪽 서브 트리로 탐색을 진행한다.
이어 만난 값이 찾고자 하는 값이므로 탐색이 종료된다.
10부터 5까지 3번의 탐색이 이뤄졌지만, 만약 3을 찾는다면 4번의 연산이 진행되었을 것이다.
즉 트리 안의 값을 찾는다면 무조건 트리의 높이(h) 이하의 탐색이 이뤄지게 된다.

여기서 하나 알아둬야 할 점은, 트리 안에 찾고자 하는 값이 없더라도 최대 h번의 연산 및 탐색이 진행된다는 것이다.
만일 13이라는 숫자를 찾는다고 가정해보자 마지막으로 도착하는 노드의 값은 14인데, 여기서 13은 14보다 작으므로 왼쪽 서브 트리로 탐생을 진행해야 한다. 하지만 오른쪽 서브트리가 없으므로 14에서 탐색이 종료 되게 된다.
그렇게 때문에 트리 안에 찾고자 하는 값이 없더라도 최대 h번의 연산 및 탐색이 진행되게 되는 것이다.


특정 목적을 위해 트리의 모든 노드를 한 번씩 방문하는 것을 트리 순회라고 한다.
1에서 10까지의 정수로 구성된 트리에서 3이라는 숫자를 찾기 위해 모든 노드를 방문하는 경우는 트리 순회의 한 예시이다.
트리 구조는 계층적 구조라는 특별한 특징을 가지기 때문에, 모든 노드를 순회하는 방법엔 크게 세 가지가 있다.

트리를 순회할 수 있는 세 가지 방법은 전위 순회, 후위 순회이다.
이 순회 방식과는 논외로, 트리 구조에서 노드를 순차적으로 조회할 때의 순서는 항상 왼쪽부터 오른쪽이다.

전위 순회 (preorder traverse)

전위 순회에서 가장 먼저 방문하는 노드는 루트이다.
루트에서 시작해 왼쪽의 노드들을 순차적으로 둘러본뒤, 왼쪽의 노드 탐색이 끝나면 오른쪽 노드를 탐색 한다.
즉 부모 노드가 제일 먼저 방문되는 순회 방식이다.
전위 순회는 주로 부모 노드가 먼저 생성되어야 하는 트리를 복사할 때 사용하게 된다.

중위 순회 (inorder traverse)

중위 순회는 루트를 가운데에 두고 순회한다.
제일 왼쪽 끝에 있는 노드부터 순회하기 시작하여, 루트를 기준으로 왼쪽에 있는 노드의 순회가 끝나면 루트를 거쳐 오른쪽에 있는 노드로 이동하여 마저 탐색한다.
부모 노드가 서브 트리의 방문 중간에 방문되는 순회 방식이다.
중위 순회는 이진 탐색 트리의 오름차순으로 값을 가져올 때 쓰인다.

후위 순회 (postorder traverse)

후위 순회는 루트를 가장 마지막에 순회한다.
제일 왼쪽 끝에 있는 노드부터 순회하기 시작하여, 루트를 거치지 않고 오른쪽으로 이동해 순회한 뒤, 제일 마지막에 루트를 방문한다.
후위 순회는 트리를 삭제할 때 사용한다. 자식 노드가 먼저 삭제되어야 상위 노드를 삭제할 수 있기 때문이다.

순회 방식을 나누는 이유

앞서 배운 이진 트리 탐색의 경우는 간단한 편이지만 순회 방법은 조금 복잡한 편이다.
일정 조건에 의해 설계된 트리 구조는 자식 노드에 대한 조건이 명확하다면 원하는 값을 쉽게 찾아낼 수 있게 되지만, 트리 구조 전체를 탐색할 때는 이야기가 조금 달라지기 때문이다.
모든 노드를 방문하기 위해서는 일정한 조건이 필요하고, 트리 구조를 유지보수하거나 특정 목적을 위해서도 순회 방법에 대한 정의는 필수적으로 필요하다.

profile
코딩으로 쓰는 일기장

0개의 댓글