廣度優先搜尋,圖的遍歷
1、 佇列
(1) 定義
佇列也是一種運算受限的線性表。在這種線性表上,插入限定在表的某一端進行,刪除限定在表的另一端進行。允許插入的一端稱為隊尾,允許刪除的一端稱為隊頭。
特點:佇列中資料元素的入隊和出隊過程是按照“先進先出” 的原則進行的。因此,佇列又稱為“先進先出”的線性表,簡稱FIFO表。
(2)
佇列的鏈式儲存結構簡稱為鏈隊。它實際上是一個同時帶有首指標和尾指標的單鏈表。頭指標指向表頭結點,而尾指標則指向隊尾元素。從隊尾插入,從隊首刪除。空的鏈隊對列的判決條件是頭指標和尾指標均指向頭結點。
鏈隊運算指標變化情況:
2、 廣度優先搜尋的演算法思想
廣度優先搜尋遍歷類似於樹的按層次遍歷。
對於無向連通圖,廣度優先搜尋是從圖的某個頂點v0出發,在訪問v0之後,依次搜尋訪問v0的各個未被訪問過的鄰接點w1,w2,…。然後順序搜尋訪問w1的各未被訪問過的鄰接點,w2的各未被訪問過的鄰接點,…。即從
廣度優先搜尋的順序不是唯一的。
具體描述如下:
設圖G的初態是所有頂點均未訪問,在G 中任選一頂點i作為初始點,則廣度優先搜尋的基本思想是:
(1)從圖中的某個頂點V出發,訪問之;並將其訪問標誌置為已被訪問,即visited[i]=1;
(2)依次訪問頂點V的各個未被訪問過的鄰接 點,將V的全部鄰接點都訪問到;
(3)分別從這些鄰接點出發,依次訪問它們的未被訪問過的鄰接點,並使“先被訪問的頂點的鄰接點”先於“後被訪問的頂點的鄰接點”被訪問,直到圖中所有已被訪問過的頂
依此類推,直到圖中所有頂點都被訪問完為止 。
廣度優先搜尋在搜尋訪問一層時,需要記住已被訪問的頂點,以便在訪問下層頂點時,從已被訪問的頂點出發搜尋訪問其鄰接點。所以在廣度優先搜尋中需要設定一個佇列Queue,使已被訪問的頂點順序由隊尾進入佇列。在搜尋訪問下層頂點時,先從隊首取出一個已被訪問的上層頂點,再從該頂點出發搜尋訪問它的各個鄰接點。
如下圖(c)中為對圖(a)的遍歷:
按照廣度優先演算法,其遍歷順序為:
3、 廣度優先搜尋演算法的C語言描述
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、 廣度優先搜尋和深度優先搜尋
深度優先搜尋演算法涉及的是堆疊,廣度優先搜尋涉及的是佇列。