数据结构与算法基础(王卓)(24)附:邻接表的广度优先遍历算法BFS(学习过程记录)

邻接表的广度优先遍历算法BFS

第一版:

void BFS(ALG G, int v)
{
    cout << G.vex[v].data;
    visited[v] = 1;
    SqQueue Q;
    InitQueue(Q);
    auto i=G.vex[v].firstarc;
    while(!QueneEmpty(Q))
    { 
        if(visited[i->adjvex]=0)
            EnQueue(Q, i->adjvex);
        i = i->nextarc;
        BFS(G,i->adjvex);
    }
}

问题:

一开始要先入队一个元素

没有进行出队操作,与此同时我们注意到:
要出队有一个前提条件,那就是该条链路上的所有后继边结点都已经入队以后我们才可以出队

这里面不能用递归,因为用递归他就不断的开始重复新建队列,他这样就搞没完了


然后我们根据这些点,就暂时列出搞出来了

第二版的框架:

{
    //i表示头,J表示指向的每个元素
    while (j.next != NULL)
    {
        if(visited[j.邻接])
        {
            入队;
            下一位;
            输出;
        }
        出队;
    }
}

 结果还是有不少问题:

没有标记“已访问” 

 判断的应该是结点本身,而不是:j.next

而重要的是:只要这个节点不为空,我们就永远指向下一位

不管元素之前有没有没输出访问过,我们每次循环寻找下一位的操作都是不变的

同样的,输出的次数应该是和出队的次数保持一致的

注意:

I表示头用来出队和输出

J表示指向的每个元素用来循环遍历


所以感觉这里写的有点乱啊,TMD这里面这样随着感觉些感觉还是很混乱,还是要

理清一下脉络:

  1. 把链路上所有【没被访问过的】元素都入队
  2. 将顶点出队
  3. 继续从队首开始遍历,重复循环步骤(也就是说1、2是循环体内部的语句)

根据脉络去写第三版:


第三版:(错误)

然后我们又去鼓捣了半天,但是依然还是出现了以下的问题错误:

1:

注意:判断语句

            if (visited[j->adjvex] == 0)//入队【没被访问过的】元素

应该是“==”,而不是“=”


2: 

        cout << j->adjvex;

注意:我们应该是用 i 来输出这个玩意


在过程中碰到的问题主要大概就是以上这些了,因为学习过程中我没有把每次的程序修改都去打版修改,只能根据过程列出来这些坑,可能还有其他的,但是这些坑应该是已经踩得够多了,,


最终结果:(含注释版本)

int visited[MVNum] = {};    
void BFS(ALG G, int v)
{
    cout << G.vex[v].data;
    visited[v] = 1;
    SqQueue Q;
    InitQueue(Q);
    EnQueue(Q, G.vex[v].firstarc->adjvex);//从第一个顶点开始遍历
    auto i = G.vex[v].firstarc;//指向(代表)链头
    while (!QueneEmpty(Q))//直至队空结束
    {
        auto j = i;//用于指向访问各个元素节点
        while (j != NULL)//当结点为空(链尾,结束了)结束循环
        {
            if (visited[j->adjvex] == 0)//入队【没被访问过的】元素
            {
                EnQueue(Q, j->adjvex);
            }
            j = j->nextarc;//指向下一轮循环
            visited[j->adjvex] = 1;//别忘了
        }
        DeQueue(Q, i->adjvex);//出队队头
        cout << j->adjvex;
        //输出出队的元素,当然这里出队和输出在循环开始时操作也可以
    }
}

包括环境以及前置条件的整个程序版本:

#include
using namespace std;

typedef int Status;

#define MVNum 100  //最大顶点数
//MAX Vertex Number
typedef char VertexType;  //设顶点类型:字符型

//弧/边的结点结构
typedef int OtherInfo;
struct ArcNode
{
    int adjvex;//Adjacency
    //该边所指向的(相邻)顶点的位置
    struct ArcNode* nextarc;  //指向下一条边的指针
    OtherInfo info;  //和边相关的信息
};

struct VertexNode
    //顶点的结点结构
{
    VertexType data;  //顶点信息
    ArcNode* firstarc;  //指向第一条依附该顶点的边的指针
};

//图的结构定义
struct ALG
{
    //AdjList vertices;  
    VertexNode vex[MVNum];//顶点表
    int vexnum, arcnum;  //顶点数和边数
}; //Adjacency List Graph

#include//存放exit
#include//OVERFLOW,exit

#define TRUE        1
#define FALSE       0
#define OK          1
#define ERROR       0
#define INFEASIBLE  -1
//#define OVERFLOW   -2   

typedef char QElemType;
typedef int Status;         //函数调用状态
#define MAXQSIZE 100  //初始大小为100,可按需修改

struct SqQueue//循环队列定义
{
    QElemType* base;//初始化的动态分配存储空间
    int rear;//头指针
    int front;//尾指针
};

Status InitQueue(SqQueue& Q)//初始化
{
    Q.base = new QElemType[MAXQSIZE];
    //Q.base = (QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
    if (!Q.base) exit(OVERFLOW);//存储分配失败
    Q.rear = Q.front = 0;
    return true;
}

Status Queuelength(SqQueue Q)//求长度
{
    return(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

QElemType GetHead(SqQueue Q)//取队头元素
{
    if (Q.front != Q.rear)
        //别忘排除空表的情况
        return(Q.base[Q.front]);
}

Status EnQueue(SqQueue& Q, QElemType e)//入队
{
    if ((Q.rear + 1) % MAXQSIZE == Q.front)
        return OVERFLOW;
    Q.base[Q.rear] = e;
    //这里rear只是下标,不是指针,所以只能这样用
    Q.rear = (Q.rear + 1) % MAXQSIZE;
    return true;
}

Status DeQueue(SqQueue& Q, QElemType e)//出队
{
    if (Q.front == Q.rear)
        return NULL;
    e = Q.base[Q.front];
    Q.front = (Q.front + 1) % MAXQSIZE;
    return true;
}

Status QueneEmpty(SqQueue& Q)
{
    if (Q.front == Q.rear)
        return true;
    else
        return false;
}

int visited[MVNum] = {};    
void BFS(ALG G, int v)
{
    cout << G.vex[v].data;
    visited[v] = 1;
    SqQueue Q;
    InitQueue(Q);
    EnQueue(Q, G.vex[v].firstarc->adjvex);//从第一个顶点开始遍历
    auto i = G.vex[v].firstarc;//指向(代表)链头
    while (!QueneEmpty(Q))//直至队空结束
    {
        auto j = i;//用于指向访问各个元素节点
        while (j != NULL)//当结点为空(链尾,结束了)结束循环
        {
            if (visited[j->adjvex] == 0)//入队【没被访问过的】元素
            {
                EnQueue(Q, j->adjvex);
            }
            j = j->nextarc;//指向下一轮循环
            visited[j->adjvex] = 1;//别忘了
        }
        DeQueue(Q, i->adjvex);//出队队头
        cout << j->adjvex;
        //输出出队的元素,当然这里出队和输出在循环开始时操作也可以
    }
}

int main()
{

}

祝愿:不要内耗,不知道怎么回事时间就莫名其妙过去了,真的很奇怪

以上

你可能感兴趣的:(算法,深度优先,宽度优先)