C++로 트리 자료구조를 구현할 때에는 보통 왼쪽 자식을 가리키는 포인터, 오른쪽 자식을 가리키는 포인터, 내 데이터 이렇게 3가지 정보를 가지고 있는 Node라는 구조체를 만들어서 구현한다.
그런데 이 방법은 알고리즘 문제를 풀 때 직접 구현하기에는 너무 복잡하고 포인터를 이용하기 때문에 nullpointer 예외가 나기도 쉽다.
이진트리는 C++ STL인 map과 pair를 이용해서 쉽게 구현할 수 있다.
(만약 map을 잘 모르신다면 이 글을 먼저 보고 오는 것을 추천한다. 링크↓)
https://breakcoding.tistory.com/154
다음과 같은 이진트리가 있다고 하자.
일단 트리를 저장할 map 객체를 선언한다. 이 트리에는문자가 저장되어 있기 때문에 char 타입으로 선언했다.
pair에는 왼쪽 자식 노드와 오른쪽 자식 노드를 집어넣을 것이다.
map<char, pair<char, char>> tree;
A의 오른쪽 자식은 B, 왼쪽 자식은 C이므로 A 노드를 다음과 같이 집어넣어준다.
tree['A'] = make_pair('B', 'C');
B의 왼쪽 자식 노드는 D, 오른쪽 자식 노드는 없다. 자식이 없을 경우 .으로 표현하기로 하자. (NULL로도 표현해도 되고 내가 원하는 방식으로 표현해주면 된다. 대신 데이터로는 절대 나올 수 없는 것으로 선택해야 한다.)
tree['B'] = make_pair('D', '.');
D는 왼쪽, 오른쪽 자식이 모두 없으므로 tree['D']에는 이렇게 저장해준다.
tree['D'] = make_pair('.', '.');
이런식으로 모든 노드들을 tree라는 map에 저장해준다.
tree['C'] = make_pair('E', 'F');
tree['E'] = make_pair('.', '.');
tree['F'] = make_pair('.', 'G');
tree['G'] = make_pair('.', '.');
이렇게 노드의 개수만큼 map에 저장하는 것을 반복해주면 이진트리가 완성된다.
A 노드의 왼쪽 자식을 알고 싶으면
tree['A'].first
A의 오른쪽 자식을 알고 싶으면
tree['A'].second
이렇게 해주면 된다.
(pair 사용법이 낯설다면 이전 포스팅을 보고 오는 것을 추천한다. 링크↓)
https://breakcoding.tistory.com/96
일반적인 이진트리 구현방법인 포인터를 이용한 구조체로 트리를 구현했다면 무조건 가장 아래쪽에 있는 노드 D, 노드 E, 노드 G부터 만들어주고 위로 올라가야 한다. 따라서 그냥 이음선의 정보만 주어진다면 트리를 구현하기 위해서 위상정렬까지 해야 하는 상황이 발생한다. 하지만 이렇게 map을 이용해서 이진트리를 구현한다면 순서와 상관없이 이렇게 이음선의 정보만 map에 추가해주면 되기 때문에 트리를 쉽게 구현할 수 있다.
그러면 이렇게 map으로 구현한 이진트리를 전위순회, 중위순회, 후위순회 하는 방법을 알아보자.
void preorder(char node) {//전위순회
cout << node << " "; //현재 노드의 데이터 출력
if (m[node].first != '.') { //왼쪽 자식이 있다면
preorder(m[node].first);
}
if (m[node].second != '.') { //오른쪽 자식이 있다면
preorder(m[node].second);
}
}
void inorder(char node) {//중위순회
if (m[node].first != '.') { //왼쪽 자식이 있다면
inorder(m[node].first);
}
cout << node << " "; //현재 노드의 데이터 출력
if (m[node].second != '.') { //오른쪽 자식이 있다면
inorder(m[node].second);
}
}
void postorder(char node) { //후위순회
if (m[node].first != '.') { //왼쪽 자식이 있다면
postorder(m[node].first);
}
if (m[node].second != '.') { //오른쪽 자식이 있다면
postorder(m[node].second);
}
cout << node << " "; //현재 노드의 데이터 출력
}
이렇게 재귀함수로 쉽게 순회할 수 있다. 만약 자식 노드가 없을 때에 NULL로 저장했다면
왼쪽 자식이 있는지 체크하는 부분을 m[node].first != NULL로
오른쪽 자식이 있는지 체크하는 부분을 m[node].second != NULL로 해주면 된다.
'C++' 카테고리의 다른 글
[C++] 배열 초기화, 벡터 초기화, fill 함수 (0) | 2020.03.14 |
---|---|
[C++] next_permutation 이용해서 순열 구하기 (0) | 2020.02.19 |
[C++] 문자열을 숫자로 바꾸기, char을 int로 바꾸기 (0) | 2020.02.17 |
[C++] 이진탐색 binary_search, upper_bound, lower_bound 함수 사용법 (0) | 2020.02.14 |
[C++] 스트림 조종자 (출력 형식, 소수점 반올림, 16진수, 8진수 출력, 소수점 표기, 줄 맞추기) (1) | 2020.02.12 |