12、图的广度优先遍历算法(BFS)

// 图的广度优先遍历算法BFS
// 1、存储结构:临界表(选用这个) + 临界矩阵
// 2、遍历算法:BFS(选这个)+ DFS

// 临界表
// 结点方式:a.头结点 + b.边表结点
// a.头结点----data(数据) | firstedge(第一条边)
// b.边表结点----adjvex(临界点域:存放与该点相临的结点在数组中的位置) | nextarc(链域:指向下一条边或弧)

// BFS
// 1、创建visited数组,记录该结点是否被访问过
// 2、创建队列
//      a.将第一个结点入队
//      b.将该结点相邻的结点
//      c.将第一个结点出对
#include <string>
#include <iostream>
#define MAXNUM 100 // 图中最大顶点数
using namespace std;
typedef string VexType; // 结点类型
typedef VexType QElemType;

struct ArcNode;

// a.头结点
struct HNode
{
    VexType data;
    ArcNode *firstedge;
};
// b.边表结点
struct ArcNode
{
    int adjvex;
    ArcNode *nextarc;
};

typedef HNode AdjList[MAXNUM]; // 头结点数组 AdjList v; ---- HNode v[MVNUM];

// 图的结构定义
struct ALGraph
{
    AdjList vertices;     // vertices -- vertex的复数,找到头结点相当于找到了邻接表
    int vexnum, arcnum;   // 图当前顶点数和弧数
    bool visited[MAXNUM]; // 1
};

// 采用临界表的方式创建无向图
void CreateUDG(ALGraph &);

// 定位临界表中点的信息
int LocateVex(const ALGraph &, VexType &);

// BFS
void BFS(ALGraph &);
// 创建队列
struct Queue
{
    QElemType elem[MAXNUM];
    int front, rear;
};
void InitQueue(Queue &Q);             // 初始化
bool IsEmptyQueue(const Queue &Q);    // 判断是否为空
void EnQueue(Queue &Q, QElemType &v); // 入队
QElemType DeQueue(Queue &Q);          // 出对

int main()
{
    ALGraph G;
    CreateUDG(G);
    for (int i = 0; i < G.vexnum; ++i)
    {
        cout << G.vertices[i].data << " ";
        cout << "该结点相邻的边: ";
        ArcNode *temp = G.vertices[i].firstedge;
        while (temp)
        {
            cout << G.vertices[temp->adjvex].data << " ";
            temp = temp->nextarc;
        }
        cout << endl;
    }

    // // 测试队列
    // QElemType e = "v1";
    // Queue q;
    // EnQueue(q, e);
    // cout << DeQueue(q) << endl;
    BFS(G);

    return 0;
}

void CreateUDG(ALGraph &G)
{
    // 1.建立头结点数组
    cout << "请输入结点数和边数: " << endl;
    cin >> G.vexnum >> G.arcnum;
    for (int i = 0; i < G.vexnum; ++i)
    {
        cout << "请输入第" << i + 1 << "个结点信息:" << endl;
        cin >> G.vertices[i].data;
        G.vertices[i].firstedge = NULL;
    }
    // 2.建立结点相邻的结点信息
    // a.定位结点在结点表中的位置;
    // b.生成两个边表结点头插到头结点后面
    for (int i = 0; i < G.arcnum; ++i)
    {
        cout << "请输入第" << i + 1 << "条边所依赖的结点: " << endl;
        VexType v1, v2;
        cin >> v1 >> v2;
        // a
        int i1 = LocateVex(G, v1);
        int i2 = LocateVex(G, v2);

        // b
        ArcNode *p1 = new ArcNode{i1, NULL};
        p1->nextarc = G.vertices[i2].firstedge;
        G.vertices[i2].firstedge = p1;
        ArcNode *p2 = new ArcNode{i2, NULL};
        p2->nextarc = G.vertices[i1].firstedge;
        G.vertices[i1].firstedge = p2;
    }

    // 初始化visited数组
    for (int i = 0; i < G.vexnum; ++i)
    {
        G.visited[i] = 0;
    }
}

int LocateVex(const ALGraph &G, VexType &v)
{
    for (int i = 0; i < G.vexnum; ++i)
    {
        if (v == G.vertices[i].data)
            return i;
    }
    return -1;
}

void BFS(ALGraph &G)
{
    Queue q;
    InitQueue(q);
    cout << "选择一个遍历起点: ";
    VexType e;
    cin >> e;
    EnQueue(q, e);
    int j = LocateVex(G, e);
    G.visited[j] = 1;
    while (!IsEmptyQueue(q))
    {
        e = DeQueue(q);
        cout << "出对: " << e << endl;
        int i = LocateVex(G, e);
        ArcNode *temp = G.vertices[i].firstedge;
        while (temp)
        {
            if (!G.visited[temp->adjvex])
            {
                VexType e1 = G.vertices[temp->adjvex].data; // 入队元素
                // cout << "入队: " << e1 << endl;
                EnQueue(q, e1);
                G.visited[temp->adjvex] = 1;
            }
            temp = temp->nextarc;
        }
    }
}

void InitQueue(Queue &Q)
{
    Q.front = Q.rear = 0;
}
bool IsEmptyQueue(const Queue &Q)
{
    return Q.front == Q.rear;
}

void EnQueue(Queue &Q, QElemType &v)
{
    Q.elem[Q.rear] = v;
    ++Q.rear;
}

QElemType DeQueue(Queue &Q)
{
    QElemType e;
    e = Q.elem[Q.front];
    ++Q.front;
    return e;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值