Sự khác biệt giữa các phiên bản tìm kiếm đồ thị và tìm kiếm dạng cây liên quan đến các tìm kiếm DFS, A * trong trí tuệ nhân tạo là gì?
Sự khác biệt giữa các phiên bản tìm kiếm đồ thị và tìm kiếm dạng cây liên quan đến các tìm kiếm DFS, A * trong trí tuệ nhân tạo là gì?
Câu trả lời:
Đánh giá từ các câu trả lời hiện có, dường như có nhiều sự nhầm lẫn về khái niệm này.
Sự phân biệt giữa tìm kiếm dạng cây và tìm kiếm đồ thị không bắt nguồn từ thực tế là đồ thị bài toán là cây hay đồ thị tổng quát. Nó luôn được cho là bạn đang xử lý một biểu đồ chung. Sự khác biệt nằm ở mô hình truyền tải được sử dụng để tìm kiếm thông qua biểu đồ, có thể là hình biểu đồ hoặc hình cây.
Nếu bạn đang giải quyết một vấn đề hình cây , cả hai biến thể thuật toán đều dẫn đến kết quả tương đương. Vì vậy, bạn có thể chọn biến thể tìm kiếm cây đơn giản hơn.
Thuật toán tìm kiếm đồ thị cơ bản của bạn trông giống như sau. Với một nút bắt đầu start
, các cạnh có hướng như successors
và một goal
đặc tả được sử dụng trong điều kiện vòng lặp. open
giữ các nút trong bộ nhớ, hiện đang được xem xét, danh sách mở . Lưu ý rằng mã giả sau đây không đúng ở mọi khía cạnh (2).
open <- []
next <- start
while next is not goal {
add all successors of next to open
next <- select one node from open
remove next from open
}
return next
Tùy thuộc vào cách bạn triển khai select from open
, bạn có được các biến thể khác nhau của thuật toán tìm kiếm, như tìm kiếm theo chiều sâu (DFS) (chọn phần tử mới nhất), tìm kiếm đầu tiên theo chiều rộng (BFS) (chọn phần tử cũ nhất) hoặc tìm kiếm chi phí thống nhất (chọn phần tử có chi phí đường dẫn thấp nhất ), tìm kiếm sao hạng A phổ biến bằng cách chọn nút có chi phí thấp nhất cộng với giá trị heuristic , v.v.
Thuật toán nêu trên thực sự được gọi là tìm kiếm cây . Nó sẽ truy cập một trạng thái của biểu đồ vấn đề cơ bản nhiều lần, nếu có nhiều đường dẫn trực tiếp dẫn đến nó root ở trạng thái bắt đầu. Thậm chí có thể truy cập một trạng thái vô số lần nếu nó nằm trên một vòng lặp có hướng. Nhưng mỗi lượt truy cập tương ứng với một nút khác nhau trong cây được tạo bởi thuật toán tìm kiếm của chúng tôi. Sự kém hiệu quả rõ ràng này đôi khi được mong muốn, như được giải thích sau.
Như chúng ta đã thấy, tìm kiếm trên cây có thể truy cập một trạng thái nhiều lần. Và như vậy, nó sẽ khám phá "cây phụ" được tìm thấy sau trạng thái này vài lần, điều này có thể tốn kém. Tìm kiếm đồ thị khắc phục điều này bằng cách theo dõi tất cả các trạng thái đã truy cập trong một danh sách đóng . Nếu người kế nhiệm mới được tìm thấy next
đã được biết đến, nó sẽ không được đưa vào danh sách mở:
open <- []
closed <- []
next <- start
while next is not goal {
add next to closed
add all successors of next to open, which are not in closed
remove next from open
next <- select from open
}
return next
Chúng tôi nhận thấy rằng tìm kiếm đồ thị yêu cầu nhiều bộ nhớ hơn, vì nó theo dõi tất cả các trạng thái đã truy cập. Điều này có thể được bù đắp bởi danh sách mở nhỏ hơn, dẫn đến hiệu quả tìm kiếm được cải thiện.
Một số phương pháp thực hiện select
có thể đảm bảo trả về các giải pháp tối ưu - tức là một con đường ngắn nhất hoặc một con đường với chi phí tối thiểu (đối với đồ thị có chi phí gắn với các cạnh). Điều này về cơ bản đúng bất cứ khi nào các nút được mở rộng theo thứ tự tăng chi phí hoặc khi chi phí là một hằng số dương khác không. Một thuật toán phổ biến thực hiện loại lựa chọn này là tìm kiếm chi phí thống nhất hoặc nếu chi phí bước giống hệt nhau, BFS hoặc IDDFS . IDDFS tránh tiêu thụ bộ nhớ tích cực của BFS và thường được khuyến nghị cho tìm kiếm không có thông tin (hay còn gọi là brute force) khi kích thước bước không đổi.
Ngoài ra, thuật toán tìm kiếm cây A * (rất phổ biến) cung cấp một giải pháp tối ưu khi được sử dụng với một phương pháp kinh nghiệm có thể chấp nhận được . Tuy nhiên, thuật toán tìm kiếm đồ thị A * chỉ đảm bảo điều này khi nó được sử dụng với heuristic nhất quán (hoặc "đơn điệu") (một điều kiện mạnh hơn khả năng chấp nhận).
Để đơn giản, mã được trình bày không:
state
hay không , ngược lại với biểu đồ truyền tải, tùy thuộc vào ngữ cảnh. Nhưng việc sử dụng cho các đỉnh của đồ thị bài toán và cho đồ thị ngang có thể cải thiện rõ ràng sự rõ ràng của câu trả lời. Tôi sẽ cố gắng viết lại nó sớm. Cảm ơn bạn. node
state
node
Cây là một trường hợp đặc biệt của đồ thị, vì vậy bất cứ thứ gì phù hợp với đồ thị chung đều phù hợp với cây. Cây là một đồ thị trong đó có chính xác một đường đi giữa mỗi cặp nút. Điều này ngụ ý rằng nó không chứa bất kỳ chu trình nào, như câu trả lời trước đã nêu, nhưng một đồ thị có hướng không có chu trình (DAG, đồ thị xoay chiều có hướng) không nhất thiết phải là một cây.
Tuy nhiên, nếu bạn biết rằng biểu đồ của mình có một số hạn chế, chẳng hạn như đó là một cây hoặc một DAG, bạn thường có thể tìm thấy một số thuật toán tìm kiếm hiệu quả hơn so với một biểu đồ không bị giới hạn. Ví dụ: có lẽ không có ý nghĩa gì khi sử dụng A *, hoặc đối chứng không theo phương pháp heuristic của nó "thuật toán Dijkstra", trên một cây (nơi chỉ có một đường dẫn để chọn, bạn có thể tìm thấy bằng DFS hoặc BFS) hoặc trên một DAG (nơi có thể tìm thấy đường đi tối ưu bằng cách xem xét các đỉnh theo thứ tự thu được bằng cách sắp xếp topo).
Đối với đồ thị có hướng vs vô hướng, đồ thị vô hướng là trường hợp đặc biệt của đồ thị có hướng, cụ thể là trường hợp tuân theo quy tắc “nếu có một cạnh (liên kết, chuyển tiếp) từ u sang v thì cũng có một cạnh từ v đến u .
Cập nhật : Lưu ý rằng nếu điều bạn quan tâm là mô hình duyệt của tìm kiếm hơn là cấu trúc của biểu đồ, thì đây không phải là câu trả lời. Ví dụ, hãy xem câu trả lời của @ ziggystar.
Sự khác biệt duy nhất giữa biểu đồ và cây là chu kỳ . Một đồ thị có thể chứa các chu trình, một cây thì không. Vì vậy, khi bạn thực hiện một thuật toán tìm kiếm trên cây, bạn không cần phải xem xét sự tồn tại của các chu trình, nhưng khi làm việc với một đồ thị tùy ý, bạn sẽ cần phải xem xét chúng. Nếu bạn không xử lý các chu trình, thuật toán cuối cùng có thể rơi vào vòng lặp vô hạn hoặc đệ quy vô tận.
Một điểm khác cần suy nghĩ là các thuộc tính định hướng của biểu đồ mà bạn đang xử lý. Trong hầu hết các trường hợp, chúng tôi xử lý các cây đại diện cho mối quan hệ cha-con ở mỗi cạnh. Một DAG (đồ thị xoay chiều có hướng) cũng cho thấy các đặc điểm tương tự. Nhưng đồ thị hai chiều thì khác. Mỗi cạnh trong đồ thị hai hướng đại diện cho hai lân cận. Vì vậy, các cách tiếp cận thuật toán sẽ khác nhau một chút đối với hai loại đồ thị này.
ĐỒ HỌA VS CÂY
Nhưng trong trường hợp AI Graph-search so với Tree-search
Tìm kiếm đồ thị có một thuộc tính tốt đó là bất cứ khi nào thuật toán khám phá một nút mới và nó đánh dấu nó là đã được truy cập, "Bất kể thuật toán được sử dụng", thuật toán thường khám phá tất cả các nút khác có thể truy cập được từ nút hiện tại.
Ví dụ, hãy xem xét đồ thị sau với 3 đỉnh AB và C, và xét các cạnh sau
AB, BC và CA, Có một chu kỳ từ C đến A,
Và khi nào DFS bắt đầu từ A, A sẽ tạo ra trạng thái mới B, B sẽ tạo ra trạng thái mới C, nhưng khi C được khám phá, thuật toán sẽ cố gắng tạo ra trạng thái mới A nhưng A đã được truy cập nên nó sẽ bị bỏ qua. Mát mẻ!
Nhưng cây cối thì sao? Thuật toán cây tốt không đánh dấu nút đã thăm là đã thăm, nhưng cây không có chu kỳ, làm thế nào nó sẽ nhận được trong một vòng lặp vô hạn?
Xét Cây này có 3 đỉnh và xét các cạnh sau
A - B - C gốc tại A, hướng xuống. Và giả sử chúng ta đang sử dụng thuật toán DFS
A sẽ tạo ra một trạng thái mới B, B sẽ tạo ra hai trạng thái A & C, bởi vì Cây không có "Đánh dấu một nút đã thăm nếu nó được khám phá", do đó có thể thuật toán DFS sẽ khám phá lại A, do đó tạo ra một trạng thái B mới, do đó chúng ta đang vướng vào một vòng lặp vô hạn.
Nhưng bạn có nhận thấy điều gì đó, chúng tôi đang làm việc trên các cạnh vô hướng tức là có một kết nối giữa AB và BA. tất nhiên đây không phải là một chu trình, bởi vì chu trình ngụ ý rằng các đỉnh phải> = 3 và tất cả các đỉnh là phân biệt ngoại trừ các nút đầu tiên và cuối cùng.
ST A-> B-> A-> B-> A nó không phải là một chu trình vì nó vi phạm đặc tính chu kỳ> = 3. Nhưng thực sự A-> B-> C-> A là một chu trình> = 3 nút riêng biệt được kiểm tra, nút đầu tiên và nút cuối cùng được kiểm tra giống nhau.
Một lần nữa hãy xem xét các cạnh của cây, A-> B-> C-> B-> A, tất nhiên nó không phải là một chu trình, bởi vì có hai B, có nghĩa là không phải tất cả các nút đều khác biệt.
Cuối cùng, bạn có thể triển khai thuật toán tìm kiếm dạng cây, để ngăn việc khám phá cùng một nút hai lần. Nhưng điều đó có hậu quả.
Nói một cách đơn giản, cây không chứa chu trình và ở đâu như đồ thị có thể. Vì vậy, khi chúng ta thực hiện tìm kiếm, chúng ta nên tránh các chu trình trong đồ thị để chúng ta không đi vào các vòng lặp vô hạn.
Một khía cạnh khác là cây thường sẽ có một số kiểu sắp xếp tôpô hoặc một thuộc tính như cây tìm kiếm nhị phân giúp tìm kiếm rất nhanh và dễ dàng so với đồ thị.