之前談到的先深後廣法是利用堆疊及遞迴的技巧來走訪圖形, 而先廣後深法 (Breadth-First Search, bfs) 走訪方式則是以佇列及遞迴技巧來走訪, 也是從圖形某一頂點開始走訪, 被拜訪過的頂點就做上已拜訪的記號. 接著走訪此頂點的所有相鄰且未拜訪過的頂點中的任一個頂點, 並且做上已拜訪的記號, 再以該頂點做為新的起點繼續進行先廣後深的搜尋. 底下我們以下圖來看看 BFS 的走訪過程 :
步驟一 : 以頂點一為起點, 與頂點一相鄰且未拜訪過的頂點2 及頂點 5放入佇列 :
步驟二 : 取出頂點2, 將與頂點2 相鄰且未拜訪過的頂點3 及頂點4 放入佇列 :
步驟三 : 取出頂點5, 將與頂點5 相鄰且未拜訪過的頂點3 及頂點4 放入佇列 :
步驟四 : 取出頂點3, 將與頂點3 相鄰且未拜訪過的頂點4 放入佇列 :
步驟五 : 取出頂點4, 將與頂點4 相鄰且未拜訪過的頂點放入佇列中, 各位可以發現與頂點4 相鄰的頂點全部都被拜訪過, 所以無須再放入佇列中.
步驟六 : 將佇列值取出並判斷是否已經走訪過, 直到佇列內無節點可走訪為止. 所以先廣後深走訪順序為 : 頂點1 > 頂點2 > 頂點5 > 頂點3 > 頂點4
範例代碼 :
- #include
- using namespace std;
- class graphicPoint{
- public:
- int val;
- class graphicPoint *next;
- graphicPoint(){
- next = NULL;
- val = -1;
- }
- };
- int run[6] = {0};
- class graphicPoint head[6]; // 共有5個頂點
- #define MAX_QUEUESIZE 10 // 定義佇列最大容量
- int front = -1;
- int rear = -1;
- int queue[MAX_QUEUESIZE] = {0};
- void enqueue(int val) {
- if(rear >= MAX_QUEUESIZE)
- return;
- rear++;
- queue[rear] = val;
- }
- int dequeue(){
- if(front == rear) return -1;
- front++;
- return queue[front];
- }
- void bfs(int current) { //先廣後深法
- graphicPoint *tmpnode;
- enqueue(current); // 將第一個頂點存入佇列
- while(front != rear) { // 判斷目前是否為空佇列
- current=dequeue(); // 將頂點從佇列取出
- if(run[current]==0) {
- run[current] = 1; // 將走訪過的頂點設為1
- cout << "[" << current << "] ";
- }
- tmpnode = head[current].next;
- while(tmpnode!=NULL) {
- if(run[tmpnode->val]==0)
- enqueue(tmpnode->val);
- tmpnode = tmpnode->next;
- }
- }
- }
- void ch07_05(bool b) {
- if(b) {
- int data[14][2] = {{1,2}, {2,1}, {1,5}, {5,1}, {2,3}, {3,2}, {2,4}, {4,2}, {3,4}, {4,3}, {3,5}, {5,3}, {4,5}, {5,4}}; //圖形邊線陣列宣告
- for(int i=0; i<14; i++) {
- int tmpi = data[i][0];
- int tmpj = data[i][1];
- graphicPoint *npt = new graphicPoint;
- npt->val = tmpj;
- graphicPoint *pt = &head[tmpi];
- while(pt->next != NULL)
- pt = pt->next;
- pt->next = npt;
- }
- cout << "圖形鄰接串列內容 : " << endl;
- for(int i=1; i<6; i++) {
- graphicPoint *pt = head[i].next;
- cout << "頂點 " << i << "=>";
- while(pt!=NULL) {
- cout << "[" << pt->val << "] ";
- pt = pt->next;
- }
- cout << endl;
- }
- cout << "廣度優先走訪頂點 :" << endl;
- for(int i=0; i<6; i++) { // 初始化run 陣列
- run[i] = 0;
- }
- bfs(1);
- printf("\n");
- }
- }
補充說明 :
* [ 資料結構 小學堂 ] 佇列 : 認識佇列
沒有留言:
張貼留言