最小限の操作を計算して、2つのツリー構造を同一にします


81

これはCSの質問ですが、興味深い質問です。

多かれ少なかれ同じノードが再編成された2つのツリー構造があるとしましょう。どのように見つけますか

  1. どれか
  2. ある意味で最小限

操作のシーケンス

  • MOVE(A, B) -ノードAをノードBの下に移動します(サブツリー全体を含む)
  • INSERT(N, B)-ノードBの下に新しいノードNを挿入します
  • DELETE (A) -ノードAを削除します(サブツリー全体を含む)

これは、あるツリーを別のツリーに変換します。

明らかに、そのような変換が不可能な場合があります。たとえば、ルートAと子Bから、ルートBと子Aなどです。このような場合、アルゴリズムは単に「不可能結果をもたらします。

さらに壮観なバージョンは、ネットワークの一般化です。つまり、ノードがツリー内で複数回発生する可能性がある(事実上複数の「親」を持つ)と想定し、サイクルは禁止されています。

免責事項:これは宿題ではありません。実際には実際のビジネス上の問題から来ているので、誰かが解決策を知っているのではないかと思うと非常に興味深いと思いました。


MOVE(A,B)同じように見えるINSERT(A,B)場合はA子を持っていません。Aもしそうしたら、子供たちはどうなりINSERT(A,B)ますか?(それらはAの親に添付されますか?)
Andre Holzner 2011

違いは、INSERTは、以前はツリーになかった(したがって、少なくとも子が存在していなかった元の状態ではない)実際には新しいノードを意味することです。一方、MOVEは実際には移動です。つまり、子を含むノードの移動
Tomas Vana

11
これは、グラフ同型を検出する必要があるようです。変換に関する部分は、動的計画法を使用してO(n * m)で適切に解くことができるレーベンシュタイン距離を思い出させます。たぶん、これらのポインタはあなたを助けます。
ビョルンポレックス2011

解決策を思いついたことがありますか?ウィキペディアの記事とリンクされた参照を見ると、どこにもアルゴリズムがありません。これをjavascriptで実行したいのですが、2つのツリーを異なるものにした元の操作をすでに知っていますが、オプションの差分を生成したいと思います。たとえば、ツリーの一部が剪定されてから同じ場所に再移植された場合などです。変更なしに最適化されます。
マイケル

@マイケル、何か役に立つものを見つけましたか?私は、ツリーの変化の減少の同じアルゴリズムを監視しています。
Pavel

回答:


25

グラフ同型に関するウィキペディアの記事(Space_C0wb0yが指摘しているように)だけでなく、グラフ同型問題に関する専用の記事もありますSolved special cases多項式時間解が知られているセクションがあります。木はそれらの1つであり、次の2つの参照を引用しています。


16

ソースコードの抽象構文木、ツリーとして解釈されるXMLドキュメント、またはその他の種類のツリーを比較しているかどうかが明確ではありませんでした。

構文木の比較とさまざまな方法による最小距離の計算について説明している論文はたくさんあります。アイデアは関連している必要があります。

良い論文はChangeDistillingです。これは、2つの抽象構文ツリーのソースコードを比較し、最小限の違いを報告しようとします。このホワイトペーパーでは、特定の方法について説明し、さまざまな同様の手法について簡単に言及(および参照)しています。

これらのアルゴリズムのいくつかは、コンピュータプログラムのソーステキストを比較するために利用可能なツールで実際に実現されています。私たちのスマートディファレンサーはその1つです。これは、多くの言語の明示的な言語文法によって駆動されます。


2
実際、私たちの場合、それはソースコードではなく、これらは実際にはツリーです。これらのツリーにはいくつかのセマンティクスがありますが、全体としてそれほど重要ではありません。ユーザーがツリーとして
Tomas Vana

リンク切れ:「ChangeDistilling」の論文を探すのに20分かかりました。更新されたリンクは次のとおりです。merlin.uzh.ch / publication / show / 2531 ソフトウェアプロジェクト自体がbitbucket.org/sealuzh/tools-changedistiller/wiki/Homeに移動しました(これがPDFへの正しいリンクを取得する方法です)
Shalom Craimer 2016

13

この質問は古いものですが、以下にいくつかの参照とアルゴリズムを追加します。

  1. X-Diff:XMLドキュメントの効果的な変更検出アルゴリズム、Yuan Wang、David J. DeWitt、Jin-Yi Cai
  2. KF-Diff +:XMLドキュメント用の非常に効率的な変更検出アルゴリズム
  3. diffX:マルチバージョンXMLドキュメントの変更を検出するアルゴリズム
  4. XMLツリーでの変更検出:調査、Luuk Peters
  5. ツリーデータ構造の類似性

さらに、GitHub(javascript)には、JSONデータやXMLツリーを処理するアプリケーション(クライアント側のMVC / MVVMなど)など、ツリーのような構造の差分を実装するライブラリとフレームワークがあります。

  1. React.js
  2. JSONパッチ
  3. jsondiffpatch
  4. objectDiff

このChange Detection in XML Trees: a Survey論文を読むことを強くお勧めします-XML差分(単なるツリー差分)のための数十のアルゴリズムがリストされています。
Timmmm

8

人々がこの質問を見つけて、Node.jsまたはブラウザー用に実装されたものが必要な場合に備えて、私が書いた実装のリンクとコード例を提供します。これはgithubで見つけることができます:(https://github.com /hoonto/jqgram.git)既存のPyGram Pythonコード(https://github.com/Sycondaman/PyGram)に基づいています

これはツリー編集距離近似アルゴリズムですが、実際の編集距離を見つけようとするよりもはるかに高速です。近似はO(n log n)時間とO(n)空間で実行されますが、真の編集距離は、多くの場合、真の編集距離の既知のアルゴリズムを使用してO(n ^ 3)またはO(n ^ 2)です。PQ-Gramアルゴリズムの元となった学術論文を参照してください:(http://www.vldb2005.org/program/paper/wed/p301-augsten.pdf

したがって、jqgramを使用します。

例:

var jq = require("jqgram").jqgram;
var root1 = {
    "thelabel": "a",
    "thekids": [
        { "thelabel": "b",
        "thekids": [
            { "thelabel": "c" },
            { "thelabel": "d" }
        ]},
        { "thelabel": "e" },
        { "thelabel": "f" }
    ]
}

var root2 = {
    "name": "a",
    "kiddos": [
        { "name": "b",
        "kiddos": [
            { "name": "c" },
            { "name": "d" },
            { "name": "y" }
        ]},
        { "name": "e" },
        { "name": "x" }
    ]
}

jq.distance({
    root: root1,
    lfn: function(node){ return node.thelabel; },
    cfn: function(node){ return node.thekids; }
},{
    root: root2,
    lfn: function(node){ return node.name; },
    cfn: function(node){ return node.kiddos; }
},{ p:2, q:3 },
function(result) {
    console.log(result.distance);
});

そして、それはあなたに0と1の間の数を与えます。ゼロに近いほど、2つのツリーはjqgramに密接に関連しています。1つのアプローチは、jqgramを使用して、速度を考慮して多くのツリーの中から密接に関連するいくつかのツリーを絞り込み、残りのいくつかのツリーで実際の編集距離を利用して、詳細に調べる必要があります。そのために、Pythonを見つけることができます。たとえば、Zhang&Shashaアルゴリズムの参照または移植のための実装。

lfnパラメーターとcfnパラメーターは、各ツリーがノードラベル名と各ツリールートの子配列を個別に決定する方法を指定するため、たとえば、オブジェクトをブラウザーDOMと比較するなどのファンキーなことができることに注意してください。あなたがする必要があるのは、各ルートと一緒にそれらの関数を提供することだけであり、jqgramが残りを行い、ツリーを構築するためにあなたのlfnとcfnが提供する関数を呼び出します。その意味で、(とにかく私の意見では)PyGramよりもはるかに使いやすいです。さらに、そのJavascriptなので、クライアント側またはサーバー側で使用してください。

また、サイクル検出に関して答えるために、jqgram内のクローンメソッドをチェックしてください。そこにはサイクル検出がありますが、その功績は、その部分がわずかに変更されて含まれているノードクローンの作成者にあります。


これは複数のlfnを許可しますか?ラベル以上に一致させたい、つまり。また、保存された値。node.value。
johnktejik18年

0

これは、ツリー間修正問題またはツリー間編集問題と呼ばれます。これを扱っている文献のほとんどは、何らかの理由でXMLツリーの比較に明示的に関連しているため、「XML差分アルゴリズム」を検索すると多くの結果が得られます。Nikosのリンクのリストに加えて、私はこれらを見つけました:

また、XMLツリーの変更検出:調査を読むことを強くお勧めしますが、これは2005年のものであるため、言及されているツールはほとんど存在しません。XMLドキュメントを参照対応のラベル付き順序付きツリーとして比較すると、これまでに見つけたいくつかのアルゴリズムについて最も直感的に説明できます(セクション2.1.2から開始)。

残念ながら、これを実行し、古くはないオープンソースコードはあまり利用できないようです。非常に複雑な論文がたくさんあります。:-/


私はこの論文を見ることができませんが、PDFリンクが壊れていますか? Change Detection in XML Trees: a Survey
メンゴ

私のために働きます。Download full-test PDFボタンをクリックしましたか?何らかの理由でブロックされている場合は、Sci-hubを試してみてください。
Timmmm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.