图->遍历

时间:2023-03-09 00:19:18
图->遍历

文字描述

  从图中某一顶点出发遍历图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫图的遍历。

  深度优先搜索:类似树的先根遍历;假设初始状态下,图中所有顶点都未曾被访问,则从某个顶点出发,访问此顶点,然后依次从v的未被访问的邻接点出发继续深度优先遍历图,直到图中所有和v有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选一个未曾被访问的顶点作起始点。

  广度优先搜索:类似数的层次遍历;以v为起始点,由近及远,依次访问和v有路径相通且路径长度为1,2,…的顶点。

示意图

图->遍历

图->遍历

算法分析

  深度优先搜索:遍历图的过程实质上是对每个顶点找其邻接点的过程。其耗费的时间取决于所采用的存储结构。当用二维数组表示邻接矩阵作图的存储结构时,查找每个顶点的邻接点所需时间为n*n, 其中n为图中顶点数。而当以邻接表作图的存储结构时,找邻接点所需时间为e,其中e为无向图中的边数或有向图中弧的数。由此,当以邻接表作存储结构时,深度优先搜索遍历图的时间复杂度为n+e。

  广度优先搜索:其时间复杂度和深度优先遍历相同,两者不同之处在于对顶点的访问顺序不同。

代码实现

 /*
1.以邻接表作为图的存储结构创建图。
2.用深度优先搜索的方法对图中结点进行遍历
3.用广度优先搜索的方法对图中结点进行遍历
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h> #define INFINITY 100000 //最大值
#define MAX_VERTEX_NUM 20 //最大顶点数
#define None -1
typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网}
typedef char VertexType;
typedef struct{
char note[];
}InfoType;
//与顶点相连的弧结点
typedef struct ArcNode{
int adjvex; //该弧所指向的顶点的位置
struct ArcNode *nextarc; //指向下一条弧的指针
InfoType *info; //该弧相关信息的指针
}ArcNode;
//顶点结点
typedef struct VNode{
VertexType data;//顶点信息
ArcNode *firstarc;//指向第一条依附该顶点的弧的指针
}VNode, AdjList[MAX_VERTEX_NUM];
//图结点
typedef struct{
AdjList vertices;
int vexnum;//图的顶点数
int arcnum;//图的弧数
int kind; //图的种类标志
}ALGraph; /*
若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。
*/
int LocateVex(ALGraph G, VertexType v)
{
int i = ;
for(i=; i<G.vexnum; i++){
if(G.vertices[i].data == v){
return i;
}
}
return -;
} /*
在链表L的头部前插入v
*/
int InsFirst(ArcNode *L, int v)
{
ArcNode *n = (ArcNode *)malloc(sizeof(struct ArcNode));
n->adjvex = v;
n->nextarc = L->nextarc;
L->nextarc = n;
return ;
} /*
采用邻接表的存储结构,构造无向图
*/
int CreateUDG(ALGraph *G)
{
int i = , j = , k = , IncInfo = ;
int v1 = , v2 = ;
char tmp[] = {}; printf("输入顶点数,弧数,其他信息标志位: ");
scanf("%d,%d,%d", &G->vexnum, &G->arcnum, &IncInfo); for(i=; i<G->vexnum; i++){
printf("输入第%d个顶点: ", i+);
memset(tmp, , sizeof(tmp));
scanf("%s", tmp);
G->vertices[i].data = tmp[];
G->vertices[i].firstarc = malloc(sizeof(struct ArcNode));
G->vertices[i].firstarc->adjvex = None;
G->vertices[i].firstarc->nextarc = NULL;
} for(k=; k<G->arcnum; k++){
printf("输入第%d条弧(顶点1, 顶点2): ", k+);
memset(tmp, , sizeof(tmp));
scanf("%s", tmp);
sscanf(tmp, "%c,%c", &v1, &v2);
i = LocateVex(*G, v1);
j = LocateVex(*G, v2);
InsFirst(G->vertices[i].firstarc, j);
InsFirst(G->vertices[j].firstarc, i);
if(IncInfo){
//other info on arc
}
}
return ;
} /*
采用邻接表的存储结构,构造图
*/
int CreateGraph(ALGraph *G)
{
printf("输入图类型: -有向图(0), -有向网(1), +无向图(2), -无向网(3): ");
scanf("%d", &G->kind);
switch(G->kind){
case DG:
case DN:
case UDN:
printf("还不支持!\n");
return -;
case UDG:
return CreateUDG(G);
default:
return -;
}
} /*
输出图的信息
*/
void printG(ALGraph G)
{
if(G.kind == DG){
printf("类型:有向图;顶点数 %d, 弧数 %d\n", G.vexnum, G.arcnum);
}else if(G.kind == DN){
printf("类型:有向网;顶点数 %d, 弧数 %d\n", G.vexnum, G.arcnum);
}else if(G.kind == UDG){
printf("类型:无向图;顶点数 %d, 弧数 %d\n", G.vexnum, G.arcnum);
}else if(G.kind == UDN){
printf("类型:无向网;顶点数 %d, 弧数 %d\n", G.vexnum, G.arcnum);
}
int i = ;
ArcNode *p = NULL;
for(i=; i<G.vexnum; i++){
printf("%c\t", G.vertices[i].data);
p = G.vertices[i].firstarc;
while(p){
if(p->adjvex != None)
printf("%d\t", p->adjvex);
p = p->nextarc;
}
printf("\n");
}
return;
} //////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//开始用深度优先搜索的方法对图中结点进行遍历
int Visited[MAX_VERTEX_NUM] = {};//访问标志数组
void (*VisitFun)(ALGraph G, int v);//函数变量 //打印顶点中位置v的顶点信息
void printfun(ALGraph G, int v){
printf("[%d]:%c\t", v, G.vertices[v].data);
} //返回图G中与顶点位置为v的顶点相连的第一个结点在顶点中的位置
int FirstAdjVex(ALGraph G, int v)
{
return G.vertices[v].firstarc->nextarc->adjvex;
} //返回图G中与顶点位置为v的顶点相连的结点w的下一个结点在顶点中的位置
int NextAdjVex(ALGraph G, int v, int w)
{
ArcNode *arc = G.vertices[v].firstarc;
while(arc && arc->adjvex != w){
arc = arc->nextarc;
}
if(arc && arc->nextarc){
return arc->nextarc->adjvex;
}
return -;
} //从第v个顶点出发递归地深度优先遍历图G
void DFS(ALGraph G, int v){
//访问第v个顶点
Visited[v] = ;
VisitFun(G, v);
int w = ;
for(w=FirstAdjVex(G,v); w>=; w=NextAdjVex(G,v,w)){
//对v的尚未访问的邻接顶点w递归调用DFS
if(!Visited[w]){
DFS(G,w);
}
}
} //对图G作深度优先遍历
void DFSTraverse(ALGraph G, void (*Visit)(ALGraph G, int v))
{
printf("深度优先搜索: ");
//使用全局变量VisitFun, 是DFS不必设函数指针参数
VisitFun = Visit;
int v = ;
//访问标志数组初始化
for(v=; v<G.vexnum; v++){
Visited[v] = ;
}
for(v=; v<G.vexnum; v++){
//对尚未访问的顶点调用DFS
if(!Visited[v])
DFS(G, v);
}
} //////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//开始用广度优先搜索的方法对图中结点进行遍历
typedef struct QNode{
int data;
struct QNode *next;
}QNode, *QuenePtr; typedef struct{
QuenePtr front;
QuenePtr rear;
}LinkQueue;
LinkQueue *InitQueue(void){
LinkQueue *Q = (LinkQueue*)malloc(sizeof(LinkQueue));
Q->front = Q->rear = (QuenePtr)malloc(sizeof(QNode));
Q->front->next = Q->rear->next = NULL;
return Q;
}
int QueueEmpty(LinkQueue *Q){
if(Q->front == Q->rear){
return ;
}else{
return -;
}
}
int EnQueue(LinkQueue *Q, int e){
QuenePtr p = (QuenePtr)malloc(sizeof(QNode));
p->data = e;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
return ;
} int DeQueue(LinkQueue *Q, int *e)
{
if(Q->rear == Q->front){
return -;
}
QuenePtr p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
if(p == Q->rear){
Q->rear = Q->front;
}
free(p);
return ;
} void PrintQ(LinkQueue *Q)
{
QuenePtr head = Q->front;
while(head){
printf("%d\t", head->data);
head = head->next;
}
printf("\n");
} /*广度优先搜索
*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组Visited
*/
void BFSTraverse(ALGraph G, void (*Visit)(ALGraph G, int v))
{
printf("广度优先搜索: ");
int v = ;
int u = ;
int w = ;
//访问标志数组初始化
for(v=; v<G.vexnum; v++){
Visited[v] = ;
}
//置空的辅助队列Q
LinkQueue *Q = InitQueue();
for(v=; v<G.vexnum; v++){
if(!Visited[v]){
//v尚未访问
Visited[v] = ;
//访问v顶点
Visit(G, v);
//v入队列
EnQueue(Q, v); while(QueueEmpty(Q)){
//队头元素出队并置为u
DeQueue(Q, &u);
for(w=FirstAdjVex(G, u); w>=; w=NextAdjVex(G, u, w)){
if(!Visited[w]){
//w为u的尚未访问的邻接顶点
Visited[w] = ;
Visit(G, w);
EnQueue(Q, w);
}
}
}
}
}
} int main(int argc, char *argv[])
{
ALGraph G;
if(CreateGraph(&G) > -){
printG(G);
}
DFSTraverse(G, printfun);printf("\n");
BFSTraverse(G, printfun);printf("\n");
return ;
}

图深度优先遍历和广度优先遍历

代码运行

图->遍历