无向图-邻接矩阵-宽度优先遍历-BFS C代码实现

一、BFS算法思路

本算法以无向图为例,存储方式采用邻接矩阵

1)将该网以邻接矩阵的方式存储,由于这里的示例采用无向图,因此它是一个对称阵
2)选取A点为起始点,访问此顶点,用一个visit的bool型数组记录访问状态(false表示未被访问,true表示已访问)
3)从A的未被访问的邻接点出发,宽度优先遍历图,直到图中所有和v有路径相通的顶点都被访问到

宽度优先遍历需要借助队列,思想与二叉树的层序遍历类似

二、BFS测试用例

本算法的测试用例为《大话数据结构》p242中的图7-5-3


三、C代码邻接矩阵的BFS实现

/*******************************************************************************************
【BFS】
Author:tmw
date:2018-2-20
********************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>


#define MAX_VERTEX 100
#define inf 65535  //表示两点之间没有边相连

int visit[MAX_VERTEX];   //标记顶点是否被访问

/**图的邻接矩阵的建立**/
//邻接矩阵数据结构定义
typedef struct Martrix_Graph
{
    char vertex[MAX_VERTEX]; //存储顶点信息
    int edge[MAX_VERTEX][MAX_VERTEX]; //存储边信息
    int vertex_number,edge_number;//存储顶点数和边数
}Martrix_Graph;

void Create_non_direction_martrix_Graph( Martrix_Graph *G )
{
    int i,j,k,m;
    printf("请输入构造的无向图的顶点数和边数:\n");
    scanf("%d %d",&G->vertex_number,&G->edge_number);

    printf("请输入无向图顶点信息(如ABCDEF....):\n");
    char ch;
    while( ( ch = getchar() != '\n' ) );  //过滤掉前面的\n,防止\n被scanf进去
    for(i=0;i<G->vertex_number;i++)
        scanf("%c",&G->vertex[i]);

    //不相连的顶点之间的权值设为inf,包括顶点自身
    //初始化邻接矩阵
    for(i=0;i<G->vertex_number;i++)
        for(j=0;j<G->vertex_number;j++)
            G->edge[i][j] = inf;

    //更新无向图边信息
    printf("请输入无向图邻接矩阵相连的边信息,相连标记为1\n");
    for(k=0;k<G->edge_number;k++)
    {
        scanf("%d %d %d",&i,&j,&m);
        G->edge[i][j] = m;
        G->edge[j][i] = G->edge[i][j];//无向图是对称阵
    }


    //打印邻接矩阵存储信息,检查正确性
    printf("---------------------构造出来的无向图邻接矩阵如下---------------------\n");
    for(i=0;i<G->vertex_number;i++)
    {
        for(j=0;j<G->vertex_number;j++)
            printf("%d\t",G->edge[i][j]);
        printf("\n");
    }
}
/**BFS会用到队列这个数据结构**/
/**循环队列**/
typedef struct
{
    char data[MAX_VERTEX];
    int front;  //头指针
    int rear;   //尾指针,队列非空则指向队尾最后一个元素后一个位置
}SqQueue;

//队列初始化
void InitQueue(SqQueue *Q)
{
    Q->front = 0;
    Q->rear = 0;
}
//入队
bool EnQueue(SqQueue *Q, char e)
{
    //判断队列是否满
    if( ( Q->rear+1 ) % MAX_VERTEX == Q->front )
        return false;
    Q->data[Q->rear]=e;
    Q->rear = (Q->rear+1)%MAX_VERTEX;
    return true;
}
//出队---删除队首元素,并赋给e
char* DeQueue(SqQueue *Q, char *e)
{
    //判断队列是否为空
    if( Q->front == Q->rear )
        return NULL;
    *e = Q->data[Q->front];
    Q->front = (Q->front+1)%MAX_VERTEX;
    return e;
}
//队列判空
bool isEmptyQueue(SqQueue *Q)
{
    return Q->front == Q->rear?true:false;
}

//无向图邻接矩阵BFS
void BFS_Travel(Martrix_Graph G)
{
//    int layerNumer = 0;
    SqQueue Q;
    int i,j,mark;
    char data;
    //初始化visit数组
    for(i=0;i<G.vertex_number;i++)
        visit[i] = false;
    //初始化队列
    InitQueue(&Q);

    //开始遍历整个图的顶点--默认从第一个顶点开始
    printf("此邻接矩阵无向图BFS的结果为:\n");
    for(i=0;i<G.vertex_number;i++)
    {
        //对未访问的顶点做BFS
        if(!visit[i])
        {
            visit[i] = true;

            //将此顶点入队
            EnQueue(&Q,G.vertex[i]);
//            layerNumer++;

            while(!isEmptyQueue(&Q))
            {
                DeQueue(&Q,&data);  //队首顶点出队,并赋值给data
                printf("%c ",data);

                //找所删除顶点的下标,更新该下标值,以便正确找到与出队元素相连的其他顶点
                for( j = 0;j<G.vertex_number;j++)
                    if(G.vertex[j] == data )
                        mark = j ;
                //找寻与此顶点相连且未被访问的顶点,逐次标记、打印,并入队
                for(j=0;j<G.vertex_number;j++)
                {
                    if(G.edge[mark][j]==1 && !visit[j])
                    {

                        visit[j] = true;
//                        printf("%c ",G.vertex[j]);
                        EnQueue(&Q,G.vertex[j]);
                    }
                }
            }
        }

    }

}

四、测试代码及运行结果

int main()
{
    printf("测试代码\n");
    Martrix_Graph G;
    Create_non_direction_martrix_Graph(&G);
    BFS_Travel(G);
    return 0;
}


以下是 C++ 代码实现: ```c++ #include <iostream> #include <queue> #include <stack> #include <cstring> using namespace std; const int MAXN = 100; const int INF = 0x3f3f3f3f; int n; // 点的数量 int e[MAXN][MAXN]; // 邻接矩阵存储图 bool vis[MAXN]; // 标记节点是否被访问过 // 深度优先遍历 void dfs(int u) { vis[u] = true; cout << u << " "; for (int v = 0; v < n; v++) { if (e[u][v] && !vis[v]) { dfs(v); } } } // 广度优先遍历 void bfs(int s) { queue<int> q; memset(vis, false, sizeof(vis)); vis[s] = true; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); cout << u << " "; for (int v = 0; v < n; v++) { if (e[u][v] && !vis[v]) { vis[v] = true; q.push(v); } } } } // Dijkstra算法求最短路径 void dijkstra(int s) { int dist[MAXN]; // 存储源点到各个点的最短距离 bool vis[MAXN]; // 标记节点是否已经加入S集合 memset(vis, false, sizeof(vis)); for (int i = 0; i < n; i++) { dist[i] = INF; } dist[s] = 0; for (int i = 1; i < n; i++) { int u = -1; for (int j = 0; j < n; j++) { if (!vis[j] && (u == -1 || dist[j] < dist[u])) { u = j; } } vis[u] = true; for (int v = 0; v < n; v++) { if (e[u][v] && !vis[v]) { dist[v] = min(dist[v], dist[u] + e[u][v]); } } } cout << "源点到各点的最短距离为:" << endl; for (int i = 0; i < n; i++) { cout << s << "到" << i << "的最短距离为:" << dist[i] << endl; } } int main() { cout << "请输入节点数:"; cin >> n; cout << "请输入邻接矩阵:" << endl; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { cin >> e[i][j]; } } // 深度优先遍历 memset(vis, false, sizeof(vis)); cout << "深度优先遍历:"; for (int i = 0; i < n; i++) { if (!vis[i]) { dfs(i); } } cout << endl; // 广度优先遍历 memset(vis, false, sizeof(vis)); cout << "广度优先遍历:"; for (int i = 0; i < n; i++) { if (!vis[i]) { bfs(i); } } cout << endl; // Dijkstra算法求最短路径 cout << "请输入源点编号:"; int s; cin >> s; dijkstra(s); return 0; } ``` 需要注意的是,以上实现中的图默认为无向图。如果是有向图,需要在读入邻接矩阵时注意。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值