データ構造とアルゴリズムの基礎 (Wang Zhuo) (26) 添付資料: 隣接リストの幅優先走査アルゴリズム BFS (学習プロセス記録)

目次

隣接リストの幅優先トラバーサル アルゴリズム BFS

初版:

質問:

第 2 版のフレーム:

コンテキストを整理します。

バージョン 3: (エラー)

1:

2: 

最終結果: (コメント付きバージョン)

環境と前提条件を含むプログラム全体のバージョン:

Wish: 内輪もめしないで、何が起こっているのか分からないまま時間が過ぎていく、本当に不思議だ

以上


隣接リストの幅優先トラバーサル アルゴリズム 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);
    }
}

質問:

最初に、1 つの要素を最初にキューに入れる必要があります

デキュー操作はありませんが、同時に、
デキューの前提条件があること、つまり、リンク上の後続のすべてのエッジ ノードがチームに参加した後でのみデキューできることに気付きました。

ここでは再帰は使用できません。再帰を使用すると、新しいキューを繰り返し作成し始め、このように無限になるためです。


そして、これらの点を踏まえて、暫定的に列挙してみました。

第 2 版のフレーム:

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

 その結果、依然として多くの問題が残っています。

「訪問済み」とマークされていない 

 判断は j.next ではなくノード自体である必要があります。

そして重要なことは、このノードが空でない限り、常に次のノードを指すということです。

要素が以前にアクセスされたかどうかに関係なく、ループするたびに次のビットを見つける操作は同じです。

同様に、出力の数はデキューの数と一致している必要があります。

知らせ:

つまり、ヘッドはデキューと出力に使用されるということです

J は、ポイントされた各要素がループ処理に使用されることを意味します。


TMD は私が感じているようにまだ非常にわかりにくいので、まだ書かなければなりません。

コンテキストを整理します。

  1. リンク上のすべての [未訪問] 要素をキューに入れる
  2. 頂点をデキューする
  3. チームの先頭からトラバースを続けてループ ステップを繰り返します (つまり、1 と 2 はループ本体内のステートメントです)。

文脈に従って第 3 版を作成します。


バージョン 3: (エラー)

その後、長時間いじってみましたが、依然として次のような問題が発生しました。

1:

注:判決文

            if (visited[j->adjvex] == 0)// [unvisited] 要素をキューに入れる

「=」ではなく「==」である必要があります。


2: 

        cout << j->副詞;

注: これを出力するには 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<iostream>
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<stdlib.h>//存放exit
#include<math.h>//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()
{

}

Wish: 内輪もめしないで、何が起こっているのか分からないまま時間が過ぎていく、本当に不思議だ

以上

おすすめ

転載: blog.csdn.net/Zz_zzzzzzz__/article/details/130068772