BFS thường được mô tả một cái gì đó như sau (từ Wikipedia ).
1 procedure BFS(G,start_v):
2 let Q be a queue
3 label start_v as discovered
4 Q.enqueue(start_v)
5 while Q is not empty
6 v = Q.dequeue()
7 if v is the goal:
8 return v
9 for all edges from v to w in G.adjacentEdges(v) do
10 if w is not labeled as discovered:
11 label w as discovered
12 w.parent = v
13 Q.enqueue(w)
Vấn đề là một vấn đề hơi khó hiểu: nó ẩn trong dòng 3! Câu hỏi là, chúng ta sẽ sử dụng cấu trúc dữ liệu nào để lưu trữ các đỉnh đã được phát hiện?
Giải pháp đơn giản nhất là sử dụng mảng Boolean với một mục nhập trên mỗi đỉnh. Trong trường hợp này, chúng ta phải khởi tạo mọi phần tử của mảng false
và điều này sẽ mất thời gian . Điều này áp dụng cho mọi biểu đồ, ngay cả khi không có cạnh nào cả, vì vậy chúng tôi không thể giả sử bất kỳ mối quan hệ nào giữavà và chúng ta có thời gian chạy .Θ ( | V| )|V||E|O(|V|+|E|)
Chúng ta có thể tránh việc có cấu trúc dữ liệu với thời gian khởi tạo không? Nỗ lực đầu tiên của chúng tôi có thể là sử dụng một danh sách liên kết. Tuy nhiên, bây giờ kiểm tra nếu một đỉnh đã được phát hiện (dòng 10) cần thời gian tuyến tính theo số lượng đỉnh được truy cập, thay vì thời gian không đổi như trước. Điều này có nghĩa là thời gian chạy trở thành , tệ hơn nhiều trong trường hợp xấu nhất. (Lưu ý rằng chúng tôi không muốn viết lại thành vì điều đó thậm chí còn tệ hơn: nó có thể tệ như , trong khi )Θ(|V|)O(|V||E|)O(|E|2)|V|4|V||E|≤|V|3
Sử dụng một mảng được thay đổi kích thước động sẽ cho phép chúng tôi giữ danh sách được sắp xếp, vì vậy bây giờ việc tra cứu sẽ chỉ mất thời gian nhưng điều đó vẫn cho thời gian chạy chỉ , mà vẫn còn tệ hơn so với tiêu chuẩn.O(log|V|)O(|E|log|V|)
Cuối cùng, chúng ta có thể sử dụng bảng băm có kích thước động: bắt đầu với một bảng có kích thước không đổi và nhân đôi mỗi khi nó đầy một nửa. Điều này có nghĩa là kích thước cuối cùng của bảng nhiều nhất gấp đôi số đỉnh được phát hiện trước khi thuật toán kết thúc và điều này nhiều nhất là vì chúng ta không bao giờ phát hiện ra bất cứ điều gì bên ngoài thành phần của đỉnh bắt đầu. Hơn nữa, tổng số lượng công việc đã thực hiện sao chép bảng băm để mở rộng nó nhiều nhất là. Tra cứu và chèn vào bảng băm được khấu hao để chúng tôi thực sự có được thời gian chạy của .c|E|+1c+2c+4c+⋯+2|E|≤4|E| O(1)O(|E|)
Vì vậy, là có thể, nhưng muốn thực hiện điều đó trong một triển khai thực sự? Tôi có thể nói có lẽ là không. Trừ khi bạn có lý do để tin rằng đồ thị đầu vào của bạn sẽ có nhiều thành phần nhỏ, chi phí duy trì bảng băm sẽ thêm một yếu tố không đổi đáng chú ý vào thời gian chạy. Phát triển bảng băm có thể mất thời gianvà tra cứu sẽ yêu cầu bạn tính toán hàm băm và, trung bình, nhìn vào nhiều hơn một vị trí trong bảng. Hiệu suất bộ nhớ cache kém của các bảng băm cũng có thể làm tổn thương bạn trên một máy tính thực. Trong hầu hết các trường hợp với việc triển khai mảng tiêu chuẩn, phần là thuật ngữ chi phối củaO(|E|)4|E|O(|E|)O(|V|+|E|) thời gian hoạt động không đáng để sử dụng bảng băm để loại bỏ thuật ngữ thống trị, do chi phí thực tế để làm việc này.