bfs知识点

来源:互联网 发布:中控考勤软件 编辑:程序博客网 时间:2024/05/16 19:52


广度优先搜索算法英语:Breadth-First-Search),又译作宽度优先搜索,或横向优先搜索,简称BFS,是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。广度优先搜索的实现一般采用open-closed表。

目录

  [隐藏] 
  • 1 作法
  • 2 实现方法
    • 2.1 C 的实现
    • 2.2 C++ 的实现
  • 3 特性
    • 3.1 空间复杂度
    • 3.2 时间复杂度
    • 3.3 完全性
    • 3.4 最佳解
  • 4 广度优先搜索算法的应用
    • 4.1 寻找连接元件
    • 4.2 测试是否二分图
    • 4.3 应用于电脑游戏中平面网格
  • 5 参见
  • 6 参考资料
  • 7 外部连接

作法[编辑]

BFS是一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位址,彻底地搜索整张图,直到找到结果为止。BFS并不使用经验法则算法。

从算法的观点,所有因为展开节点而得到的子节点都会被加进一个先进先出的队列中。一般的实现里,其邻居节点尚未被检验过的节点会被放置在一个被称为 open 的容器中(例如伫列或是链表),而被检验过的节点则被放置在被称为 closed 的容器中。(open-closed表)

以德国城市为范例的地图。城市间有数条道路相连接。
从法兰克福开始执行广度优先搜索算法,所产生的广度优先搜索算法树。
广度优先搜索算法的动画范例

实现方法[编辑]

  1. 首先将根节点放入队列中。
  2. 从队列中取出第一个节点,并检验它是否为目标。
    • 如果找到目标,则结束搜寻并回传结果。
    • 否则将它所有尚未检验过的直接子节点加入队列中。
  3. 若队列为空,表示整张图都检查过了——亦即图中没有欲搜寻的目标。结束搜寻并回传“找不到目标”。
  4. 重复步骤2。
 s为初始点  R:=\{ s \},Q:=\{ s \},T=\empty  while Q \ne \empty      从Q中选一点         /* 选最先插入进Q的点,则为广度遍历,可以说先进先出。*/     /* 选最后插入进Q的点,则为深度遍历,可以说后进先出。 */     if \exists w \in N(v) \setminus R then    /* N(v):v的邻接点 */         Q:=Q \cup \{ w \}         R:=R \cup \{ w \}         T:=T \cup \{ vw \}     else Q:=Q \setminus \{ w \} return H=(R,T)

C 的实现[编辑]

广度优先搜索算法:

void BFS(VLink G[], int v) { int w;  VISIT(v);                    /*訪問頂點v*/  visited[v] = 1;              /*頂點v對應的訪問標記置為1*/  ADDQ(Q,v);  while(!EMPTYQ(Q))  { v = DELQ(Q);               /*退出隊頭元素v*/    w = FIRSTADJ(G,v);         /*求v的第1個鄰接點。無鄰接點則返回-1*/    while(w != -1)    { if(visited[w] == 0)      { VISIT(w);              /*訪問頂點v*/        ADDQ(Q,w);             /*當前被訪問的頂點w進隊*/        visited[w] = 1;        /*頂點w對應的訪問標記置為1*/      }      w = NEXTADJ(G,v);        /*求v的下一個鄰接點。若無鄰接點則返回-1*/    }  }  }

对图G=(V,E)进行广度优先搜索的主算法如下。

void TRAVEL_BFS(VLink G[], int visited[], int n){ int i;  for(i = 0; i < n; i ++)  { visited[i] = 0;            /* 標記數組賦初值(清零)*/  }  for(i = 0; i < n; i ++)    if(visited[i] == 0)      BFS(G,i);}

C++ 的实现[编辑]

(这个例子仅针对Binary Search Tree)
定义一个结构体来表达一个节点的结构:

 struct node {    int self; //数据    node *left; //左节点    node *right; //右节点 };

那么,我们在搜索一个树的时候,从一个节点开始,能首先获取的是它的两个子节点。例如:

   AB     C

A是第一个访问的,然后顺序是B和C;然后再是B的子节点,C的子节点。那么我们怎么来保证这个顺序呢?

这里就应该用queue数据结构,因为queue采用先进先出( first-in-first-out )的顺序。

使用C++的STL函式库,下面的程序能帮助理解:

 std::queue<node*> visited, unvisited;  node nodes[9]; node* current;  unvisited.push(&nodes[0]); //先把root放入unvisited queue  while(!unvisited.empty()) //只有unvisited不空 {    current = (unvisited.front()); //目前應該檢驗的     if(current -> left != NULL)       unvisited.push(current -> left); //把左邊放入queue中     if(current -> right != NULL) //右边压入。因为QUEUE是一个先进先出的结构,所以即使后面再压其他东西,依然会先访问这个。       unvisited.push(current -> right);     visited.push(current);     cout << current -> self << endl;     unvisited.pop(); }

特性[编辑]

空间复杂度[编辑]

因为所有节点都必须被储存,因此BFS的空间复杂度为 O(|V| + |E|),其中 |V| 是节点的数目,而 |E| 是图中边的数目。注:另一种说法称BFS的空间复杂度为 O(B^M),其中 B 是最大分支系数,而 M 是树的最长路径长度。由于对空间的大量需求,因此BFS并不适合解非常大的问题。

时间复杂度[编辑]

最差情形下,BFS必须寻找所有到可能节点的所有路径,因此其时间复杂度为 O(|V| + |E|),其中 |V| 是节点的数目,而 |E| 是图中边的数目。

完全性[编辑]

广度优先搜索算法具有完全性。这意指无论图形的种类如何,只要目标存在,则BFS一定会找到。然而,若目标不存在,且图为无限大,则BFS将不收敛(不会结束)。

最佳解[编辑]

若所有边的长度相等,广度优先搜索算法是最佳解——亦即它找到的第一个解,距离根节点的边数目一定最少;但对一般的图来说,BFS并不一定回传最佳解。这是因为当图形为加权图(亦即各边长度不同)时,BFS仍然回传从根节点开始,经过边数目最少的解;而这个解距离根节点的距离不一定最短。这个问题可以使用考虑各边权值,BFS的改良算法成本一致搜寻法来解决。然而,若非加权图形,则所有边的长度相等,BFS就能找到最近的最佳解。

广度优先搜索算法的应用[编辑]

广度优先搜索算法能用来解决图论中的许多问题,例如:

  • 寻找图中所有连接元件(Connected Component)。一个连接元件是图中的最大相连子图。
  • 寻找连接元件中的所有节点。
  • 寻找非加权图中任两点的最短路径。
  • 测试一图是否为二分图。
  • (Reverse) Cuthill–McKee算法

寻找连接元件[编辑]

由起点开始,执行广度优先搜索算法后所经过的所有节点,即为包含起点的一个连接元件。

测试是否二分图[编辑]

BFS 可以用以测试二分图。从任一节点开始搜寻,并在搜寻过程中给节点不同的标签。例如,给开始点标签 0,开始点的所有邻居标签 1,开始点所有邻居的邻居标签 2……以此类推。若在搜寻过程中,任一节点有跟其相同标签的邻居,则此图就不是二分图。若搜寻结束时这种情形未发生,则此图为一二分图。

应用于电脑游戏中平面网格[编辑]

BFS 可用来解决电脑游戏(例如即时策略游戏)中找寻路径的问题。在这个应用中,使用平面网格来代替图形,而一个格子即是图中的一个节点。所有节点都与它的邻居(上、下、左、右、左上、右上、左下、右下)相接。

值得一提的是,当这样使用BFS算法时,首先要先检验上、下、左、右的邻居节点,再检验左上、右上、左下、右下的邻居节点。这是因为BFS趋向于先寻找斜向邻居节点,而不是四方的邻居节点,因此找到的路径将不正确。BFS 应该先寻找四方邻居节点,接着才寻找斜向邻居节点1。









广度优先搜索算法(Breadth-First-Search),又译作宽度优先搜索,或横向优先搜索,简称BFS,是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。广度优先搜索的实现一般采用open-closed表。

特性

 

空间复杂度

因为所有节点都必须被储存,因此BFS的空间复杂度为 O(|V| + |E|),其中 |V| 是节点的数目,而 |E| 是图中边的数目。注:另一种说法称BFS的空间复杂度为 O(BM),其中 B 是最大分支系数,而 M 是树的最长路径长度。由于对空间的大量需求,因此BFS并不适合解非常大的问题。

时间复杂度

最差情形下,BFS必须寻找所有到可能节点的所有路径,因此其时间复杂度为 O(|V| + |E|),其中 |V| 是节点的数目,而 |E| 是图中边的数目。

最佳解

若所有边的长度相等,广度优先搜索算法是最佳解——亦即它找到的第一个解,距离根节点的边数目一定最少;但对一般的图来说,BFS并不一定回传最佳解。这是因为当图形为加权图(亦即各边长度不同)时,BFS仍然回传从根节点开始,经过边数目最少的解;而这个解距离根节点的距离不一定最短。这个问题可以使用考虑各边权值,BFS的改良算法成本一致搜寻法(en:uniform-cost search)来解决。然而,若非加权图形,则所有边的长度相等,BFS就能找到最近的最佳解。

广度优先搜索算法的应用

 

广度优先搜索算法能用来解决图论中的许多问题,例如:

  • 寻找图中所有连接元件(Connected Component)。一个连接元件是图中的最大相连子图。
  • 寻找连接元件中的所有节点。
  • 寻找非加权图中任两点的最短路径。
  • 测试一图是否为二分图。
  • (Reverse) Cuthill–McKee算法

 

寻找连接元件

由起点开始,执行广度优先搜索算法后所经过的所有节点,即为包含起点的一个连接元件。

广度优先搜索,即BFS(Breadth First Search),是一种相当常用的图算法,其特点是:每次搜索指定点,并将其所有未访问过的邻近节点加入搜索队列,循环搜索过程直到队列为空。

        算法描述如下:

        (1)将起始节点放入队列尾部

         (2)While(队列不为空)

取得删除队列首节点Node

                          处理该节点Node

                          把Node的未处理相邻节点加入队列尾部

         使用该算法注意的问题:

        (1)使用该算法关键的数据结构为:队列,队列保证了广度渡优先,并且每个节点都被处理到

         (2)新加入的节点一般要是未处理过的,所以某些情况下最初要对所有节点进行标记

         (3)广度优先在实际使用时,很对情况已超出图论的范围,将新节点加入队列的条件不再局限于

相邻节点这个概念。例如,使用广度优先的网络爬虫在抓取网页时,会把一个链接指向的网页中的所有

URL加入队列供后续处理。

         典型实例:

        1.图的遍历(VC6.0/VS2005)

////////////////////////////////// 
//广度优先之节点遍历 
//1-----5----------9 
//|        |              | 
//|        |              |   
//2-----4----6-----8 
//|               |         | 
//|             |         | 
//3----------7-----10 
// 1 2 3 4 5 6 7 8 
//1 0 1 0 0 1 0 0 0 
//2 1 0 1 1 0 0 0 0 
//3 0 1 0 0 0 0 1 0 
//4 0 1 0 0 1 1 0 0 
//5 1 0 0 1 0 0 0 0 
//6 0 0 0 1 0 0 1 1 
//7 0 0 1 0 0 1 0 0 
//8 0 0 0 0 0 1 0 0

#include 
#include 
using namespace std;

//节点数 
#define M 10

//图的矩阵表示 
int matrix[M][M] = 
{ 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 
0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 
1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 
0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 
0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 
0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 
0, 0, 0, 0, 0, 0, 1, 1, 0, 0

}; 
//访问标记,初始化为0, 
int visited[M + 1];

//graph traverse 
void GT_BFS() 

visited[1] = 1; 
queue q; 
q.push(1); 
while(!q.empty()) 

   int top = q.front(); 
   cout << top<<" ";//输出 
   q.pop(); 
   int i ; 
   for(i = 1; i <= M; ++i) 
   { 
    if(visited[i] == 0 && matrix[top - 1][i - 1 ] == 1) 
    { 
     visited[i] = 1; 
     q.push(i); 
    } 
   } 

}

int main() 

GT_BFS();//输出结果为1 2 5 3 4 9 7 6 8 10 
system("pause"); 
return 0; 
}

      2.有权最短路径,Dijkstra

/////////////////////////////////////////// 
//广度优先搜索之有权最短路径,Dijkstra算法 
// 1---(1)-->5 
// |     | 
//(2)      (12) 
// |        | 
// 2--(13)---4---(2)--6--(2)--8 
// |                  | 
//(4)               (5) 
// |                 | 
// 3----(1)----------7 
// 1 2 3 4 5 6 7 8 
//1 0 2 0 0 1 0 0 0 
//2 2 0 4 7 0 0 0 0 
//3 0 4 0 0 0 0 1 0 
//4 0 7 0 0 12 2 0 0 
//5 1 0 0 12 0 0 0 0 
//6 0 0 0 2 0 0 5 2 
//7 0 0 1 0 0 5 0 0 
//8 0 0 0 0 0 2 0 0

#include 
#include 
using namespace std;

//节点数 
#define M 8

//图的矩阵表示 
int matrix[M][M] = 
{ 0, 2, 0, 0, 1, 0, 0, 0, 
2, 0, 4, 13, 0, 0, 0, 0, 
0, 4, 0, 0, 0, 0, 1, 0, 
0, 13, 0, 0, 12, 2, 0, 0, 
1, 0, 0, 12, 0, 0, 0, 0, 
0, 0, 0, 2, 0, 0, 5, 2, 
0, 0, 1, 0, 0, 5, 0, 0, 
0, 0, 0, 0, 0, 2, 0, 0

};

//保存每个节点的最短路径,初始化为0xFFFF 
int dist[M + 1] ={0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}; 
//calculate the distance 
void Dijkstra_BFS(int startNodeNum) 

dist[startNodeNum] = 0; 
queue q; 
q.push(startNodeNum); 
while(!q.empty()) 

   int top = q.front(); 
   q.pop(); 
   cout<   int i ; 
   for(i = 1; i <= M; ++i) 
   { 
    if(matrix[top - 1][i - 1 ] != 0 && (dist[top] + matrix[top - 1][i -1]) < dist[i] ) 
    { 
     dist[i] = dist[top] + matrix[top - 1][i -1]; 
     q.push(i); 
    } 
   } 


void PrintDist() 
{

for(int i = 1; i <= M; ++i) 
   cout<}

int main() 

Dijkstra_BFS(1); 
PrintDist(); 
system("pause"); 
return 0; 
}

0 0
原创粉丝点击