广度优先搜索,图的遍历

1、  队列

(1)       定义

    队列也是一种运算受限的线性表。在这种线性表上,插入限定在表的某一端进行,删除限定在表的另一端进行。允许插入的一端称为队尾,允许删除的一端称为队头。

    特点:队列中数据元素的入队和出队过程是按照“先进先出” 的原则进行的。因此,队列又称为“先进先出”的线性表,简称FIFO

(2)       实现-链队列

队列的链式存储结构简称为链队。它实际上是一个同时带有首指针和尾指针的单链表。头指针指向表头结点,而尾指针则指向队尾元素。从队尾插入,从队首删除。空的链队对列的判决条件是头指针和尾指针均指向头结点。

10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地

链队运算指针变化情况:

10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地

2、  广度优先搜索的算法思想

广度优先搜索遍历类似于树的按层次遍历。

    对于无向连通图,广度优先搜索是从图的某个顶点v0出发,在访问v0之后,依次搜索访问v0的各个未被访问过的邻接点w1w2,…。然后顺序搜索访问w1的各未被访问过的邻接点,w2的各未被访问过的邻接点,…。即从v0开始,由近至远,按层次依次访问与v0有路径相通且路径长度分别为12,…的顶点,直至连通图中所有顶点都被访问一次。

广度优先搜索的顺序不是唯一的。

具体描述如下:

设图G的初态是所有顶点均未访问,在中任选一顶点i作为初始点,则广度优先搜索的基本思想是:

1)从图中的某个顶点V出发,访问之;并将其访问标志置为已被访问,即visited[i]=1

2)依次访问顶点V的各个未被访问过的邻接 点,将V的全部邻接点都访问到;

3分别从这些邻接点出发,依次访问它们的未被访问过的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直到图中所有已被访问过的顶 点的邻接点都被访问到。

依此类推,直到图中所有顶点都被访问完为止 

广度优先搜索在搜索访问一层时,需要记住已被访问的顶点,以便在访问下层顶点时,从已被访问的顶点出发搜索访问其邻接点。所以在广度优先搜索中需要设置一个队列Queue,使已被访问的顶点顺序由队尾进入队列。在搜索访问下层顶点时,先从队首取出一个已被访问的上层顶点,再从该顶点出发搜索访问它的各个邻接点。

如下图(c)中为对图(a)的遍历:

10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地

按照广度优先算法,其遍历顺序为:

10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地

3、  广度优先搜索算法的C语言描述

10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地10、广度优先搜索,图的遍历 - 墨涵 - 墨涵天地

 

4、  广度优先搜索算法的C语言实现

   #include "stdio.h"

#define MAX_VERTEX_NUM 20

#include "conio.h"

#include "stdlib.h"

 

typedef char VertexType;

//我们依然用邻接表来作图的存储结构

typedef struct ArcNode{

       int adjvex;

       struct ArcNode *nextarc;

       int info;

}ArcNode;  //表结点类型

 

typedef struct VNode{

       VertexType data;

       ArcNode *firstarc;

}VNode,AdjList[MAX_VERTEX_NUM]; //头结点

 

typedef struct{

       AdjList vertices;  //邻接表

       int vexnum,arcnum;

}ALGraph;

 

typedef struct Qnode{       //链队结点的类型

    int data;

    struct Qnode *next;

}Qnode,*QueuePtr;

 

typedef struct

{         //链队指针类型

   QueuePtr front;

   QueuePtr rear;

}LinkQueue;

 

int visited[MAX_VERTEX_NUM];

 

int LocateVex(ALGraph G,char u)

    {

       int i;

       for (i=0;i<G.vexnum;i++)

           { if(u==G.vertices[i].data) return i; }

       if (i==G.vexnum) {printf("Error u!\n");exit(1);}

       return 0;

    }

 

void InitQueue(LinkQueue &Q)

{

  Q.front=Q.rear=(QueuePtr)malloc(sizeof(Qnode));

  if(!Q.front) exit(1); //存储分配失败

  Q.front->next=NULL;

 }

 

void EnQueue(LinkQueue &Q,int e)

{ QueuePtr p;

  p=(QueuePtr)malloc(sizeof(Qnode));

  p->data=e;

  p->next=NULL;

  Q.rear->next=p;

  Q.rear=p;

}

 

int QueueEmpty(LinkQueue &Q)

{

       return(Q.front==Q.rear? 1:0);

}

 

void DeQueue(LinkQueue &Q,int &e)

{ QueuePtr p;

  if(QueueEmpty(Q))

  {

    printf("\n Queue is free!");

    exit(1);

  }//if

  p=Q.front->next;

  e=p->data;

  Q.front->next=p->next;

  if(Q.front->next==NULL) Q.rear=Q.front;

  free(p);

 }

 

 

void CreateALGraph_adjlist(ALGraph &G)

    {    

       int i,j,k,w; 

       char v1,v2,enter;

       ArcNode *p;

       printf("Input vexnum & arcnum:\n");

       scanf("%d",&G.vexnum);

       scanf("%d",&G.arcnum);

       printf("Input Vertices(以回车隔开各个数据):\n");

       for (i=0;i<G.vexnum;i++)

              {     scanf("%c%c",&enter,&G.vertices[i].data);//注意点解说

                     G.vertices[i].firstarc=NULL;

              }//for

      

printf("Input Arcs(v1,v2,w)以回车分开各个数据:\n");

   for (k=0;k<G.arcnum;k++)

       {

              scanf("%c%c",&enter,&v1);

              scanf("%c%c",&enter,&v2);

              //scanf("%d",&w);

              i=LocateVex(G,v1);

              j=LocateVex(G,v2);

              p=(ArcNode*)malloc(sizeof(ArcNode));

              p->adjvex=j;  

              //p->info = w;

              p->nextarc=G.vertices[i].firstarc; //前插法,即每次都插入到头结点的后面

              G.vertices[i].firstarc=p;

              printf("Next\n");

       }//for     

   return;

}//CreateALGraph_adjlist

 

void BFSTraverse(ALGraph &G)

{

LinkQueue Q;

for(int v=0;v<G.vexnum;++v) visited[v]=false;

InitQueue(Q);

for(int v=0;v<G.vexnum;++v)

       if(!visited[v])

       {

       EnQueue(Q,v);

       while(!QueueEmpty(Q))

       {

       int u;      

       DeQueue(Q,u);

       visited[u]=true;

       printf("->%c",G.vertices[u].data);//visit一下

       for(ArcNode *w=G.vertices[u].firstarc;w;w=w->nextarc)

              if(!visited[w->adjvex]) EnQueue(Q,w->adjvex);

       }//while

       }//if

}//BFSTraverse

 

int main()

{

ALGraph G;

CreateALGraph_adjlist(G);

BFSTraverse(G);

}

5、  广度优先搜索和深度优先搜索

深度优先搜索算法涉及的是堆栈,广度优先搜索涉及的是队列。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
广度优先搜索(BFS)是一种用于的算法,它从一个源节点开始,逐层遍中所有节点,直到找到目标节点或遍完整张。 BFS 的遍方式是从源节点开始,将其加入队列中,然后遍与其相邻的节点,将这些节点加入队列中,接着从队列中取出一个节点作为下一轮的源节点,重复上述步骤,直到队列为空或者找到目标节点为止。 在实现 BFS 时,需要使用一个队列来存储待遍的节点。同时,还需要一个数组来记录每个节点是否已经被遍过。 下面是一个使用 C 语言实现 BFS 遍的示例代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 100 // 最大节点数 typedef struct node { int data; struct node *next; } Node; typedef struct { Node *first; // 邻接表头指针 } Vertex; typedef struct { Vertex vertexes[MAX_VERTEX_NUM]; // 邻接表 int visited[MAX_VERTEX_NUM]; // 记录节点是否已经被遍过 int vertex_num; // 实际节点数 } Graph; typedef struct { int data[MAX_VERTEX_NUM]; // 队列数组 int front, rear; // 队列头部和尾部指针 } Queue; // 初始化队列 void initQueue(Queue *q) { q->front = q->rear = -1; } // 判断队列是否为空 int isQueueEmpty(Queue *q) { return q->front == -1; } // 入队 void enqueue(Queue *q, int data) { if (q->front == -1) { q->front = q->rear = 0; } else { q->rear++; } q->data[q->rear] = data; } // 出队 int dequeue(Queue *q) { int data = q->data[q->front]; if (q->front == q->rear) { q->front = q->rear = -1; } else { q->front++; } return data; } // 添加边 void addEdge(Graph *g, int u, int v) { Node *node = (Node *)malloc(sizeof(Node)); node->data = v; node->next = g->vertexes[u].first; g->vertexes[u].first = node; } // 初始化 void initGraph(Graph *g, int n) { g->vertex_num = n; for (int i = 0; i < n; i++) { g->vertexes[i].first = NULL; g->visited[i] = 0; } } // BFS 遍 void bfs(Graph *g, int s) { Queue q; initQueue(&q); g->visited[s] = 1; printf("%d ", s); enqueue(&q, s); while (!isQueueEmpty(&q)) { int u = dequeue(&q); for (Node *node = g->vertexes[u].first; node != NULL; node = node->next) { int v = node->data; if (!g->visited[v]) { g->visited[v] = 1; printf("%d ", v); enqueue(&q, v); } } } } int main() { Graph g; initGraph(&g, 5); addEdge(&g, 0, 1); addEdge(&g, 0, 2); addEdge(&g, 1, 2); addEdge(&g, 2, 0); addEdge(&g, 2, 3); addEdge(&g, 3, 3); bfs(&g, 2); return 0; } ``` 上述代码中,我们通过邻接表来表示,其中 `vertexes` 数组用于存储每个节点的邻接表,`visited` 数组用于记录每个节点是否已经被遍过。在 `bfs` 函数中,我们使用队列来存储待遍的节点,首先将源节点入队,并标记为已访问。然后,我们从队列中取出一个节点,并遍与其相邻的节点,将未访问过的节点入队,并标记为已访问。重复这个过程,直到队列为空为止。在遍每个节点时,我们还会输出其数据,以便观察遍顺序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值