图的遍历之广度优先搜索(Breadth First Search)

描述

广度优先搜索算法(Breadth First Search)与树的层序遍历(level-order traversal)类似,基本思想是思想是:

  1. 从图中某顶点v出发,访问v之后,并将其访问标志置为已被访问,即visited[i]=1;
  2. 依次访问v的各个未曾访问过的邻接点;
  3. 分别从这些邻接点出发依次访问它们的邻接点,并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直至图中所有已被访问的顶点的邻接点都被访问到;
  4. 如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。

如果用广度优先搜索算法对下图中结点进行搜索,从结点a出发,先搜索处理 它的子结点b和c,即深度为2的结点;然后搜索深度为3的子结点d、e、f、g;最后搜索深度为4的 结点h。
《图的遍历之广度优先搜索(Breadth First Search)》

伪代码如下:

bool visited[MAX_VERTEXT_NUM];  // 访问标记数组 


void BFS_Traversal(Graph G, int v)  
{    
    visit(v);          // 访问初始顶点 
    visited[v] = true;      // v已访问 
    Enqueue(Q, v);        // 顶点v入队列 
    while(!isEmpty(Q))    
    {      
        Dequeue(Q, v);      // 顶点v出队列 
        for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v))        
            if(!visited[w])   // 检测v的所有邻接点 
            {          
                visit(w);    // 若w未访问,访问之 
                visited[w]=true; // 标记 
                Enqueue(Q, w);  // 顶点w入队列 
            }    
    }  
}
void BFS(Graph G)    // 设访问函数为visit() 
{    
    for(i=0; i<G.vexnum; ++i)      
        visited[i] = false;   // 初始化 

    for(i=0; i<G.vexnum; ++i)  // 从0号顶点开始遍历 
        if(!visited[i])     // 对每个连通分量调用一次BFS 
            BFS_Traversal(G,i);      // Vi未访问过,从Vi开始BFS 
}    

测试代码

(图的存储是邻接表的深度优先搜索)

#include <iostream>
using namespace std;

#include <stdio.h>
#include <stdlib.h>

#define Max_Vertex_Num 100 //最大顶点数

typedef char VertexType;      //顶点数类型定义
typedef int EdgeType;        //边类型定义

typedef struct EdgeNode
{
    int adjvex;               // 该边所指的顶点的位置
    EdgeType weight;          //该边的权值
    struct EdgeNode *NextEdge; //指向下一条边的指针
}EdgeNode;

typedef struct VertexNode
{
    VertexType data;     // 顶点信息
    EdgeNode *firstEdge;  //指向第一条依附该顶点的边表头指针
}VertexNode, AdjList[Max_Vertex_Num];

typedef struct
{
    AdjList adjList;
    int EdgeNum;    // 图的当前边数
    int VertexNum;  //图的当前顶点数
    bool visited[Max_Vertex_Num];  //顶点是否被访问过
}ALGraph;


/* 队列是一种先进先出线性表,队列是线性表的特化 也具有线性表的性质分为:顺序队列与链式队列 链式队列与线性表的单链表相似只不过链式队列只 允许从头部进行删除、尾部进行插入.需要为链式队列 创建一个头结点包括两个指针,指向队头的指针(front) 与指向队尾的指针(rear).当两个指针相等时队列为空*/
typedef struct QueenNode
{
    int data;      //队列的数据
    struct QueenNode *Qnext;  //指向下一个结点
}QueenNode,*pQuee;



typedef struct
{
    pQuee front;   //指向队头的指针
    pQuee rear;    //指向队尾的指针
}LinkQueen;


void InitQueen(LinkQueen &Queen)
{
    Queen.front = Queen.rear = (pQuee)malloc(sizeof(QueenNode));//初始化队头与队尾的指针指向头结点
    if(!Queen.front) //生成头结点失败
        exit(1);
    Queen.front->Qnext = NULL;
}

void DestroyQueen(LinkQueen &Queen)
{
    while(Queen.front)
    {
        Queen.rear = Queen.front->Qnext;
        free(Queen.front);
        Queen.front = Queen.rear;
    }
}

bool IsEmpty(LinkQueen &Queen) //判断队列是否为空
{
    if(Queen.front == Queen.rear)
        return true;
    return false;
}

 // 插入元素e为队列Q的新的队尾元素。

 void EnQueen(LinkQueen &Queen, int data)
 {
     pQuee ptr;

     ptr = (pQuee)malloc(sizeof(QueenNode));  //动态生成新结点
     if(!ptr)
        exit(1);

     ptr->data = data;
     ptr->Qnext = NULL; //队列只能从队尾插入所以下一个结点初始化为NULL
     Queen.rear->Qnext = ptr;  // 原队尾结点的指针指向新结点,如果新结点为第一个结点则q->rear->next相当于q->front->next
     Queen.rear = ptr;       // 尾指针指向新结点
 }

//删除Q的队头元素,用e返回其值
void DeQueen(LinkQueen &Queen, int *data)
{
    pQuee ptr;
    if(Queen.front == Queen.rear)  // 队列空
        exit(1);
    ptr = Queen.front->Qnext ;   // p指向队头结点
    *data = ptr->data;              // 将队头元素的值赋给data
    Queen.front->Qnext = ptr->Qnext;  // 头结点指向下一个结点
    if(Queen.rear==ptr) // 删除的是队尾结点
        Queen.rear=Queen.front; // 修改队尾指针指向头结点(空队列)
    free(ptr); // 释放队头结点
}



// 返回顶点v的位置
int LocateVertex(ALGraph *G, VertexType v)
{
    int i = 0;
    for(i = 0; v != G->adjList[i].data && i < G->VertexNum; i ++);

    if(i >= G->VertexNum)
        return -1;
    return i;
}

//增加节点
void AddVertex(ALGraph *G)
{
    cout << "input vertex number" << endl;
    cin >> G->VertexNum;

    cout << "input vertex value" << endl;
    for(int i = 0; i < G->VertexNum; i++)
    {
        cin >> G->adjList[i].data;
        G->adjList[i].firstEdge = NULL;
    }
}

//增加边表
void AddEdge(ALGraph *G)
{
    cout << "input edge number" << endl;
    cin >> G->EdgeNum ;
    VertexType V1, V2;
    cout << "input two vertex" << endl;
    for(int k = 0; k < G->EdgeNum; k ++)
    {
        cin >> V1 >> V2;
        int i = LocateVertex(G,V1);
        int j = LocateVertex(G,V2);

        EdgeNode *pe1 = (EdgeNode *)malloc(sizeof(EdgeNode));
        pe1->adjvex = i;
        pe1->NextEdge = G->adjList[j].firstEdge;
        G->adjList[j].firstEdge = pe1;

        EdgeNode *pe2 = (EdgeNode *)malloc(sizeof(EdgeNode));
        pe2->adjvex = j;
        pe2->NextEdge = G->adjList[i].firstEdge;
        G->adjList[i].firstEdge = pe2;

    }
}

void CreatALGraph(ALGraph *G)
{
    AddVertex(G);
    AddEdge(G);
}

void PrintALGrap(ALGraph *G)
{
    EdgeNode *pe;
    cout << "编号 顶点 邻点编号" << endl;

    for(int i = 0; i < G->VertexNum; i ++)
    {
        cout << " " << i << " " << G->adjList[i].data << " ";
        for(pe = G->adjList[i].firstEdge; pe; pe = pe->NextEdge)
            cout << pe->adjvex << " ";
        cout << endl;
    }
}

// 广度搜索
void BFS(ALGraph *G, int i)
{
    EdgeNode *pe;
    LinkQueen queen;

    InitQueen(queen);
    G->visited[i] = true;
    EnQueen(queen,i);
    cout << G->adjList[i].data << " ";  //打印顶点


    while(!IsEmpty(queen))
    {
        DeQueen(queen,&i);
        pe = G->adjList[i].firstEdge;
        while(pe)
        {
            if(!G->visited[pe->adjvex])
            {
                G->visited[pe->adjvex] = true;
                cout << G->adjList[pe->adjvex].data << " ";  //打印顶点
                EnQueen(queen,pe->adjvex);
            }

            pe = pe->NextEdge;
        }
    }


}

void BFS_Traverse(ALGraph *G)
{
    int i = 0;
    for(i = 0; i < G->VertexNum; i ++)
        G->visited[i] = 0;
    for(i = 0; i < G->VertexNum; i ++)
        if(!G->visited[i])
            BFS(G,i);
}

int main()
{
    ALGraph GL;
    CreatALGraph(&GL);
    PrintALGrap(&GL);
    BFS_Traverse(&GL);
}

(图的存储是邻接矩阵的深度优先搜索)

#include <iostream>
using namespace std;

#include <stdio.h>
#include <stdlib.h>

const int VERTEX_NUM = 20;    // 顶点的最大数

typedef int graph_weight_t;   // 边的权值类型 可以为 int float double
typedef struct SArc
{
    graph_weight_t Weight;            // 权值
}AdjMatrix[VERTEX_NUM][VERTEX_NUM];   // 邻接矩阵

typedef struct SGraph
{
    int       iVertexNum;     // 顶点数
    int       iArcNum;        // 边数
    int       aVertex[VERTEX_NUM];  // 顶点向量
    AdjMatrix mArcs;          //邻接矩阵
    bool visited[VERTEX_NUM];
}Graph;

/* 队列是一种先进先出线性表,队列是线性表的特化 也具有线性表的性质分为:顺序队列与链式队列 链式队列与线性表的单链表相似只不过链式队列只 允许从头部进行删除、尾部进行插入.需要为链式队列 创建一个头结点包括两个指针,指向队头的指针(front) 与指向队尾的指针(rear).当两个指针相等时队列为空*/
typedef struct QueenNode
{
    int data;      //队列的数据
    struct QueenNode *Qnext;  //指向下一个结点
}QueenNode,*pQuee;



typedef struct
{
    pQuee front;   //指向队头的指针
    pQuee rear;    //指向队尾的指针
}LinkQueen;


void InitQueen(LinkQueen &Queen)
{
    Queen.front = Queen.rear = (pQuee)malloc(sizeof(QueenNode));//初始化队头与队尾的指针指向头结点
    if(!Queen.front) //生成头结点失败
        exit(1);
    Queen.front->Qnext = NULL;
}

void DestroyQueen(LinkQueen &Queen)
{
    while(Queen.front)
    {
        Queen.rear = Queen.front->Qnext;
        free(Queen.front);
        Queen.front = Queen.rear;
    }
}

bool IsEmpty(LinkQueen &Queen) //判断队列是否为空
{
    if(Queen.front == Queen.rear)
        return true;
    return false;
}

 // 插入元素e为队列Q的新的队尾元素。

 void EnQueen(LinkQueen &Queen, int data)
 {
     pQuee ptr;

     ptr = (pQuee)malloc(sizeof(QueenNode));  //动态生成新结点
     if(!ptr)
        exit(1);

     ptr->data = data;
     ptr->Qnext = NULL; //队列只能从队尾插入所以下一个结点初始化为NULL
     Queen.rear->Qnext = ptr;  // 原队尾结点的指针指向新结点,如果新结点为第一个结点则q->rear->next相当于q->front->next
     Queen.rear = ptr;       // 尾指针指向新结点
 }

//删除Q的队头元素,用e返回其值
void DeQueen(LinkQueen &Queen, int *data)
{
    pQuee ptr;
    if(Queen.front == Queen.rear)  // 队列空
        exit(1);
    ptr = Queen.front->Qnext ;   // p指向队头结点
    *data = ptr->data;              // 将队头元素的值赋给data
    Queen.front->Qnext = ptr->Qnext;  // 头结点指向下一个结点
    if(Queen.rear==ptr) // 删除的是队尾结点
        Queen.rear=Queen.front; // 修改队尾指针指向头结点(空队列)
    free(ptr); // 释放队头结点
}

void IintGraph(Graph &graph)
{
    //graph = (pGraph)malloc(sizeof(Graph));
    graph.iVertexNum = 0;
    graph.iArcNum    = 0;
    for(int i = 0; i < VERTEX_NUM; i++)
        graph.aVertex[i] = 0;
    for(int i = 0; i < VERTEX_NUM; i ++)
        for(int j= 0; j < VERTEX_NUM; j ++)
            graph.mArcs[i][j].Weight = 0;
}

void Add_Vertex(Graph &graph)
{
    cout << "Add Vertex" << endl;
    cout << "Input vertex number:";
    cin >> graph.iVertexNum;

    cout << "Input vertex value:";
    for(int i = 0; i < graph.iVertexNum; i ++)
        cin >> graph.aVertex[i];
}

int Locat_vertex(Graph &graph, int vertex)
{
    for(int i = 0; i < graph.iVertexNum; i ++)
    {
        if(graph.aVertex[i] == vertex)
            return i;
    }

    return -1;
}

void Add_Arcs(Graph &graph)
{
    cout << "Add Arcs" << endl;
    cout << "input arcs numbers:";
    cin >> graph.iArcNum;

    int   iFirst           = 0;
    int   iSecond          = 0;
    int   iRow             = 0;
    int   iCol             = 0;
    graph_weight_t iWeight  = 0;
    for(int i = 0; i < graph.iArcNum; i ++)
    {
        cout << "Input two Arc and Weight(ex. 1 2 32)" << endl;
        cin >> iFirst >> iSecond >> iWeight;

        iRow   =  Locat_vertex(graph, iFirst);
        iCol   =  Locat_vertex(graph, iSecond);

        graph.mArcs[iRow][iCol].Weight = iWeight;
        graph.mArcs[iCol][iRow].Weight = iWeight;
    }

}

void Creat_Graph(Graph &graph)
{
    cout << "Creat Graph" << endl;
    Add_Vertex(graph);
    Add_Arcs(graph);
}

void Show_Graph(Graph &graph)
{
    cout << "show the graph represented by adjmatrix "<<endl;

    for(int row = 0; row < graph.iVertexNum; row ++)
    {
        for(int col =0; col < graph.iVertexNum; col ++)
        {
            cout << graph.mArcs[row][col].Weight << "\t";
        }
        cout << endl;
    }

}



void BFS(Graph &graph, int i)
{
    LinkQueen queen;

    InitQueen(queen);
    graph.visited[i] = true;

    cout << graph.aVertex[i] << " ";
    EnQueen(queen,i);
    while(!IsEmpty(queen))
    {
        DeQueen(queen,&i);
        for(int j = 0; j < graph.iVertexNum; j ++)
        {
            if(graph.mArcs[i][j].Weight==1&&!graph.visited[j])
            {
                graph.visited[j] = true;
                cout << graph.aVertex[j] << " ";
                EnQueen(queen,j);
            }

        }
    }

}

void BFS_traversal(Graph &graph)
{
    for(int i = 0; i < graph.iVertexNum; i ++)
        graph.visited[i] = 0;

    for(int j = 0; j < graph.iVertexNum; j ++)
    {
        if(!graph.visited[j])
            BFS(graph,j);
    }
}

int main()
{
    Graph graph;
    IintGraph(graph);
    Creat_Graph(graph);
    Show_Graph(graph);
    BFS_traversal(graph);
}



    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/zwhlxl/article/details/45100931
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞