广度优先遍历也叫广度优先搜索(Breadth First Search)。
它的遍历规则:
1.先访问完当前顶点的所有邻接点。(应该看得出广度的意思)
2.先访问顶点的邻接点先于后访问顶点的邻接点被访问。
给定一图G=<V,E>,用visited[i]表示顶点i的访问情况,则初始情况下所有的visited[i]都为false。假设从顶点V0开始遍历,且顶点V0的邻接点,从小到大有Vi、Vj...Vk。按规则1,接着应遍历Vi、Vj ... Vk。再按规则2,接下来应遍历Vi的所有邻接点,之后是Vj的所有邻接点,...,最后是Vk的所有邻接点。接下来就是递归的过程...
在广度遍历的过程中,会出现图不连通的情况,此时也需按上述情况二来进行:测试visited[i]...。在上述过程中,可以看出需要用到队列。
从V0开始遍历,V0有两个邻接点V1和V2,于是按序遍历V1、V2。V1先于V2被访问,于是V1的邻接点应先于V2的邻接点被访问,那就是接着访问V3。V2无邻接点,只能看V3的邻接点了,而V0已被访问过了。此时需检测visited[i],只有V4了。广度遍历完毕。
遍历序列是
V0->V1->V2->V3->V4。
从其它顶点出发的广度优先遍历序列是
V1->V3->V0->V2->V4。
V2->V0->V1->V3->V4。
V3->V0->V1->V2->V4。
V4->V2->V0->V1->V3。
以上结果,我们同样用于测试程序。
// 邻接矩阵的STL实现 BFS Status InitQueue(Queue *Q) { Q->front=0; Q->rear=0; return OK; } void BFSTraverse(MGraph G) { //按广度优先非递归地遍历图G。使用辅助队列Q和访问标志数组visited int v, w, u; Queue Q; // 自定义数据结构 - 队列 // front; /* 头指针 */ // rear; /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */ for(v=0; v<G.vexnum; ++v) // 访问标志数组初始化 visited[v] = false; InitQueue(Q); // 置空的辅助队列 for(v=0; v<G.vexnum; ++v) if(!visited[v]) { visited[v] = true; VisitFunc(v); EnQueue(Q,v); // 入队 while(QueueEmpty(Q) == FALSE){ DeQueue(Q, u); //对头元素出队,并置为u for(w = FirstAdjVex(G,v); w>=0; w=NextAdjVex(G, v, w)) if(!visited[w]){ // w为u未访问的邻接顶点 visited[w] = true; VisitFunc(w); // 自定义函数 - 输出节点数据 EnQueue(Q, w); } } }//if }//BFSTraverse int FirstAdjVex(MGraph G, int v) { //返回节点v的第一个邻接顶点 int i; for(i=0; i<G.vexnum; ++i) if(G.arcs[v][i].adj != 0 && i!=v) return i; return -1; //如果没有,返回-1 } int NextAdjVex(MGraph G, int v, int w) { //返回节点v的邻接顶点中w之后的下一个邻接顶点 int i; for(i=w+1; i<G.vexnum; ++i) if(G.arcs[v][i].adj != 0 && i!=v) return i; return -1; //如果没有,返回-1 }
// 邻接表的STL实现 BFS void BFSTraverse(GraphAdjList GL) { int i; EdgeNode *p; Queue Q; for(i = 0; i < GL->numVertexes; i++) visited[i] = FALSE; InitQueue(&Q); for(i = 0; i < GL->numVertexes; i++) // 第一层循环 { if (!visited[i]) { visited[i]=TRUE; printf("%c ",GL->adjList[i].data);/* 打印顶点,也可以其它操作 */ EnQueue(&Q,i); // 入队 while(!QueueEmpty(Q)) // 第二层循环 { DeQueue(&Q,&i); // 出队 p = GL->adjList[i].firstedge; /* 找到当前顶点的边表链表头指针 */ while(p) // 第三层循环 { if(!visited[p->adjvex]) /* 若此顶点未被访问 */ { visited[p->adjvex]=TRUE; printf("%c ",GL->adjList[p->adjvex].data); EnQueue(&Q,p->adjvex); /* 将此顶点入队列 */ } p = p->next; /* 指针指向下一个邻接点 */ } } } } } Status EnQueue(Queue *Q,int e) { if ((Q->rear+1)%MAXSIZE == Q->front) /* 队列满的判断 */ return ERROR; Q->data[Q->rear]=e; /* 将元素e赋值给队尾 */ Q->rear=(Q->rear+1)%MAXSIZE;/* rear指针向后移一位置, */ /* 若到最后则转到数组头部 */ return OK; } /* 若队列不空,则删除Q中队头元素,用e返回其值 */ Status DeQueue(Queue *Q,int *e) { if (Q->front == Q->rear) /* 队列空的判断 */ return ERROR; *e=Q->data[Q->front]; /* 将队头元素赋值给e */ Q->front=(Q->front+1)%MAXSIZE; /* front指针向后移一位置, */ /* 若到最后则转到数组头部 */ return OK; }
【数组邻接表采用指针实现广度优先遍历(不推荐)】
/* 广度优先搜索 从vertex开始遍历,visit是遍历顶点的函数指针 */ void Graph::bfs(int vertex, void(*visit)(int)) { //使用队列 queue<int> q; //visited[i]用于标记顶点i是否被访问过 bool *visited = new bool[numV]; //count用于统计已遍历过的顶点数 int i, count; for (i = 0; i < numV; i++) visited[i] = false; q.push(vertex); visit(vertex); visited[vertex] = true; count = 1; while (count < numV) { if (!q.empty()) { vertex = q.front(); q.pop(); } else { for (vertex = 0; vertex < numV && visited[vertex]; vertex++); visit(vertex); visited[vertex] = true; count++; if (count == numV) return; q.push(vertex); } //代码走到这里,vertex是已经访问过的顶点 for (int i = 0; i < numV; i++) { if (!visited[i] && matrix[vertex][i] > 0 && matrix[vertex][i] < MAXWEIGHT) { visit(i); visited[i] = true; count ++; if (count == numV) return; q.push(i); } } } delete[]visited; } void visit(int vertex) { cout << setw(4) << vertex; } int main() { cout << "******图的遍历:深度优先、广度优先***by David***" << endl; bool isDirected, isWeighted; int numV; cout << "建图" << endl; cout << "输入顶点数 "; cin >> numV; cout << "边是否带权值,0(不带) or 1(带) "; cin >> isWeighted; cout << "是否是有向图,0(无向) or 1(有向) "; cin >> isDirected; Graph graph(numV, isWeighted, isDirected); cout << "这是一个"; isDirected ? cout << "有向、" : cout << "无向、"; isWeighted ? cout << "有权图" << endl : cout << "无权图" << endl; graph.createGraph(); cout << "打印邻接矩阵" << endl; graph.printAdjacentMatrix(); cout << endl; cout << "深度遍历" << endl; for (int i = 0; i < numV; i++) { graph.dfs(i, visit); cout << endl; } cout << endl; cout << "广度遍历" << endl; for (int i = 0; i < numV; i++) { graph.bfs(i, visit); cout << endl; } system("pause"); return 0; }
【代码详址】
http://blog.csdn.net/manoel/article/details/16119969