Tính toán các phép toán tối thiểu để tạo hai cấu trúc cây giống hệt nhau


81

Đây là một câu hỏi CS nhiều hơn, nhưng là một câu hỏi thú vị:

Giả sử chúng ta có 2 cấu trúc cây với nhiều hơn hoặc ít hơn các nút giống nhau được tổ chức lại. Làm thế nào bạn sẽ tìm thấy

  1. bất kì
  2. theo nghĩa nào đó là tối thiểu

trình tự của chiến dịch

  • MOVE(A, B) - di chuyển nút A dưới nút B (với toàn bộ cây con)
  • INSERT(N, B)- chèn một nút mới N dưới nút B
  • DELETE (A) - xóa nút A (với toàn bộ cây con)

chuyển đổi cây này sang cây kia.

Rõ ràng là có thể có những trường hợp không thể thực hiện được phép chuyển đổi như vậy, nhỏ là gốc A với con B thành gốc B với con A, v.v.). Trong những trường hợp như vậy, thuật toán sẽ chỉ đưa ra kết quả " không thể ".

Phiên bản ngoạn mục hơn nữa là sự tổng quát hóa cho các mạng, tức là khi chúng ta giả định rằng một nút có thể xuất hiện nhiều lần trong cây (thực sự có nhiều "cha mẹ"), trong khi các chu kỳ bị cấm.

Tuyên bố từ chối trách nhiệm: Đây không phải là bài tập về nhà, thực ra nó xuất phát từ một vấn đề kinh doanh thực sự và tôi thấy khá thú vị khi tự hỏi liệu ai đó có thể biết giải pháp hay không.


MOVE(A,B)dường như vẫn giống như INSERT(A,B)thể Akhông có bất kỳ đứa con nào. Điều gì xảy ra với con cái của Anếu một trong số đó INSERT(A,B)? (liệu họ có gắn bó với Acha mẹ của mình không?)
Andre Holzner

sự khác biệt là INSERT thực sự có nghĩa là một nút mới, trước đó không có trong cây (do đó không có bất kỳ nút con nào, ít nhất là không ở trạng thái ban đầu, nơi nó thậm chí không có mặt). MOVE mặt khác thực sự là một bước đi, tức là di chuyển của nút kể cả trẻ em của nó
Tomas Vana

11
Điều này có vẻ như bạn cần phát hiện hiện tượng đẳng cấu đồ thị . Phần về sự biến đổi làm tôi nhớ đến khoảng cách Levenshtein , khoảng cách này có thể được giải quyết gọn gàng bằng O (n * m) bằng cách sử dụng lập trình động. Có thể những gợi ý này sẽ giúp bạn.
Björn Pollex

Bạn đã bao giờ nghĩ ra một giải pháp? Nhìn vào bài báo wikipedia và các tài liệu tham khảo được liên kết, tôi không thấy một thuật toán nào cả. Tôi muốn thực hiện việc này trong javascript nơi tôi đã biết các thao tác ban đầu làm cho hai cây khác nhau, nhưng muốn tạo ra sự khác biệt tùy chọn: ví dụ: nếu một phần của cây được cắt tỉa và sau đó được ghép lại vào cùng một điểm nó sẽ tối ưu hóa để không thay đổi.
Michael

@Michael, bạn đã tìm thấy thứ gì hữu ích chưa? Tôi đang xem cho cùng một alhoritm của sự giảm thay đổi trong cây.
Pavel

Câu trả lời:


25

Không chỉ có một bài viết trên Wikipedia về đẳng cấu biểu đồ (như Space_C0wb0y đã chỉ ra) mà còn có một bài báo dành riêng về vấn đề đẳng cấu biểu đồ . Nó có một phần Solved special casesmà các nghiệm thời gian đa thức được biết đến. Cây cối là một trong số đó và nó trích dẫn hai tài liệu tham khảo sau:


16

Bạn không rõ bạn đang so sánh cây cú pháp trừu tượng cho mã nguồn, tài liệu XML được hiểu là cây hay một số loại cây khác.

Có một số bài báo thảo luận về việc so sánh cây cú pháp và tính toán khoảng cách tối thiểu bằng nhiều phương tiện khác nhau. Các ý tưởng phải có liên quan.

Một bài báo hay là Change Distilling , nó cố gắng so sánh mã nguồn cho hai cây cú pháp trừu tượng và báo cáo một sự khác biệt nhỏ nhất. Bài báo nói về một phương pháp cụ thể, và breifly cũng đề cập (và cung cấp tài liệu tham khảo) đến nhiều kỹ thuật tương tự.

Rất ít thuật toán này thực sự được thực hiện trong các công cụ có sẵn để so sánh văn bản nguồn chương trình máy tính. Smart Differencer của chúng tôi là một trong số đó; nó được thúc đẩy bởi một ngữ pháp ngôn ngữ rõ ràng cho nhiều ngôn ngữ.


2
Trên thực tế, trong trường hợp của chúng tôi, nó không phải là mã nguồn, đây thực sự là những cái cây. Có một số ngữ nghĩa trong những cây cối, nhưng tất cả trong tất cả không phải là quan trọng - họ đang thao tác trực tiếp bởi người sử dụng như một cây
Tomas Vana

Liên kết bị hỏng: Tôi vừa dành 20 phút để tìm bài báo "Thay đổi cách chưng cất". Đây là liên kết được cập nhật: merlin.uzh.ch/publication/show/2531 Bản thân dự án phần mềm đã chuyển sang bitbucket.org/sealuzh/tools-changedistiller/wiki/Home (đó là cách tôi lấy liên kết chính xác đến tệp PDF)
Shalom Craimer

13

Mặc dù câu hỏi này đã cũ, nhưng tôi sẽ thêm một số tài liệu tham khảo và thuật toán bên dưới:

  1. X-Diff: Một thuật toán phát hiện thay đổi hiệu quả cho tài liệu XML, Yuan Wang, David J. DeWitt, Jin-Yi Cai
  2. KF-Diff +: Thuật toán phát hiện thay đổi hiệu quả cao cho tài liệu XML
  3. diffX: Một thuật toán để phát hiện các thay đổi trong tài liệu XML nhiều phiên bản
  4. Phát hiện thay đổi trong cây XML: một cuộc khảo sát, Luuk Peters
  5. Sự giống nhau trong cấu trúc dữ liệu dạng cây

Hơn nữa, có các thư viện và khuôn khổ trên GitHub (bằng javascript) triển khai các cấu trúc dạng Cây khác nhau, ví dụ các ứng dụng xử lý dữ liệu JSON hoặc Cây XML (ví dụ: cho MVC / MVVM phía máy khách):

  1. React.js
  2. JSON-Patch
  3. jsondiffpatch
  4. objectDiff

Thực sự khuyên bạn nên đọc Change Detection in XML Trees: a Surveybài báo - nó liệt kê hàng chục thuật toán cho sự khác biệt của XML (chỉ là sự khác biệt của cây).
Timmmm

8

Trong trường hợp mọi người tìm thấy câu hỏi này và cần một thứ gì đó được triển khai cho Node.js hoặc trình duyệt, tôi cung cấp một liên kết và ví dụ mã cho một triển khai mà tôi đã viết mà bạn có thể tìm thấy trên github tại đây: ( https://github.com /hoonto/jqgram.git ) dựa trên mã PyGram Python hiện có ( https://github.com/Sycondaman/PyGram ).

Đây là thuật toán xấp xỉ khoảng cách chỉnh sửa cây , nhưng nó nhanh hơn rất nhiều so với việc cố gắng tìm khoảng cách chỉnh sửa thực sự. Phép tính gần đúng thực hiện trong thời gian O (n log n) và không gian O (n) trong khi khoảng cách hiệu chỉnh thực thường là O (n ^ 3) hoặc O (n ^ 2) bằng cách sử dụng các thuật toán đã biết cho khoảng cách hiệu chỉnh đúng. Xem tài liệu học thuật sử dụng thuật toán PQ-Gram: ( http://www.vldb2005.org/program/paper/wed/p301-augsten.pdf )

Vì vậy, sử dụng jqgram:

Thí dụ:

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);
});

Và điều đó mang lại cho bạn một số từ 0 đến 1. Càng gần 0, hai cây càng có liên quan chặt chẽ với jqgram. Một cách tiếp cận có thể là sử dụng jqgram để thu hẹp một số cây có liên quan chặt chẽ trong số nhiều cây với tốc độ của nó, sau đó sử dụng khoảng cách chỉnh sửa thực trên một vài cây còn lại mà bạn cần kiểm tra kỹ hơn và bạn có thể tìm thấy python triển khai để tham chiếu hoặc cổng của thuật toán Zhang & Shasha chẳng hạn.

Lưu ý rằng các tham số lfn và cfn chỉ định cách mỗi cây xác định tên nhãn nút và mảng con cho từng gốc cây một cách độc lập để bạn có thể làm những việc thú vị như so sánh một đối tượng với DOM của trình duyệt chẳng hạn. Tất cả những gì bạn cần làm là cung cấp các hàm đó cùng với mỗi gốc và jqgram sẽ thực hiện phần còn lại, gọi các hàm được cung cấp lfn và cfn của bạn để xây dựng cây. Vì vậy, theo quan điểm của tôi, nó (theo ý kiến ​​của tôi dù sao) dễ sử dụng hơn nhiều so với PyGram. Thêm vào đó, Javascript của nó, vì vậy hãy sử dụng nó ở phía máy khách hoặc phía máy chủ!

CŨNG, để trả lời liên quan đến phát hiện chu kỳ, hãy kiểm tra phương pháp sao chép bên trong jqgram, có phát hiện chu kỳ ở đó, nhưng tín dụng cho điều đó thuộc về tác giả của bản sao nút mà từ đó phần đó đã được sửa đổi một chút và đưa vào.


điều này có cho phép nhiều lfn không? Tôi muốn phù hợp hơn với nhãn, tức là. cũng là giá trị được lưu trữ. node.value.
john ktejik

0

Đây được gọi là vấn đề chỉnh sửa cây thành cây hoặc vấn đề chỉnh sửa cây thành cây . Hầu hết các tài liệu liên quan đến vấn đề này một cách rõ ràng liên quan đến việc so sánh các cây XML vì một số lý do, vì vậy việc tìm kiếm "thuật toán khác biệt của XML" mang lại rất nhiều kết quả. Ngoài danh sách các liên kết của Nikos, tôi tìm thấy những thứ sau:

Tôi cũng thực sự khuyên bạn nên đọc Phát hiện thay đổi trong cây XML: một cuộc khảo sát nhưng nó có từ năm 2005 nên hầu như không có bất kỳ công cụ nào mà nó đề cập còn tồn tại nữa. So sánh Tài liệu XML như Câythứ tự được gắn nhãn nhận biết Tham chiếu có mô tả trực quan tốt nhất về một số thuật toán mà tôi đã tìm thấy cho đến nay (bắt đầu từ phần 2.1.2).

Thật không may, dường như không có nhiều mã nguồn mở có sẵn để làm điều này và không phải là cổ điển. Chỉ là nhiều giấy tờ quá phức tạp. : - /


Tuy nhiên, tôi không thể nhìn thấy tờ giấy này, liên kết pdf có bị hỏng không? Change Detection in XML Trees: a Survey
Mengo

Làm việc cho tôi. Bạn đã nhấp vào Download full-test PDFnút? Có thể thử Sci-hub nếu nó bị chặn vì lý do nào đó.
Timmmm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.