はい、この圧縮は時間で実行できますが、簡単ではありません:)最初にいくつかの観測を行ってから、アルゴリズムを示します。ツリーは最初は圧縮されていないと仮定します。これは実際には必要ではありませんが、分析を容易にします。O(nlogn)
まず、「構造的平等」を帰納的に特徴付けます。ましょうとTが「 2(サブ)の木も。場合TおよびTは' NULL木(全く頂点を有さない)の両方であり、それらは構造的に等価です。もしTT′TT′と Tは「両方ともNULLでない木です、そして、彼らは左の子供が構造的に同等であり、その右の子供が構造的に等価である場合に限っ構造的に等価です。「構造的等価」は、これらの定義の最小の不動点です。TT′
たとえば、2つのリーフノードは構造的に同等です。これは、両方の子が構造的に同等である両方の子としてnullツリーを持っているためです。
「彼らの左の子供は構造的に同等であり、彼らの右の子供も」と言うのはむしろ迷惑なので、しばしば「彼らの子供は構造的に同等」と言い、同じことを意図します。また、「この頂点をルートとするサブツリー」を意味するとき、「この頂点」と言うことがあります。
上記の定義は、圧縮の実行方法のヒントをすぐに提供します。深さが最大でのすべてのサブツリーの構造的等価性がわかっている場合、深さd + 1のサブツリーの構造的等価性を簡単に計算できます。O (n 2)の実行時間を避けるために、この計算をスマートな方法で行う必要があります。dd+1O (n2)
アルゴリズムは、実行中にすべての頂点に識別子を割り当てます。識別子は、セットの数であり。識別子は一意であり、変更されることはありません。したがって、アルゴリズムの開始時に何らかの(グローバル)変数を1に設定し、識別子を頂点に割り当てるたびに、その変数の現在の値を頂点に割り当て、インクリメントしますその変数の値。{ 1 、2 、3 、... 、N }
最初に、入力ツリーを、親へのポインターとともに、同じ深さの頂点を含む(最大)リストに変換します。これはOで簡単にできますn時間ます。O (n )
最初にすべてのリーフ(深さ0の頂点を持つリストでこれらのリーフを見つけることができます)を単一の頂点に圧縮します。この頂点に識別子を割り当てます。2つの頂点の圧縮は、いずれかの頂点の親をリダイレクトして、代わりに他の頂点を指すようにします。
次の2つの観測を行います。1つ目は、すべての頂点に厳密に小さい深度の子があり、2つ目は、dよりも小さい深度のすべての頂点に対して圧縮を実行した場合です。d(およびそれらの識別子を与えている)、そして深さの2つの頂点構造的に等価であり、子の識別子が一致する場合は圧縮できます。この最後の観察結果は次の引数から得られます:2つの頂点は、それらの子が構造的に同等である場合、構造的に同等です。圧縮後、これは、ポインターが同じ子を指していることを意味します。d
深さが小さいものから大きいものまで同じ深さのノードを使用して、すべてのリストを反復処理します。すべてのレベルについて、整数ペアのリストを作成します。すべてのペアは、そのレベルのある頂点の子の識別子に対応します。そのレベルの2つの頂点は、対応する整数ペアが等しい場合にのみ構造的に同等です。辞書編集順序を使用して、これらをソートし、等しい整数ペアのセットを取得できます。これらのセットを上記のように単一の頂点に圧縮し、それらに識別子を与えます。
上記の観察結果は、このアプローチが機能し、圧縮されたツリーが得られることを証明しています。合計実行時間はと作成したリストのソートに必要な時間です。作成する整数ペアの総数はnなので、必要に応じて、合計実行時間はO (n log n )になります。プロシージャの最後に残ったノードの数を数えるのは簡単です(配布した識別子の数を見てください)。O (n )nO ( n ログn )