예, 시간 에이 압축을 수행 할 수 는 있지만 쉽지는 않습니다. :) 먼저 몇 가지 관찰을 한 다음 알고리즘을 제시합니다. 트리가 처음에 압축되지 않았다고 가정합니다. 실제로 필요하지는 않지만 분석이 더 쉬워집니다.O(nlogn)
첫째, 우리는 '구조적 평등'을 귀납적으로 특징 짓는다. 와 T ' 를 두 개의 (서브 트리) 트리 라고 하자 . 경우 T 와 T가 ' (전혀 정점이없는) 널 나무는 모두, 그들은 구조적으로 동일합니다. 경우 T 와 T는 ' 모두 null이 아닌 나무입니다, 그들은 자신의 왼쪽 아이들이 구조적으로 동일하고 권리 아이들이 구조적으로 동일 IFF에 구조적으로 동일합니다. '구조적 동등성'은 이러한 정의에 대한 최소한의 고정 점입니다.TT′TT′TT′
예를 들어, 두 개의 리프 노드는 둘 다 하위 트리로 널 트리를 가지므로 구조적으로 동일합니다.
'그들의 왼쪽 아이들은 구조적으로 동등하고 그들의 오른쪽 아이들도 마찬가지입니다'라고 말하는 것이 오히려 성가 시므로, 우리는 종종 '자녀들이 구조적으로 동일하다'고 말하고 같은 것을 의도합니다. 또한 '이 꼭짓점에 뿌리를 둔 하위 트리'를 의미 할 때 때때로 '이 꼭짓점'이라고 말합니다.
위의 정의는 압축을 수행하는 방법에 대한 힌트를 즉시 제공합니다. 깊이가 최대 인 모든 하위 트리의 구조적 동등성을 알고 있으면 깊이 d + 1 인 하위 트리의 구조적 동등성을 쉽게 계산할 수 있습니다 . 우리는 O ( n 2 ) 실행 시간 을 피하기 위해 현명한 방법으로이 계산을 수행해야합니다 .dd+1O(n2)
알고리즘은 실행 중에 모든 정점에 식별자를 할당합니다. 식별자는 집합 의 숫자입니다 . 식별자는 고유하며 절대 변경되지 않습니다. 따라서 알고리즘 시작시 일부 (전역) 변수를 1로 설정하고 일부 정점에 식별자를 할당 할 때마다 해당 변수의 현재 값을 정점에 할당하고 증분합니다 해당 변수의 값{ 1 , 2 , 3 , … , n }
먼저 입력 트리를 부모에 대한 포인터와 함께 같은 깊이의 정점을 포함하는 (최대 ) 목록 으로 변환합니다 . 이것은 O ( n ) 시간 안에 쉽게 수행됩니다 .엔O ( n )
먼저 모든 나뭇잎을 압축합니다 (이 나뭇잎을 깊이 0의 정점으로 목록에서 찾을 수 있음)를 단일 꼭지점으로 압축합니다. 이 정점에 식별자를 할당합니다. 두 정점의 압축은 한 정점의 부모를 대신 다른 정점을 가리 키도록 리디렉션하여 수행됩니다.
우리는 두 가지 관찰을합니다 : 첫째, 모든 정점은 깊이가 더 작은 자식을 가지며, 두 번째로, 보다 작은 모든 깊이의 정점에 대해 압축을 수행 한 경우 (그리고 식별자를 부여한 경우), 깊이 d 의 두 정점 이 구조적으로 동일합니다. 자녀의 식별자가 일치하면 압축 될 수 있습니다. 이 마지막 관찰은 다음과 같은 논증에서 비롯됩니다. 두 정점이 자녀가 구조적으로 동등한 경우 구조적으로 동일하며 압축 후 포인터가 동일한 자식을 가리키고 있음을 의미하며, 이는 자식의 식별자가 동일 함을 의미합니다.디디
우리는 작은 깊이에서 큰 깊이까지 같은 깊이의 노드로 모든 목록을 반복합니다. 모든 레벨에 대해 정수 쌍의 목록을 작성합니다. 여기서 모든 쌍은 해당 레벨에서 일부 정점의 자식 식별자에 해당합니다. 해당 수준의 두 정점이 해당 정수 쌍이 같으면 구조적으로 동일합니다. 사전 식 순서를 사용하여이를 정렬하고 동일한 정수 쌍 세트를 얻을 수 있습니다. 위와 같이 이러한 집합을 단일 정점으로 압축하고 식별자를 제공합니다.
위의 관찰은이 접근 방식이 작동하고 압축 트리를 생성 함을 증명합니다. 총 실행 시간은 에 우리가 만든 목록을 정렬하는 데 필요한 시간을 더한 것입니다. 우리가 생성하는 정수 쌍의 총 개수는 n 이므로, 필요한 총 실행 시간은 O ( n log n ) 입니다. 프로 시저 마지막에 남은 노드 수를 계산하는 것은 쉽지 않습니다 (유인한 식별자 수를 살펴보십시오).O ( n )엔O ( n 로그n )