stack trong thủ tục đệ qui. Khác với thuật toán tìm kiếm theo chiều sâu, thuật toán tìm kiếm theo chiều rộng thay thế việc sử dụng stack bằng hàng đợi (queue). Trong thủ tục này, đỉnh được nạp vào hàng đợi đầu tiên là u, các đỉnh kề với u là ( v1, v2, . . ., vk) được nạp vào hàng đợi nếu như nó chưa được xét đến. Quá trình duyệt tiếp theo được bắt đầu từ các đỉnh còn có mặt trong hàng đợi.
Để ghi nhận trạng thái duyệt các đỉnh của đồ thị, ta cũng vẫn sử dụng mảng chuaxet[] gồm n phần tử thiết lập giá trị ban đầu là TRUE. Nếu đỉnh u của đồ thị đã được duyệt, giá trị chuaxet[u] sẽ nhận giá trị FALSE. Thuật toán dừng khi hàng đợi rỗng. Hình 5.7. dưới đây mô tả chi tiết thuật toán BFS(u).
Biểu diễn thuật toán:
Hình 5.7. Thuật toán BFS(u).
Độ phức tạp tính toán:
Độ phức tạp thuật toán BFS(u) phụ thuộc vào phương pháp biểu diễn đồ thị. Độ phức tạp thuật toán BFS(u) theo các dạng biểu diễn đồ thị như sau:
Độ phức tạp thuật toán là O(n2) trong trường hợp đồ thị biểu diễn dưới dạng ma trận kề, với n là số đỉnh của đồ thị.
Độ phức tạp thuật toán là O(n.m) trong trường hợp đồ thị biểu diễn dưới dạng danh sách cạnh, với n là số đỉnh của đồ thị, m là số cạnh của đồ thị.
Thuật toán BFS(u): Bước 1(Khởi tạo):
Queue = ; //tạo lập hàng đợi rỗng
Push(Queue,u); //đưa u vào hàng đợi
chuaxet[u] = False; //ghi nhận đỉnh u đã xét
Bước 2 (Lặp):
while (Queue ) do //lặp đến khi hàng đợi rỗng
s = Pop(Queue); //đưa s ra khỏi hàng đợi
<Thăm đỉnh s>;
for each tKe(s) do //duyệt trên danh sách ke(s)
if ( chuaxet[t] ) then //nếu t chưa xét
Push(Queue, t); //đưa t vào hàng đợi
chuaxet[t] = False; //ghi nhận t đã xét
EndIf ; EndFor ; EndWhile ;
Bước 3 (Trả lại kết quả) :
Return(<Tập đỉnh được duyệt>) ;
NGUYỄN DUY PHƯƠNG 185
Độ phức tạp thuật toán là O(max(n, m)) trong trường hợp đồ thị biểu diễn dưới dạng danh sách kề, với n là số đỉnh của đồ thị, m là số cạnh của đồ thị.
Bạn đọc tự chứng minh hoặc có thể tham khảo trong các tài liệu [1, 2, 3].
Cài đặt thuật toán: thuật toán được cài đặt theo khuôn dạng dữ liệu tổ chức trong file dothi.in dưới dạng danh sách cạnh.
#include <iostream> #include <list> #include <fstream> #include <iomanip> #include <stack> using namespace std;
class Graph{//định nghĩa lớp Graph
private:
int V; // số đỉnh của đồ thị
list <int> *adj; // con trỏ đến mảng các danh sách kề adj
bool *chuaxet; //mảng ghi nhận các đỉnh cưa xét
public:
Graph(int V); // constructor của lớp
void addEdge(int v, int w); // thêm cạnh (u, w) vào đồ thị void BFS (int u);//thuật toán BFS dựa vào hàng đợi
};
Graph::Graph(int V){ //constructor của lớp
this->V = V;//thiết lập V=0, 1, 2, .., V-1
adj = new list<int>[V];//thiết lập V danh sách kề
chuaxet = new bool[V];//thiết lập trạng thái các đỉnh đều chưa xét
for(int u=0; u<V; u++) //duyệt trên tập đỉnh V
chuaxet[u]=true; //thiết lập tất cả các đỉnh đều chưa xét }
void Graph::addEdge(int v, int w){//thêm cạnh (v,w) vào đồ thị
adj[v].push_back(w); //thêm w vào list(v) nếu là đồ thị có hướng
adj[w].push_back(v); //thêm v vào list(w) nếu là đồ thị vô hướng
}
void Graph::BFS(int u){//thuật toán BFS
list<int> queue; //tạo hàng đợi rỗng
queue.push_back(u);//đưa u vào hàng đợi
chuaxet[u] = false; //ghi nhận đỉnh u đã xét
list<int>::iterator t; //sử dụng t là một iterator
while(!queue.empty()){//lặp đến khi hàng đợi rỗng
int s = queue.front();//lấy s ở đầu hàng đợi
cout << s << " ";//thăm đỉnh s
queue.pop_front();//loại s ra khỏi hàng đợi
NGUYỄN DUY PHƯƠNG 186 if(chuaxet[*t]){ //nếu đỉnh t chưa xét