트리 변형 과제가 나온김에 포스팅해야겠다

 

임의의 트리에 대해서

전위와 중위 트리에 대한 정보가 주어졌을 떄 이 정보를 통해서 실제 트리를 구현해낼 수 있다.

 

단순히 재귀만 이용하면 되는 간단한 문제이다

 

전위, 중위 뿐만 아니라 중위, 후위 등등 최소 2개의 순서 정보만 있다면 실제 트리를 구현할 수 있다.

 

예를 들어 값 자체가 중위 순회 순서 값으로 이루어진 다음과 같은 트리를 보자

 

전위와 중위의 순서를 위 순서와 같다고 할 때 

다음과 같은 특징을 알 수 있다.

 

전위의 첫번째 값인 5는 곧 전체트리의 루트노드가 된다.

그럼 전체 트리중 5의 left 와 right는 어떻게 구별해야하나?

그것은 중위 순회의 순서에서 5를 찾아주면 된다.

결국 중위순회의 [0]~[4]번째까지는 5의 left 자식이 되고 [6]~[12]번째까지는 5의 right 자식이 된다

==> 전위 기준 [1]~[5]번째까지는 left의 자식, [6]~[12]번째까지는 5의 right 자식이 된다

 

결국 left, right를 나누는 기준은 전위, 중위의 배열 인덱스를 이용해서 현재 트리의 루트를 찾고 좌 우 를 나누는 것이다

 

이 특정 구간들을 다음과 같은 재귀문을 통해서 트리를 만들 수 있다.

 

order[] : 전위 순회의 순서가 들어간 배열

node[] : 중위 순회 순서의 값을 weight로 가지는 각 노드들

(node[]의 경우는 쉬운 예를 위해 이런식으로 표현한 것이고, 애초에 중위 순서가 주어진다면

이 순서를 배열에 넣고 사용하면 된다. 이 경우는 아예 값 자체를 중위 순회 순서로 넣은 것이니 착각하지말자)

1
2
3
4
5
6
7
8
9
void make_tree() {
    root = &node[order[0]];
 
    root->left = left_tree(0, order[0- 11);
    root->right = right_tree(order[0+ 1, tree_size - 1, order[0+ 1);
 
    if (root->left != NULL) root->left->parent = root;
    if (root->right != NULL) root->right->parent = root;
}
 

전역 변수 root는 order[0] (전위 순회의 첫번째 값) 을 루트노드로 가진다.

이 root의 left와 right에 다음과 같은 함수를 적용할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
tree* right_tree(int l, int r, int idx) {
    return left_tree(l, r, idx);
}
 
tree* left_tree(int l, int r, int idx) {
    if (!(l <= r && idx < tree_size)) return NULL;
    tree* now = &node[order[idx]];
 
    if (l == r) return now;
 
    int next = order[idx];
    now->left = left_tree(l, next - 1, idx + 1);
    now->right = right_tree(next + 1, r, idx + (next - l) + 1);
 
    if (now->left != NULL) now->left->parent = now;
    if (now->right != NULL) now->right->parent = now;
 
    return now;
}
 

 

함수에서는 현재 노드를 루트로 보고 좌우의 트리를 반환받은 후에 루트노드를 리턴하는 형식이기 때문에 

결국 트리를 만드는 부분은 결국 left_tree 나 right_tree 가 같다고 볼 수 있다.

 

코드를 간단하게 설명하자면

중위 순회 : 0 1 2 3 4 5 6 7 ,,,

전위 순회 : 5 3 1 0 2 4 7 6 ... 

tree 함수는 다음과 같은 동작을 하게 된다

L,R 을 중위순회의 인덱스, idx 를 전위순회의 인덱스에 두고 좌 우를 찾게 된다

 

첫번째 left_tree를 기준으로

L : 0, R : 4, idx : 1 이다

order[idx] 는 3이 되고, 이 의미는 5의 좌측에 들어갈 루트노드가 3이 됨을 의미한다.

이 3을 중위 순회에서 몆번째 인덱스에 있는지 찾는다. (지금은 값 자체기 때문에 3이 된다)

중위 순회의 3번째 인덱스에 3이 있으므로, 3의 좌측에 들어갈 노드는

3 - 0(=> L이 0이므로) = 3개가 된다.

3의 좌측트리를 left_right(L, 3-1, idx+1) 의 반환값으로 호출 => 노드 0, 1, 2 를 3의 좌측트리에서 만든다

3의 우측트리를 right(3+1, R, idx+(3-L)+1) 의 반환값으로 호출 => 노드 4 를 3의 우측트리에서 만든다

 

다시 한번 말하지만

중위 순회를 0, 1, 2, 3, ... 순서대로 예를 든 것이기 때문에 L,R,next 같은 매개인자를 사용할 수 있는 것이고

애초에 이런식이 아닌 중위 순회의 값을 배열에 넣고 호출하는게 일반적일 것이다.

+ Recent posts