Обчисліть мінімальні операції, щоб зробити дві ідентичні деревні структури


81

Це більше питання CS, але цікаве:

Скажімо, у нас є 2 деревоподібні структури з більш-менш однаковими вузлами, реорганізованими. Як би ти знайшов

  1. будь-який
  2. в якомусь сенсі мінімальна

послідовність операцій

  • MOVE(A, B) - переміщує вузол A під вузол B (з усім піддеревом)
  • INSERT(N, B)- вставляє новий вузол N під вузол B
  • DELETE (A) - видаляє вузол A (з усім піддеревом)

що перетворює одне дерево на інше.

Очевидно, можуть бути випадки, коли таке перетворення неможливе, тривіальним є корінь А з дочірнім Б до кореневого Б з дочірнім А тощо). У таких випадках алгоритм просто дав би результат " неможливо ".

Ще більш вражаюча версія - це узагальнення для мереж, тобто коли ми припускаємо, що вузол може траплятися кілька разів у дереві (фактично маючи декількох "батьків"), тоді як цикли заборонені.

Застереження: Це не домашнє завдання, насправді воно походить від реальної ділової проблеми, і мені було досить цікаво, цікаво, чи хтось може знати рішення.


MOVE(A,B)здається таким самим, INSERT(A,B)ніби Aне має дітей. Що станеться з дітьми, Aякщо хтось так зробить INSERT(A,B)? (вони будуть прив'язані до Aбатьків?)
Андре Хольцнер,

різниця полягає в тому, що INSERT означає насправді новий вузол, який раніше не знаходився в дереві (отже, не маючи дітей, принаймні не в початковому стані, де його навіть не було). З іншого боку, MOVE - це дійсно хід, тобто переміщення вузла, включаючи його дітей
Tomas Vana,

11
Це схоже на те, що вам потрібно виявити ізоморфізм графа . Частина про перетворення нагадує мені відстань Левенштейна , яку можна акуратно вирішити за O (n * m) за допомогою динамічного програмування. Можливо, ці вказівники вам допоможуть.
Björn Pollex

Ви коли-небудь придумували рішення? Переглядаючи статтю Вікіпедії та посилання на посилання, я ніде не бачу алгоритму. Я хотів би зробити це в javascript, де я вже знаю оригінальні операції, через які два дерева відрізнялися, але хотів би створити необов’язковий різницю: наприклад, якщо частина дерева була обрізана, а потім знову прищеплена до того самого місця це оптимізувало б без змін.
Michael

@ Майкл, ти знайшов щось корисне? Я спостерігаю за тим самим алгоритмом зменшення змін у дереві.
Павло

Відповіді:


25

Існує не тільки стаття Вікіпедії про ізоморфізм графа (як зазначає Space_C0wb0y), але також спеціальна стаття про проблему ізоморфізму графа . У ньому є розділ, Solved special casesдля якого відомі розв’язки за часом поліномів. Дерева - одне з них, і воно посилається на такі два посилання:


16

Вам не було зрозуміло, чи порівнюєте абстрактні дерева синтаксису для вихідного коду, XML-документів, які інтерпретуються як дерева, або якихось інших типів дерев.

Існує ряд робіт, в яких обговорюється порівняння дерев синтаксису та обчислення мінімальних відстаней різними способами. Ідеї ​​повинні бути актуальними.

Хорошим документом є Change Distilling , який намагається порівняти вихідний код для двох абстрактних дерев синтаксису та повідомити про мінімальну різницю. У статті йдеться про конкретний метод, а також коротко згадується (і надається посилання) на безліч подібних методів.

Деякі з цих алгоритмів насправді реалізовані в доступних інструментах для порівняння вихідного тексту комп’ютерної програми. Наш розумний відмінник - один із них; це зумовлено явною граматикою мови для багатьох мов.


2
Насправді, в нашому випадку це не вихідний код, це справді дерева. У цих деревах є певна семантика, але в цілому не так важливо - ними безпосередньо маніпулюють користувачі як деревом
Томаш Вана,

Поламане посилання: Я щойно витратив 20 хвилин на пошук паперу "Змінити перегонку". Ось оновлене посилання: merlin.uzh.ch/publication/show/2531 Сам програмний проект перемістився на bitbucket.org/sealuzh/tools-changedistiller/wiki/Home (саме так я отримав правильне посилання на PDF)
Shalom Craimer

13

Хоча це питання застаріле, я додаю ще пару посилань та алгоритмів нижче:

  1. X-Diff: Ефективний алгоритм виявлення змін для XML-документів, Юань Ван, Девід Дж. Девітт, Цзінь-І Цай
  2. KF-Diff +: високоефективний алгоритм виявлення змін для XML-документів
  3. diffX: Алгоритм виявлення змін у багатоверсійних документах XML
  4. Виявлення змін у деревах XML: опитування, Луук Петерс
  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. Чим ближче до нуля, тим тісніше пов'язані два дерева до jqgram. Одним із підходів може бути використання jqgram для звуження кількох тісно пов’язаних між собою дерев з-поміж багатьох дерев, враховуючи його швидкість, а потім використовувати справжню відстань редагування на кількох деревах, що залишилися, які вам потрібно уважніше оглянути, і для цього ви можете знайти python реалізації для посилання або порту алгоритму Чжан і Шаша, наприклад.

Зауважте, що параметри lfn та cfn визначають, як кожне дерево має самостійно визначати імена міток вузлів та дочірній масив для кожного кореня дерева, щоб ви могли робити такі забавні речі, як порівняння об'єкта з DOM браузера, наприклад. Все, що вам потрібно зробити, - це надати ці функції разом із кожним коренем, а все інше зробить jqgram, викликаючи ваші функції lfn та cfn для побудови дерев. Тож у цьому сенсі (на мій погляд у будь-якому випадку) набагато простіший у використанні, ніж PyGram. Плюс, його Javascript, тому використовуйте його на клієнтській або серверній стороні!

ТАКОЖ, щоб відповісти щодо виявлення циклу, перевірте метод клонування всередині jqgram, там є виявлення циклу, але заслуга в цьому належить автору вузла-клону, з якого цей фрагмент був трохи змінений і включений.


чи дозволяє це декілька lfn? Я хочу відповідати більше, ніж ярлик, тобто. також збережене значення. node.value.
john ktejik,

0

Це називається проблемою корекції дерева або дерева або проблемою редагування дерева . Більша частина літератури, що займається цим, явно стосується порівняння дерев XML з якихось причин, тому пошук "алгоритму різниці XML" дає багато результатів. На додаток до списку посилань Нікоса, я знайшов і такі:

Я також настійно рекомендую прочитати Виявлення змін у деревах XML: опитування, але це з 2005 року, тому ледве будь-який із зазначених у ньому інструментів уже існує. Порівняння XML-документів як упорядкованих дерев із позначеними посиланнями має найкращий інтуїтивний опис деяких алгоритмів, які я знайшов на сьогодні (початок у розділі 2.1.2).

На жаль, здається, що не так багато відкритого коду, який робить це і не є давнім. Просто багато надто складних статей. : - /


Однак я не можу побачити цей документ, чи не пошкоджено посилання у форматі PDF? Change Detection in XML Trees: a Survey
Менго

Працює для мене. Ви натиснули Download full-test PDFкнопку? Можливо, спробуйте Sci-hub, якщо він з якихось причин заблокований.
Тімммм
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.