계층 구조는 선형으로 표현하기 어려운 형태이다. 자료 간에 상하위 관계나 포함 관계가 존재하는 경우 계층 구조가 생긴다.
이렇게 계층적 구조를 갖는 자료들을 표현하기 위한 자료구조가 바로 트리(Tree)
이다.
특정한 조건을 지키도록 구성된 트리들을 이용하면 배열이나 리스트를 사용하는 것보다 같은 작업을 더 빠르게 구현할 수 있다.
노드(node)
들이 간선(edge)
으로 서로 연결되어 있는 자료 구조를 말한다.부모(parent)
, 하위 노드를 자식(child)
노드라고 부른다.형제(sibiling)
노드라고 부른다.선조(ancestor)
라고 부르고, 자식 노드와 그의 자식들을 통틀어 자손(descendant)
이라고 부른다. 트리에는 최상단에 다른 모든 노드들을 자손으로 갖는 노드가 딱 하나 있게 된다. 이 노드를 트리의 뿌리 노드 혹은 루트(root)
라고 부른다.리프(leaf)
라고 부른다.깊이(depth)
라고 한다.높이(height)
라고 한다.‘t를 루트로 하는 서브트리(subtree)’
라고 말한다. 따라서 모든 트리는 루트와 루트 밑에 있는 서브트리들의 집합이라고 말할 수 있다.struct Tree Node{
string label; //저장할 자료
TreeNode* parent; // 부모 노드를 가리키는 포인터
vector<TreeNode*> children; // 자손 노드들을 가리키는 포인터의 배열
}
모든 트리는 각 자식들을 루트로 하는 서브트리와 루트로 나눌 수 있으므로, 트리의 루트가 주어질 때 루트를 ‘방문’한 뒤 각 서브트리를 재귀적으로 방문하는 함수를 만들어 트리의 모든 노드를 순회할 수 있다.
//트리를 순회하며 모든 노드에 포함된 값을 출력하기
//주어진 트리의 각 노드에 저장된 값을 모두 출력한다.
void printLabels(TreeNode* root) {
//루트에 저장된 값을 출력한다.
cout << root -> label << endl;
//각 자손들을 루트로 하는 서브트리에 포함된 값들을 재귀적으로 출력한다.
for(int i = 0; i< root -> children.size(); ++i)
printLabels(root->children[i]);
}
서브트리의 개념을 이용하면 트리의 높이 또한 재귀적으로 정의할 수 있다.
루트의 각 자식들을 루트로 하는 서브트리들의 높이를 각각 재귀 호출을 통해 계산하면 전체 트리의 높이는 그중 최대치에 1을 더한 것이 된다.
//순회를 이용해 트리의 높이를 계산하기
//root를 루트로 하는 트리의 높이를 구한다
int height(TreeNode* root){
int h = 0;
for(int i=0; i<root->children.size(); ++i)
h = max(h,1+height(root->children[i]));
return h;
}
출처
https://yoongrammer.tistory.com/70?category=956616 yoongrammer 블로그
프로그래밍 대회에서 배우는 알고리즘 문제 해결 전략 2 - 구종만 지음
https://blog.encrypted.gg/1013?category=773649 바킹독 실전 알고리즘 이진트리