Khi nào thì thực tế khi sử dụng Depth-First Search (DFS) so với Breadth-First Search (BFS)? [đóng cửa]


345

Tôi hiểu sự khác biệt giữa DFS và BFS, nhưng tôi muốn biết khi nào thực tế hơn để sử dụng cái này hơn cái kia?

Bất cứ ai cũng có thể đưa ra bất kỳ ví dụ nào về cách DFS sẽ chơi BFS và ngược lại?


4
Có lẽ bạn có thể đề cập đến các điều khoản đầy đủ cho DFS và BFS cho câu hỏi - mọi người có thể không biết những từ viết tắt này.
Hans-Peter Störr




lưu ý đề cập đến một số kịch bản ứng dụng của BFS và DFS
Yossarian42

Câu trả lời:


353

Điều đó phụ thuộc nhiều vào cấu trúc của cây tìm kiếm và số lượng và vị trí của các giải pháp (còn gọi là các mục tìm kiếm).

  • Nếu bạn biết một giải pháp không xa gốc cây, thì lần tìm kiếm đầu tiên (BFS) có thể tốt hơn.
  • Nếu cây rất sâu và các giải pháp rất hiếm, thì việc tìm kiếm đầu tiên (DFS) có thể mất một thời gian rất dài, nhưng BFS có thể nhanh hơn.

  • Nếu cây rất rộng, BFS có thể cần quá nhiều bộ nhớ, vì vậy nó có thể hoàn toàn không thực tế.

  • Nếu các giải pháp là thường xuyên nhưng nằm sâu trong cây, BFS có thể không thực tế.

  • Nếu cây tìm kiếm rất sâu, bạn sẽ cần phải hạn chế độ sâu tìm kiếm đối với độ sâu tìm kiếm đầu tiên (DFS), dù sao (ví dụ với độ sâu lặp lại).

Nhưng đây chỉ là quy tắc của ngón tay cái; có lẽ bạn sẽ cần phải thử nghiệm.


4
Đệ quy AFAIK thường cần nhiều bộ nhớ hơn lặp lại.
Marek Marczak

3
@MarekMarczak Tôi không thấy bạn muốn nói gì. Nếu bạn lấy BFS làm phép lặp - nếu không gian giải pháp không dễ dàng đếm được, bạn có thể phải lưu trữ toàn bộ cấp thứ n của cây tìm kiếm trong bộ nhớ để liệt kê cấp n + 1.
Hans-Peter Störr

11
@MarekMarczak Phiên bản lặp của DFS sử dụng ngăn xếp. Recursion vs Iteration là một chủ đề hoàn toàn riêng biệt.
Clint Deygoo

Một trường hợp khác xuất hiện trong đầu: BFS là hữu ích (cần thiết) trong trường hợp đồ thị là "vô hạn". Giống như nói, một bàn cờ kéo dài đến vô tận theo mọi hướng. DFS sẽ không bao giờ trở lại. BFS được đảm bảo để tìm thấy những gì nó đang tìm kiếm NẾU điều kiện là thỏa đáng.
ThePartyTurtle

157

Tìm kiếm theo chiều sâu

Các tìm kiếm theo chiều sâu thường được sử dụng trong các mô phỏng trò chơi (và các tình huống giống như trò chơi trong thế giới thực). Trong một trò chơi thông thường, bạn có thể chọn một trong nhiều hành động có thể. Mỗi lựa chọn dẫn đến những lựa chọn khác, mỗi lựa chọn dẫn đến những lựa chọn khác, và tiếp tục thành một biểu đồ khả năng hình cây ngày càng mở rộng.

nhập mô tả hình ảnh ở đây

Ví dụ: trong các trò chơi như Cờ vua, tic-tac-toe khi bạn đang quyết định nên làm gì, bạn có thể tưởng tượng một cách di chuyển, sau đó là phản ứng có thể của đối thủ, sau đó là phản hồi của bạn, v.v. Bạn có thể quyết định phải làm gì bằng cách xem động thái nào dẫn đến kết quả tốt nhất.

Chỉ một số đường dẫn trong cây trò chơi dẫn đến chiến thắng của bạn. Một số dẫn đến một chiến thắng của đối thủ của bạn, khi bạn đạt được kết thúc như vậy, bạn phải sao lưu hoặc quay lại, đến một nút trước đó và thử một con đường khác. Theo cách này, bạn khám phá cây cho đến khi bạn tìm thấy một con đường với một kết luận thành công. Sau đó, bạn thực hiện bước đầu tiên dọc theo con đường này.


Tìm kiếm đầu tiên

Tìm kiếm đầu tiên có một thuộc tính thú vị: Đầu tiên nó tìm thấy tất cả các đỉnh nằm cách điểm bắt đầu một cạnh, sau đó tất cả các đỉnh nằm cách hai cạnh, v.v. Điều này hữu ích nếu bạn đang cố gắng tìm đường đi ngắn nhất từ ​​đỉnh bắt đầu đến một đỉnh đã cho. Bạn bắt đầu BFS và khi bạn tìm thấy đỉnh được chỉ định, bạn sẽ biết đường dẫn bạn đã theo dõi cho đến nay là đường dẫn ngắn nhất đến nút. Nếu có một con đường ngắn hơn, BFS đã tìm thấy nó rồi.

Tìm kiếm đầu tiên có thể được sử dụng để tìm các nút lân cận trong các mạng ngang hàng như BitTorrent, hệ thống GPS để tìm các địa điểm gần đó, các trang mạng xã hội để tìm người ở khoảng cách cụ thể và những thứ tương tự.


113

Giải thích hay từ http://www.programmerinterview.com/index.php/data-strucenses/dfs-vs-bfs/

Một ví dụ về BFS

Đây là một ví dụ về giao diện của BFS. Đây là một cái gì đó giống như Chuyển đổi cây theo thứ tự cấp độ nơi chúng tôi sẽ sử dụng QUEUE với phương pháp tiếp cận ITERECT (Chủ yếu là RECURSION sẽ kết thúc với DFS). Các số biểu thị thứ tự các nút được truy cập trong BFS:

nhập mô tả hình ảnh ở đây

Trong một tìm kiếm sâu đầu tiên, bạn bắt đầu từ gốc và theo một trong các nhánh của cây càng xa càng tốt cho đến khi tìm thấy nút bạn đang tìm hoặc bạn nhấn một nút lá (một nút không có con). Nếu bạn nhấn một nút lá, thì bạn tiếp tục tìm kiếm ở tổ tiên gần nhất với những đứa trẻ chưa được khám phá.

Một ví dụ về DFS

Đây là một ví dụ về việc DFS sẽ trông như thế nào. Tôi nghĩ rằng giao dịch theo thứ tự bài trong cây nhị phân sẽ bắt đầu công việc từ cấp độ Lá trước. Các số biểu thị thứ tự các nút được truy cập trong DFS:

nhập mô tả hình ảnh ở đây

Sự khác biệt giữa DFS và BFS

So sánh BFS và DFS, lợi thế lớn của DFS là nó có yêu cầu bộ nhớ thấp hơn nhiều so với BFS, vì không cần thiết phải lưu trữ tất cả các con trỏ con ở mỗi cấp. Tùy thuộc vào dữ liệu và những gì bạn đang tìm kiếm, DFS hoặc BFS có thể thuận lợi.

Ví dụ, đưa cho một cây gia đình nếu một người đang tìm kiếm ai đó trên cây vẫn còn sống, thì sẽ an toàn khi cho rằng người đó sẽ ở dưới gốc cây. Điều này có nghĩa là một BFS sẽ mất một thời gian rất dài để đạt đến cấp độ cuối cùng đó. Một DFS, tuy nhiên, sẽ tìm thấy mục tiêu nhanh hơn. Nhưng, nếu một người đang tìm kiếm một thành viên gia đình đã chết cách đây rất lâu, thì người đó sẽ ở gần ngọn cây hơn. Sau đó, BFS thường sẽ nhanh hơn DFS. Vì vậy, lợi thế của một trong hai tùy thuộc vào dữ liệu và những gì bạn đang tìm kiếm.

Một ví dụ nữa là Facebook; Gợi ý về bạn bè của bạn bè. Chúng tôi cần bạn bè ngay lập tức để đề xuất nơi chúng tôi có thể sử dụng BFS. Có thể tìm thấy con đường ngắn nhất hoặc phát hiện chu trình (sử dụng đệ quy) chúng ta có thể sử dụng DFS.


"Chuyển đổi thứ tự bài trong cây nhị phân" là gì?
Kyle Delaney

8
DFS có tìm thấy con đường ngắn nhất tốt hơn BFS không? Tôi nghĩ rằng nó là cách khác xung quanh. Tôi nghĩ BFS tìm con đường ngắn nhất. Phải không?
Naveen Gabriel

1
Sẽ đánh giá cao hơn nếu bạn đã cung cấp các khoản tín dụng cho nguồn. Phần so sánh được chọn từ "Cấu trúc dữ liệu được thực hiện dễ dàng trong Java" bởi Narasimha Karumanchi.
learntogrow-growtolearn 18/03/2017

Chắc chắn tôi có thể cập nhật điều đó, nhưng không mong đợi bất cứ ai đánh giá cao ở đây. Chỉ muốn giúp đỡ những người kỹ thuật nghèo như tôi.
Kanagavelu Sugumar

1
@KyleDelaney có ba đơn hàng trong đó bạn có thể đi qua một cây - đặt hàng trước, đặt hàng và đặt hàng. Chúng tương ứng với ký hiệu tiền tố và ký hiệu tiền tố tương ứng. Khi bạn di chuyển cây xuống và sau đó sao lưu, nếu bạn chọn một nút trong lần đầu tiên bạn truy cập vào đó là thứ tự trước, nếu lần thứ hai nó được đặt hàng, nếu lần cuối cùng là bưu điện. Bạn thực sự có thể tuần tự hóa cây theo cách này và miễn là bạn nhớ thứ tự bạn đã sử dụng, bạn có thể xây dựng lại cây từ việc tuần tự hóa.
Dave

43

Breadth First Search thường là cách tiếp cận tốt nhất khi độ sâu của cây có thể thay đổi và bạn chỉ cần tìm kiếm một phần của cây để tìm giải pháp. Ví dụ: tìm đường đi ngắn nhất từ ​​giá trị bắt đầu đến giá trị cuối cùng là một nơi tốt để sử dụng BFS.

Depth First Search thường được sử dụng khi bạn cần tìm kiếm toàn bộ cây. Việc thực hiện (sử dụng đệ quy) dễ dàng hơn BFS và yêu cầu ít trạng thái hơn: Mặc dù BFS yêu cầu bạn lưu trữ toàn bộ 'biên giới', DFS chỉ yêu cầu bạn lưu trữ danh sách các nút cha của phần tử hiện tại.


26

DFS là không gian hiệu quả hơn BFS, nhưng có thể đi đến độ sâu không cần thiết.

Tên của họ được tiết lộ: nếu có chiều rộng lớn (tức là hệ số phân nhánh lớn), nhưng độ sâu rất hạn chế (ví dụ: số lượng "di chuyển" hạn chế), thì DFS có thể thích hợp hơn với BFS.


Trên IDDFS

Cần phải đề cập rằng có một biến thể ít được biết đến, kết hợp hiệu quả không gian của DFS, nhưng (theo cách thức), việc truy cập BFS theo cấp độ, là tìm kiếm theo chiều sâu lặp đi lặp lại . Thuật toán này xem xét lại một số nút, nhưng nó chỉ đóng góp một yếu tố không đổi của sự khác biệt tiệm cận.


1
Nó không nhất thiết phải là không gian hiệu quả hơn .. ví dụ, hãy xem xét một biểu đồ đường dẫn.
RB

16

Khi bạn tiếp cận câu hỏi này với tư cách là một lập trình viên, một yếu tố nổi bật: nếu bạn đang sử dụng đệ quy, thì tìm kiếm theo chiều sâu sẽ đơn giản hơn để thực hiện, bởi vì bạn không cần phải duy trì cấu trúc dữ liệu bổ sung có chứa các nút chưa khám phá.

Đây là tìm kiếm theo chiều sâu cho một biểu đồ không định hướng nếu bạn đang lưu trữ thông tin đã truy cập vào các thông tin trong các nút:

def dfs(origin):                               # DFS from origin:
    origin.visited = True                      # Mark the origin as visited
    for neighbor in origin.neighbors:          # Loop over the neighbors
        if not neighbor.visited: dfs(next)     # Visit each neighbor if not already visited

Nếu lưu trữ thông tin đã truy cập vào thông tin của người dùng trong một cấu trúc dữ liệu riêng biệt:

def dfs(node, visited):                        # DFS from origin, with already-visited set:
    visited.add(node)                          # Mark the origin as visited
    for neighbor in node.neighbors:            # Loop over the neighbors
        if not neighbor in visited:            # If the neighbor hasn't been visited yet,
            dfs(node, visited)                 # then visit the neighbor
dfs(origin, set())

Tương phản điều này với tìm kiếm theo chiều rộng đầu tiên, nơi bạn cần duy trì cấu trúc dữ liệu riêng cho danh sách các nút chưa truy cập, bất kể điều gì.



5

Đối với BFS, chúng ta có thể xem xét ví dụ của Facebook. Chúng tôi nhận được đề xuất để thêm bạn bè từ hồ sơ FB từ hồ sơ bạn bè khác. Giả sử A-> B, trong khi B-> E và B-> F, vì vậy A sẽ nhận được đề xuất cho E và F. Họ phải sử dụng BFS để đọc đến cấp độ thứ hai. DFS dựa nhiều hơn vào các kịch bản mà chúng tôi muốn dự báo một cái gì đó dựa trên dữ liệu chúng tôi có từ nguồn đến đích. Như đã đề cập về cờ vua hoặc sudoku. Một điều tôi có khác ở đây là, tôi tin rằng DFS nên được sử dụng cho con đường ngắn nhất vì DFS sẽ bao quát toàn bộ đường dẫn trước sau đó chúng ta có thể quyết định điều tốt nhất. Nhưng vì BFS sẽ sử dụng cách tiếp cận của người tham lam nên có thể nó giống như con đường ngắn nhất của nó, nhưng kết quả cuối cùng có thể khác. Hãy cho tôi biết liệu sự hiểu biết của tôi là sai.


Bây giờ nhận xét của tôi là một chút muộn. Nhưng để tìm ra con đường ngắn nhất, BFS nên được sử dụng. Tuy nhiên, "DFS dựa nhiều hơn vào các kịch bản mà chúng tôi muốn dự báo một cái gì đó dựa trên dữ liệu chúng tôi có từ nguồn đến đích" là một điều tuyệt vời mà bạn đã nói! Thanh danh!!
Oskarzito

4

Một số thuật toán phụ thuộc vào các thuộc tính cụ thể của DFS (hoặc BFS) để hoạt động. Ví dụ, thuật toán Hopcroft và Tarjan để tìm các thành phần được kết nối 2 lợi dụng thực tế là mỗi nút đã truy cập mà DFS gặp phải nằm trên đường dẫn từ gốc đến nút hiện đang được khám phá.


4

Sau đây là câu trả lời toàn diện cho những gì bạn đang hỏi.

Nói một cách đơn giản:

Thuật toán Breadth First Search (BFS), từ tên gọi "Breadth", phát hiện ra tất cả các lân cận của một nút thông qua các cạnh ngoài của nút, sau đó nó phát hiện ra các hàng xóm không được chú ý của các hàng xóm được đề cập trước đó qua các cạnh của chúng và cho đến khi tất cả các nút có thể truy cập từ nguồn gốc được truy cập (chúng ta có thể tiếp tục và lấy một nguồn gốc khác nếu vẫn còn các nút không mong muốn và vv). Đó là lý do tại sao nó có thể được sử dụng để tìm đường đi ngắn nhất (nếu có) từ một nút (nguồn gốc) đến một nút khác nếu trọng số của các cạnh là đồng nhất.

Thuật toán Depth First Search (DFS), từ tên "Depth", phát hiện ra các hàng xóm không được chú ý của nút x được phát hiện gần đây nhất thông qua các cạnh ngoài của nó. Nếu không có hàng xóm không được chú ý từ nút x, thuật toán quay lại để khám phá các hàng xóm không được chú ý của nút (thông qua các cạnh ngoài của nó) từ đó nút x được phát hiện, và cứ thế, cho đến khi tất cả các nút có thể truy cập từ nguồn gốc được truy cập (chúng ta có thể tiếp tục và lấy một nguồn gốc khác nếu vẫn còn các nút không mong muốn và vv).

Cả BFS và DFS có thể không đầy đủ. Ví dụ: nếu hệ số phân nhánh của một nút là vô hạn hoặc rất lớn để các tài nguyên (bộ nhớ) hỗ trợ (ví dụ: khi lưu trữ các nút được phát hiện tiếp theo), thì BFS không hoàn thành mặc dù khóa tìm kiếm có thể ở khoảng cách của một số cạnh từ nguồn gốc. Yếu tố phân nhánh vô hạn này có thể là do các lựa chọn vô hạn (các nút lân cận) từ một nút nhất định để khám phá. Nếu độ sâu là vô hạn hoặc rất lớn để các tài nguyên (bộ nhớ) hỗ trợ (ví dụ: khi lưu trữ các nút được phát hiện tiếp theo), thì DFS không hoàn thành mặc dù khóa tìm kiếm có thể là hàng xóm thứ ba của nguồn gốc. Độ sâu vô hạn này có thể là do tình huống có, đối với mỗi nút mà thuật toán phát hiện ra, ít nhất là một lựa chọn mới (nút lân cận) không được chú ý trước đó.

Do đó, chúng ta có thể kết luận khi nào nên sử dụng BFS và DFS. Giả sử chúng ta đang xử lý một yếu tố phân nhánh hạn chế có thể quản lý và độ sâu giới hạn có thể quản lý được. Nếu nút tìm kiếm nông, tức là có thể truy cập sau một số cạnh từ nguồn gốc, thì tốt hơn là sử dụng BFS. Mặt khác, nếu nút được tìm kiếm sâu tức là có thể truy cập được sau rất nhiều cạnh từ nguồn gốc, thì tốt hơn là sử dụng DFS.

Ví dụ: trong mạng xã hội nếu chúng tôi muốn tìm kiếm những người có cùng sở thích với một người cụ thể, chúng tôi có thể áp dụng BFS từ người này như một nguồn gốc, bởi vì hầu hết những người này sẽ là bạn bè hoặc bạn bè trực tiếp của anh ấy, ví dụ như một hoặc hai cạnh xa. Mặt khác, nếu chúng ta muốn tìm kiếm những người có sở thích hoàn toàn khác nhau của một người cụ thể, chúng ta có thể áp dụng DFS từ người này như một nguồn gốc, bởi vì hầu hết những người này sẽ ở rất xa anh ta, tức là bạn của bạn của bạn .... tức là quá nhiều cạnh.

Các ứng dụng của BFS và DFS cũng có thể khác nhau do cơ chế tìm kiếm trong mỗi cái. Ví dụ: chúng ta có thể sử dụng BFS (giả sử hệ số phân nhánh có thể quản lý được) hoặc DFS (giả sử độ sâu có thể quản lý được) khi chúng ta chỉ muốn kiểm tra khả năng tiếp cận từ nút này sang nút khác mà không có thông tin nào có thể có nút đó. Ngoài ra cả hai đều có thể giải quyết các nhiệm vụ giống nhau như sắp xếp tôpô của đồ thị (nếu có). BFS có thể được sử dụng để tìm đường đi ngắn nhất, với các cạnh trọng lượng đơn vị, từ một nút (nguồn gốc) đến một đường dẫn khác. Trong khi đó, DFS có thể được sử dụng để làm cạn kiệt tất cả các lựa chọn vì bản chất của nó là đi sâu, giống như khám phá con đường dài nhất giữa hai nút trong một biểu đồ chu kỳ. Ngoài ra DFS, có thể được sử dụng để phát hiện chu kỳ trong biểu đồ.

Cuối cùng, nếu chúng ta có chiều sâu vô hạn và hệ số phân nhánh vô hạn, chúng ta có thể sử dụng Tìm kiếm sâu lặp lại (IDS).


2

Theo các thuộc tính của DFS và BFS. Ví dụ, khi chúng ta muốn tìm con đường ngắn nhất. chúng tôi thường sử dụng bfs, nó có thể đảm bảo 'ngắn nhất'. nhưng dfs chỉ có thể đảm bảo rằng chúng ta có thể đến từ thời điểm này có thể đạt được điểm đó, không thể đảm bảo 'ngắn nhất'.


2

Tôi nghĩ rằng nó phụ thuộc vào những vấn đề bạn đang phải đối mặt.

  1. đường dẫn ngắn nhất trên biểu đồ đơn giản -> bfs
  2. tất cả các kết quả có thể -> dfs
  3. tìm kiếm trên biểu đồ (coi cây, martix cũng như biểu đồ) -> dfs ....

Nếu bạn thêm một dòng trống trước danh sách, câu trả lời sẽ tốt hơn nhiều.
montonero

1

Bởi vì Tìm kiếm theo chiều sâu sử dụng ngăn xếp khi các nút được xử lý, quay lui được cung cấp với DFS. Bởi vì Breadth-First Search sử dụng hàng đợi, không phải ngăn xếp, để theo dõi những nút nào được xử lý, quay lui không được cung cấp với BFS.


1

Khi chiều rộng của cây rất lớn và độ sâu thấp, hãy sử dụng DFS vì ngăn xếp đệ quy sẽ không tràn. Sử dụng BFS khi chiều rộng thấp và độ sâu rất lớn để đi qua cây.


0

Đây là một ví dụ tốt để chứng minh rằng BFS tốt hơn DFS trong một số trường hợp nhất định. https://leetcode.com/probols/01-matrix/

Khi được triển khai chính xác, cả hai giải pháp sẽ truy cập vào các ô có khoảng cách xa hơn so với ô hiện tại +1. Nhưng DFS không hiệu quả và liên tục truy cập vào cùng một ô dẫn đến độ phức tạp O (n * n).

Ví dụ,

1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
1,1,1,1,1,1,1,1, 
0,0,0,0,0,0,0,0,

0

Nó phụ thuộc vào tình huống mà nó được sử dụng. Bất cứ khi nào chúng tôi gặp vấn đề khi duyệt đồ thị, chúng tôi sẽ thực hiện nó cho một số mục đích. Khi có vấn đề tìm đường đi ngắn nhất trong đồ thị không có trọng số hoặc tìm xem đồ thị có phải là lưỡng cực hay không, chúng ta có thể sử dụng BFS. Đối với các vấn đề phát hiện chu kỳ hoặc bất kỳ logic nào cần quay lại, chúng tôi có thể sử dụng DFS.

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.