본문 바로가기
CS/자료구조

트리

by chogigang 2024. 6. 7.

이름과 비슷하게 나무를 닮은 자료구조입니다 나무는 뿌리에서부터 가지들이 뻗어 나와서 분기되고 가지 끝에는 잎이 달리듯이 트리라는 자료구조는 계층적인 관계를 한 자료의 표현에 매우 유용하게 사용됩니다. 예를 들어 회사의 조직 체계를 트리로 표현하면 사장은 뿌리에 해당하고, 사장 밑에 있는 각 부서의 부장은 뿌리에서 뻗어 나온 가지에 해당합니다.

 

 

나무의 달린 잎들의 순서를 매기기 어려운 것처럼 트리에 저장된 자료도 일렬로 나열하기 어렵고, 따라서 트리는 비선형 구조 입니다. 컴퓨터에서도 계층적인 관계를 표현하기 위해 트리가 다양하게 활용됩니다. 운영체제에서의 폴더 구조 표현, 효율적인 탐색을 위해 탐색트리, 우선순위 큐를 위한 힙 트리, 인공지능에서 의사결정 구조를 표현하기 위한 결정트리 등의 트리의 응용분야는 광범위합니다. 

 

 

트리용어

  • 트리에서 각각의 요소를 노드 노드 사이의 연결 관계를 간선 또는 예지 라고 합니다
  • 조직도에서 "사장"과 같이 계층구조의 최상위 노드를 루트(root)라 부르고, 나머지 노드들은 서브트리 라 부릅니다 트리에서 모든 노드는 자신을 루트로 하는 하나의 서브를 트리를 대표합니다. 트리는 순환적으로 정의되는 자료구조 입니다. 
  • 트리의 노드 사이에는 인간의 관계와 같이 부모 ,자식 ,형제 ,조상 및 자손의 관계가 존재합니다.  예를 들어 , 간선으로 직접 연결된 노드 사이에 상위노드를 부모, 하위노드를 자식으로 부르는 식입니다 자식이 없으면 단말이고 있으면 비 단말 노드입니다.
  • 노드가 가지고 있는 자식의 수를 차수 라 합니다 예를 들어, 단말 노드의 차수는 항상 0입니다. 또한 트리에 포함된 모든 노드의 차수 중에서 가장 큰 수를 트리의 차수라 고합니다.
  • 트리의 각층에 번호를 매긴 것을 레벨이라고 합니다. 보통 루트의 레벨은 1이고 한 층 씩 내려갈수록 1씩 증가합니다.  트리가 가지고 있는 최대 레벨을 트리의 높이라고 합니다.
  •  

트리의 표현

트리는 여러 방법으로 표현할 수 있지만, 가장 일반적인 방법은 노드와 간선을 이용하는 것입니다. 노드는 자료를 저장하는 데이터 필드와 자식들을 가리키는 링크 필드를 갖는데, 이때 링크의 수는 그 노드의 차수(자식의 수)가 됩니다. N-링크표현으로 불리는 이 방법은 간단해 보이지만 자식의 수에 제한이 없는 일반트리를 나타내는 데는 문제가 있습니다. 노드마다 자식 수가 다를 것이므로 링크를 저장할 배열의 크기를 고정할 수 없습니다.

 

노드를 약간 변형하면 두 개의 링크만으로 일반 트리를 표현할 수도 있습니다. 링크하나는 왼쪽 자식을 가리키고, 아른 하나는 오른쪽 형제를 가리키는 것입니다. 노드에는 자신의 정보와 자신의 첫 번째 자식과 다음 형제의 위치만을 저장합니다.

 

중첩된 집합

트리가 서브 트리들의 집합이라는 것을 잘 표현됩니다.

루트와 서브 트리를 중첩된 괄호로 묶어 표현할 수도 있습니다 

들여 쓰기로도 트리를 표현할 수 있는데 자료가 계층적인 구조를 갖는 것을 잘 나타냅니다. 윈도우 탐색기에서 폴더와 파일을 나타내기 위해 이 방법을 사용합니다.

 

이진트리 

자식의 수를 최대 2개로 제한한 트리입니다. 모든 노드는 왼쪽 자식을 루트로 하는 왼쪽 서브트리와 오른쪽 자식을 루트로 하는 오른쪽 서브트리를 갖는데 만약 자식이 없으면 서브트리는 공집합입니다 자식들 사이에는 순서가 있는데 왼쪽 자식과 오른쪽 자식은 반드시 구별되어야 합니다. 

 

이진트리의 종류

포화 이진트리 

 모든 레벨에 노드가 꽉 차 있는 이진트리를 말합니다 포화 이진트리는 높이를 알면 등비수열의 법칙과 같이 전체 노드의 수를 바로 계산할 수 있습니다.

이 식을 더 간단하게 바꾸면  2^() 1 식으로 간단하게 할 수 있습니다 

 

이 포화 이진트리를 식으로 바꾸면 2³⁺¹)-1 로 계산을 해보시면 8-1 = 7  전체 노드수는 7입니다

 

완전 이진 트리 

높이가 k인 트리에서 레벨 1부터 k-1까지는 노드가 모두 채워져 있고 마지막 레벨 k는 왼쪽부터 노드가 순서대로 채워져 있는 이진 트리를 말합니다. 마지막 레벨은 노드가 꽉 차 있지 않아도 되지만 중간에 빈 곳이 있으면 안 됩니다. 

 

 

균형 이진트리 

이진 트리에 좌우 "균형"의 개념을 적용할 수 있습니다. 균형 이진 트리 또는 높이 균형 이진트리는 모든 노드에서 좌우 서브 트리의 높이 차이가 1 이하인 트리를 말합니다.

높이가 1차이 나는 이진 균형 이진 트리
높이가 동일안 이진 균형 이진 트리

 

이진트리의 성질

트리에서 루트를 제외한 모든 노드는 부모로 가는 하나의 간선을 갖습니다. 따라서 n개의 노드를 가진 트리는 반드시 n-1개의 간선을 갖습니다.

 

높이가 h인 이진트리는 최소 h개의 노드를 가져야 하는데 한 레벨에 적어도 하나의 노드는 있어야 하기 때문입니다 

또한 높이가 h이면 최대 2^h -1 개의 노드를 갖는다는 것을 알 수 있는데, 포화 이진트리가 같은 높이에서 노드의 수가 최대인 트리이기 때문입니다. 

  경사 이진트리인 경우 높이=노드수                       포화 이진트리인경우 최소 높이  = (log₂(노드수+1))  = (log₂(7+1)) = log₂(8) =                                                                                                                                       log₂(2³) = 3log₂(2) = 3   <- 최소 높이 

 

 

배열 표현법

이진트리를 포화 이진트리의 일부라고 생각하면 배열 구조로 트리를 표현할 수 있습니다.

링크 표현법 

 

 

 

단말 노드부터 시작해 서브 트리를 순차적으로 병합하는데 마지막에 생성되는 루트 노드가 전체 트리를 대표합니다.

 

이진트리의 순회 

트리를 순회한다는 것은 트리의 모든 노드를 한 번씩 방문하는 것을 말합니다 선형 자료구조에서는 자료가 일렬로 저장되어 있어서 순회가 매우 단순합니다. 순서대로 방문하면 되기 때문입니다 그러나 트리에서는 노드가 일렬로 나열도어 있지 않기 때문에 여러 가지 '순서'로 노드를 방문할 수 있어 순회 방법이 다양합니다. 

 

표준 순회

  • 전위 순회(preorder traversal): VLR
  • 중위 순회(inorder traversal): LVR
  • 후위순회(postorder traversal): LRV

 

전위순회

전위순회는 루트 노드를 먼저 탐색하고, 자식 노드를 탐색하는 방식입니다.

중위 순회

중위순회는 왼쪽 자식 노드를 탐색하고, 루트 노드를 탐색하고, 오른쪽 자식 노드를 탐색하는 방식입니다.

후위순회

후위순회는 왼쪽 자식 노드를 탐색하고, 오른쪽 자식 노드를 탐색하고, 루트 노드를 탐색하는 방식입니다.

레벨 순회 

레벨순회는 루트 노드를 먼저 탐색하고, 그다음 레벨의 노드를 탐색하는 방식입니다. queue를 하나 선언해 두고, 루트 노드를 넣어준 다음, queue에 넣어준 노드를 하나씩 탐색하면서 자식 노드를 queue에 넣습니다. queue가 비어있을 때까지 반복합니다.

이진트리 노드 갯수 구하기   = (왼쪽 서브 트리 +오른쪽 서브트리 +1)

이진트리 높이 구하기  = 왼쪽 서브트리의 높이와 오른쪽 서브 트리의 높이 중에서 큰 값에 1을 더한 값   

 

이진 탐색 트리 

대부분의  탐색은 컴퓨터에서 가장 중요한 작업 중 하나입니다. 탐색을 위해서는 찾을 자료를 식별할 수 있는 유일한 값이 필요한데 이것을 키(key)라고 합니다 사람을 탐색할 때 전화번호나 주민등록번호를 사용한다면 그것이 탐색 키가 됩니다. 탐색에 트리 구조를 이용할 수도 있는데 이진 탐색 트리는 효율적인 탐색을 위한 이진트리 기반의 자료 구조입니다.  

 

  • 모든 노드는 유일한 키를 갖고 중복은 없습니다
  • 왼쪽 서브 트리 키는 루트의 키보다 작아야 합니다
  • 오른쪽 서브 트리의 키는 루트의 키보다 커야 합니다.
  • 왼쪽과 오른쪽 서브 트리도 이진 탐색 트리입니다.

 

탐색 연산

  • key가 루트의 키와 같으면 루트가 찾는 노드이다 탐색은 성공입니다.
  • key가 루트의 키보다 작으면 찾는 노드는 왼쪽 서브 트리에 있습니다. 탐색을 루트의 왼쪽 자식 노드를 기준으로 다시 시작합니다.
  • key가 루트의 키보다 크면 찾는 노드는 오른쪽 서브 트리에 있습니다. 탐색을 루트의 오른쪽 자식 노드를 기준으로 다시 시작합니다.

 

삽입 연산

삽입을 위해서는 먼저 삽입할 노드의 키를 이용한 탐색 과정이 수행되어야 합니다. 탐색에 실패한 위치가 노드를 삽입할 곳이기 때문이죠

만약 탐색에 성공하면 해당 키를 가진 노드가 이미 트리에 있는 것을 말합니다. 여기서는 키의 중복을 허용하지 않으므로 삽입하지 않습니다. 

 

 

삭제 연산 

삭제는 가장 복잡한 연산입니다. 노드를 삭제하더라도 이진 탐색 트리의 특성을 유지해야 하기 때문입니다. 삭제할 노드가 자식이 없는(단말) 경우와 , 하나의 자식을 갖는 경우 및 양쪽 자식을 모두 갖는 경우로 나누어 생각을 해보셔야 합니다.

 

CASE 1: 삭제하려는 노드가 단말 노드일 경우
삭제 노드의 부모 노드를 찾아서 연결을 끊습니다 부모 노드의 해당 링크를 NULL로 수정해야 합니다.

따라서 노드의 삭제를 위해서는 반드시 부모 노드를 알아야 하는데 실제로 변경되는 것은 부모의 링크 필드이기 때문입니다. 노드를 트리에서 삭제한 후 동적으로 해제하는 마무리 과정도 있어야 합니다. 

 

CASE 2: 자식이 하나인 노드의 삭제 
삭제 노드는 삭제하고 그 노드의 서브 트리는 부모 노드에 연결합니다 이경우에도 삭제할 노드가 부모의 왼쪽 자식인지 오른쪽 자식인지 고려하셔야 합니다.

 

 

CASE 3: 두 개의 자식을 모두 갖는 노드의 삭제
삭제할 때 적절한 후계자 노드를 하나 찾아야 합니다. 이때 후계자를 지정하는 기준은 삭제할 노드와 가장 값이 비슷한 노드가 되어야 합니다.

 왼쪽 서브 트리에서 가장 큰 노드 / 오른쪽 서브 트리에서 가장 작은 노드를 선별합니다. 

이진 탐색 트리의 성능은 최선의 경우 O(logn)이고 최악의 경우 O(n)입니다.

 

힙트리

키 값이 가장 크거나 작은 노드를 빨리 찾을 수 있도록 설계된 자료 구조입니다. 가장 크거나 작은 노드는 항사 루트에 있습니다.

최대 히프(max heap): 부모 노드의 키 값이 자식 노드의 키 값보다 크거나 같은 완전 이진트리key(부모노드) ≥ Key(자식노드)

(자식 노드가 부모 노드보다 클 순 없습니다.)

 

최소 히프(min heap): 부모 노드의 키 값이 자식 노드의 키 값보다 작거나 같은 완전 이진트리
Key(부모노드) ≤ Key(자식노드) (자식노드가 부모 노드보다 작을 수 없습니다)

 

힙 트리의 표현 

  • 최대값과 최솟값을 O(1)의 속도로 구할 수 있습니다.
  • 힙의 효과적인 저장 방법은 보통 배열을 이용하여 구현합니다
  • 구현을 쉽게 하기 위해서 인덱스 1부터 시작합니다.
  • 인덱스를 사용합니다. 
  • 연산 후에도 힙의 완전 이진트리 조건과 크기 조건을 만족해야 합니다.
    • 왼쪽 자식의 인덱스 : (부모의 인덱스) * 2
    • 오른쪽 자식의 인덱스 : (부모의 인덱스) * 2 + 1
    • 부모의 인덱스 : (자식의 인덱스) / 2

데이터 삽입

max heap일 경우

  1. 데이터를 일단 맨 마지막 인덱스에 추가합니다
  2. 부모 노드와 비교하여 부모 노드보다 작다면 그대로 두고
  3. 부모 노드보다 크다면, 부모 노드와 위치를 바꿔줍니다.

데이터 삭제

max heap일 경우

  1. root 노드를 삭제합니다
  2. root 노드의 자리에 맨 마지막 노드를 가져옵니다.
  3. heap을 재구성합니다. (만약 자식 노드보다 크다면 그대로 두고, 작다면 자식노드와 값을 꿔줍니다..



삽입 삭제 연산 둘 다 시간복잡도는 O(log₂n) 입니다.

 

 

 

 

 

 

사진 출처 : https://velog.io/@humblechoi/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%8A%B8%EB%A6%AC%EC%99%80-%ED%9E%99

https://yoongrammer.tistory.com/69

https://velog.io/@eunsung-dev/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%ED%8A%B8%EB%A6%AC

https://www.jiwon.me/binary-tree-traversal/

'CS > 자료구조' 카테고리의 다른 글

그래프  (0) 2024.06.12
리스트  (0) 2024.05.21
큐 (queue)  (0) 2024.04.06
스택(Stack)  (1) 2024.03.26
배열과 구조체  (0) 2024.03.19