Các bước thực hiện thuật toán tìm kiếm dfs bfs

Chương trình dưới đây mô tả 2 thuật toán tìm kiếm theo chiều rộng (BFS – Breadth-first search) và chiều sâu (DFS – Depth-first search) trên đồ họa, có các bước đi và màu sắc đẹp.

Giao diện của chương trình khi khởi động sẽ như thế này:

Các bước thực hiện thuật toán tìm kiếm dfs bfs

Chương trình có 4 phần chính. Phần trên (top) là tiêu đề chương trình, phần dưới (bottom) là tên mềnh =)). Phần bên trái (left) là bảng điều khiển. Phần bên phải là phần vẽ đồ thị. Bạn lưu ý đến phần bên trái (bảng điều khiển). Trước tiên bạn cần chọn thuật toán để duyệt đồ thị, sau đó nhập số điểm của đồ thị (tối đa 10 điểm, nếu bạn muốn sửa thì vào code sửa lại) và các cạnh của nó. Các điểm của đồ thị sẽ được bố trí theo hình tròn để tránh các đường đi trùng nhau gây khó quan sát. Sau khi bạn nhập xong các đầu vào thì cuối cùng là chọn điểm bắt đầu chạy.

Dưới đây là hình ảnh khi duyệt đồ thị theo BFS và DFS.

Các bước thực hiện thuật toán tìm kiếm dfs bfs

Các bước thực hiện thuật toán tìm kiếm dfs bfs

Màu của điểm đầu là vàng, màu điểm cuối cùng là đỏ. Khi duyệt thì thứ tự duyệt sẽ được đánh số. VD với đồ thị trên, khi duyệt BFS sẽ là 1->2->4->5->3

Thông thường, DFS là một dạng tìm kiếm thông tin không đầy đủ mà quá trình tìm kiếm được phát triển tới đỉnh con đầu tiên của nút đang tìm kiếm cho tới khi gặp được đỉnh cần tìm hoặc tới một nút không có con. Khi đó giải thuật quay lui về đỉnh vừa mới tìm kiếm ở bước trước. Trong dạng không đệ quy, tất cả các đỉnh chờ được phát triển được bổ sung vào một ngăn xếp LIFO.

Độ phức tạp không gian của DFS thấp hơn của BFS (tìm kiếm theo chiều rộng). Độ phức tạp thời gian của hai thuật toán là tương đương nhau và bằng O(|V| + |E|).

Ví dụ[sửa | sửa mã nguồn]

Các bước thực hiện thuật toán tìm kiếm dfs bfs

Tìm kiếm ưu tiên chiều sâu bắt đầu thăm đỉnh A, đi theo cạnh trái, tiếp tục tìm kiếm xong ở cây con trái mới chuyển sang tìm kiếm ở cây con phải. Thứ tự thăm viếng các đỉnh là: A, B, D, F, E, C, G.

Quá trình viếng thăm các đỉnh diễn ra như sau: Sau khi thăm đỉnh A, vì B chưa được thăm nên theo cạnh AB ta thăm B, tiếp tục theo cạnh BD tới viếng thăm D. Từ D không thể tiếp tục đi xa hơn, ta quay lại B. Từ B, theo BF đến thăm F, tiếp tục theo cạnh FE đến thăm E. Từ E cũng không thể đi xa hơn, quay lại A, duyệt tiếp đến C, G.

Kết quả của thuật toán[sửa | sửa mã nguồn]

Một cách tự nhiên, kết quả của giải thuật tìm kiếm theo chiều sâu là một cây phủ qua tất cả các đỉnh được duyệt của đồ thị.

Duyệt các đỉnh[sửa | sửa mã nguồn]

Có thể dùng giải thuật này để tạo một danh sách tuyến tính các đỉnh của một đồ thị (hoặc cây). Có ba cách hiện thực phương pháp này:

  • Duyệt tiền thứ tự (preordering): tạo ra một danh sách mà trong đó các đỉnh xuất hiện theo đúng trật tự nó được thăm đến khi chạy thuật toán. Đây chính là biểu diễn tự nhiên của quá trình thực hiện giải thuật tìm kiếm theo chiều sâu. Một biểu thức ở dạng tiền thứ tự được gọi là ký pháp tiền tố.
  • Duyệt hậu thứ tự (postordering): tạo ra một danh sách mà trong đó các đỉnh xuất hiện theo thứ tự của lần duyệt đến sau cùng khi thực hiện giải thuật. Một lần duyệt hậu thứ tự một cây biểu thức sẽ cho ra một ký pháp hậu tố.
  • Duyệt đảo hậu thứ tự (reverse postordering): kết quả của cách duyệt này là sự đảo ngược lại thứ tự trong kết quả duyệt hậu thứ tự. Thông thường, khi duyệt cây, cách này cho ra cùng kết quả với duyệt tiền thứ tự, nhưng xét tổng quát, khi duyệt một đồ thị, tiền thứ tự và đảo hậu thứ tự cho ra kết quả khác nhau. Với các đồ thị có hướng và không có vòng, cách duyệt đảo hậu thứ tự cho ra một trật tự tô-pô của đồ thị đó.

Thuật toán tìm kiếm theo chiều sâu trong đồ thị vô hướng[sửa | sửa mã nguồn]

Ý tưởng thuật toán[sửa | sửa mã nguồn]

  1. DFS trên cũng giống như khám phá mê cung với một cuộn chỉ và một thùng sơn đỏ để đánh dấu, tránh bị lạc. Trong đó mỗi s trong đồ thị tượng trưng cho một cửa trong mê cung.
  2. Ta bắt đầu từ s, buộc đầu cuộn chỉ vào s và đánh đấu này "đã thăm". Sau đó ta đánh dấu s là hiện hành u.
  3. Bây giờ, nếu ta đi theo (u,v) bất kỳ.
  4. Nếu (u,v) dẫn chúng ta đến "đã thăm" v, ta quay trở về u.
  5. Nếu v là mới, ta di chuyển đến v và lăn cuộn chỉ theo. Đánh dấu v là "đã thăm". Đặt v thành hiện hành và lặp lại các bước.
  6. Cuối cùng, ta có thể đi đến một mà tại đó tất cả các cạnh kề với nó đều dẫn chúng ta đến các "đã thăm". Khi đó, ta sẽ quay lui bằng cách cuộn ngược cuộn chỉ và quay lại cho đến khi trở lại một với một còn chưa được khám phá. Lại tiếp tục quy trình khám phá như trên.
  7. Khi chúng ta trở về s và không còn nào kề với nó chưa bị khám phá là lúc DFS dừng.

Mệnh đề[sửa | sửa mã nguồn]

Gọi G là một đồ thị vô hướng, trên đó ta sẽ thực hiện thao tác DFS với đỉnh bắt đầu là s thì:

  1. Phép duyệt sẽ thăm tất cả các đỉnh cùng thành phần liên thông với s.
  2. Các cạnh có nhãn "đã thăm" sẽ tạo ra một cây tối đại của thành phần liên thông chứa s.

Chứng minh[sửa | sửa mã nguồn]

  1. Khẳng định 1, là hiển nhiên vì DFS duyệt qua tất cả các đỉnh kề với đỉnh hiện hành (có thể chứng minh hoàn chỉnh hơn bằng phản chứng).
  2. Khẳng định 2, đúng do ta chỉ đánh dấu các cạnh đi đến một đỉnh mới nên không thể tạo ra chu trình. Như vậy DFS tạo ra một cây. Hơn nữa, DFS thăm tất cả các đỉnh thuộc thành phần liên thông nên cây này là cây tối đại.

Độ phức tạp của thuật toán[sửa | sửa mã nguồn]

  1. DFS được gọi đúng 1 lần ứng với mỗi đỉnh.
  2. Mỗi cạnh được xem xét đúng 2 lần, mỗi lần từ một đỉnh kề với nó.
  3. Với ns đỉnh và ms cạnh thuộc thành phần liên thông chứa s, một phép DFS bắt đầu tại s sẽ chạy với thời gian O(ns + ms) nếu:
  4. Đồ thị được biểu diễn bằng cấu trúc dữ liệu dạng danh sách kề.
  5. Đặt nhãn cho một đỉnh là "đã thăm" và kiểm tra xem một đỉnh "đã thăm" chưa tốn chi phí O(degree).
  6. Bằng cách đặt nhãn cho các đỉnh là "đã thăm", ta có thể xem xét một cách hệ thống các cạnh kề với đỉnh hiện hành nên ta sẽ không xem xét một cạnh quá 1 lần.

Xác định đỉnh kề trong DFS[sửa | sửa mã nguồn]

  • Kết quả của DFS phụ thuộc vào cách ta chọn đỉnh kế tiếp.
    Các bước thực hiện thuật toán tìm kiếm dfs bfs
    Xác định đỉnh kề trong Depth-first search
  • Nếu ta bắt đầu tại A và thử cạnh nối đến F, sau đó đến B, rồi đến E, C, cuối cùng là G ta được:
    Các bước thực hiện thuật toán tìm kiếm dfs bfs
    Bắt đầu từ A và kết thúc tại G
  • Nếu cũng bắt đầu từ A nhưng đi theo trình tự, tập các cạnh đã thăm, backedge và các điểm đệ quy sẽ khác trước.
    Các bước thực hiện thuật toán tìm kiếm dfs bfs
    Bắt đầu từ A nhưng đi theo trình tự tập các cạnh đã thăm.

Chạy từng bước thuật toán[sửa | sửa mã nguồn]

Giờ ta sẽ chạy từng bước thuật toán theo ví dụ trên.

Nguyên lý[sửa | sửa mã nguồn]

Khởi đầu từ một đỉnh, đi theo các cung(cạnh) xa nhất có thể. Trở lại đỉnh của cạnh xa nhất, tiếp tục duyệt như trước, cho đến đỉnh cuối cùng.