TIL
[멋쟁이사자처럼 부트캠프 TIL 회고] 유니티 게임개발 3기 15일차 자료구조(Tree)
HYttt
2024. 12. 10. 15:47
Tree
- 트리는 계층적 구조를 표현하는 비선형 자료구조로, 노드들과 노드들을 연결하는 간선들로 구성되어 있다.
트리의 주요 특징
- 하나의 루트 노드를 가진다.
- 각 노드는 0개 이상의 자식 노드를 가질 수 있다.
- 사이클이 존재하지 않는다.
트리의 종류
- 일반 트리 (General Tree): 노드가 임의의 수의 자식을 가질 수 있는 트리
- 이진 트리 (Binary Tree): 각 노드가 최대 2개의 자식을 가질 수 있는 트리
- 완전 이진 트리 (Complete Binary Tree): 마지막 레벨을 제외한 모든 레벨이 완전히 채워진 이진 트리
- 포화 이진 트리 (Perfect Binary Tree): 모든 내부 노드가 2개의 자식을 가지며, 모든 리프 노드가 같은 레벨에 있는 트리
- 이진 탐색 트리 (Binary Search Tree): 왼쪽 자식은 부모보다 작고, 오른쪽 자식은 부모보다 큰 값을 가지는 이진 트리
- AVL 트리: 자동으로 균형을 맞추는 이진 탐색 트리로, 왼쪽과 오른쪽 서브트리의 높이 차이가 최대 1
- 레드-블랙 트리 (Red-Black Tree): 자가 균형 이진 탐색 트리의 일종으로, 색상 속성을 사용하여 균형을 유지한다.
트리의 순회 방법
- 전위 순회 (Preorder): 루트 → 왼쪽 서브트리 → 오른쪽 서브트리
- 중위 순회 (Inorder): 왼쪽 서브트리 → 루트 → 오른쪽 서브트리
- 후위 순회 (Postorder): 왼쪽 서브트리 → 오른쪽 서브트리 → 루트
- 레벨 순회 (Level-order): 루트부터 레벨별로 왼쪽에서 오른쪽으로 순회
레드블랙 트리
- 모든 새로운 노드는 Red로 삽입된다다 (조건 1)
- 루트 노드는 항상 Black으로 유지된다 (조건 2)
- NIL 노드는 Black으로 처리된다 (조건 3)
- Red 노드의 자식들은 Black이 되도록 보장된다 (조건 4)
- 모든 경로의 Black 높이가 같도록 유지된다 (조건 5)
레드블랙 트리 구현
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RedBlackTree : MonoBehaviour
{
//노드 색상 정의하는 열거형
private enum NodeColor
{
Red, Black
}
// 노드 class
private class Node
{
public int data;
public Node left, right, parent;
public NodeColor color;
// 새로운 노드는 항상 Red
public Node(int data)
{
this.data = data;
left = right = parent = null;
color = NodeColor.Red;
}
private Node root;
private Node TNULL; // NIL node
void Start()
{
// NIL 노드는 항상 Black
TNULL = new Node(0);
TNULL.color = NodeColor.Black;
root = TNULL;
}
// 삽입 시 트리 재조정을 위한 좌회전
private void LeftRotate(Node x)
{
Node y = x.right;
x.right = y.left;
if (y.left != TNULL)
y.left.parent = x;
y.parent = x.parent;
if (x.parent == null)
root = y;
else if(x == x.parent.left)
x.parent.left = y;
else
x.parent.right = y;
}
// 삽입 시 트리 재조정을 위한 우회전
private void RightRotate(Node x)
{
Node y = x.left;
x.left = y.right;
if(y.right != TNULL)
y.right.parent = x;
y.parent = x.parent;
if(x.parent == null)
root = y;
else if (x == x.parent.right)
x.parent.right = y;
else
x.parent.left = y;
y.right = x;
x.parent = y;
}
// 노드 삽입
public void Insert(int key)
{
Node node = new Node(key);
node.left = TNULL;
node.right = TNULL;
Node y = null;
Node x = root;
// 삽입 위치 찾기
while (x != TNULL)
{
y = x;
if(node.data < x.data)
x = x.left;
else
x = x.right;
}
node.parent = y;
if (y == null)
root = node;
else if (node.data < y.data)
y.left = node;
else
y.right = node;
InsertFixup(node);
}
// 삽입 후 레드-블랙 트리 속성 복구
private void InsertFixup(Node k)
{
Node u;
while (k.parent != null && k.parent.color == NodeColor.Red)
{
if (k.parent == k.parent.left)
{
u = k.parent.left;
// case 1 : 삽촌 노드가 red
if (u.color == NodeColor.Red)
{
// 색상 변경으로 해결
u.color = NodeColor.Black;
k.parent.color = NodeColor.Black;
k.parent.parent.color = NodeColor.Red;
k = k.parent.parent;
}
else
{
// case 2 & 3 : 삼촌 노드가 black
if (k == k.parent.left)
{
k = k.parent;
RightRotate(k);
}
// 색상 변경 및 회전으로 해결
k.parent.color = NodeColor.Black;
k.parent.parent.color = NodeColor.Red;
LeftRotate(k.parent.parent);
}
}
else
{
// 위의 경우의 대칭
u = k.parent.parent.right;
if (u.color == NodeColor.Red)
{
u.color = NodeColor.Black;
k.parent.color = NodeColor.Black;
k.parent.parent.color = NodeColor.Red;
k = k.parent.parent;
}
else
{
if (k == k.parent.right)
{
k = k.parent;
LeftRotate(k);
}
k.parent.color = NodeColor.Black;
k.parent.parent.color = NodeColor.Red;
RightRotate(k.parent.parent);
}
}
if (k == root)
break;
}
root.color = NodeColor.Black;
}
}
}