文字描述

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

  深度优先搜索:类似树的先根遍历;假设初始状态下,图中所有顶点都未曾被访问,则从某个顶点出发,访问此顶点,然后依次从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 ;
}

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

代码运行

图->遍历的更多相关文章

  1. DS图遍历--深度优先搜索

    DS图遍历--深度优先搜索 题目描述 给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始 注意:图n个顶点编号从0到n-1 代码框架如下: 输入 第一行输入t,表示有t个测试实例 第二行输入n, ...

  2. Gremlin:图遍历语言

    Gremlin简介 Gremlin是Apache TinkerPop 框架下的图遍历语言.Gremlin是一种函数式数据流语言,可以使得用户使用简洁的方式表述复杂的属性图(property graph ...

  3. 一步一步学数据结构之n--n(图遍历--深度优先遍历--非递归实现)

    前面已经说了图的深度优先遍历算法,是用递归实现的,而在这里就讲一下用非递归实现,需要借助栈: 算法思想:        1. 栈初始化        2. 输出起始顶点,起始顶点改为“已访问”标志,将 ...

  4. PAT A1134 Vertex Cover (25 分)——图遍历

    A vertex cover of a graph is a set of vertices such that each edge of the graph is incident to at le ...

  5. PAT A1034 Head of a Gang (30 分)——图遍历DFS,字符串和数字的对应保存

    One way that the police finds the head of a gang is to check people's phone calls. If there is a pho ...

  6. PAT A1013 Battle Over Cities (25 分)——图遍历,联通块个数

    It is vitally important to have all the cities connected by highways in a war. If a city is occupied ...

  7. 算法学习笔记(六) 二叉树和图遍历—深搜 DFS 与广搜 BFS

    图的深搜与广搜 复习下二叉树.图的深搜与广搜. 从图的遍历说起.图的遍历方法有两种:深度优先遍历(Depth First Search), 广度优先遍历(Breadth First Search),其 ...

  8. ent 基本使用十五 一个图遍历的例子

    以下是来自官方的一个user group pet 的查询demo 参考关系图 环境准备 docker-compose mysql 环境 version: "3" services: ...

  9. DS图遍历--广度优先搜索

    题目描述 代码框架如下: 输入 第一行输入t,表示有t个测试实例 第二行输入n,表示第1个图有n个结点 第三行起,每行输入邻接矩阵的一行,以此类推输入n行 第i个结点与其他结点如果相连则为1,无连接则 ...

随机推荐

  1. 超简单Windows安装Scrapy (仅需一步)

    网上很多关于windows安装Scrapy的教程都非常的繁琐,请看我给大家分享的教程,非常简单 一步完成. 超简单的安装方法: 下载地址: https://www.continuum.io/downl ...

  2. duilib进阶教程 -- TreeView控件的bug (9)

    一.不自动调整子控件的宽度(TreeView宽度小于260时) 相信亲们用同样的代码,显示效果肯定和Alberl不一样吧~O(∩_∩)O~ 嘿嘿,仔细对比下,看看你们的列表头背景图片是下面这样的么? ...

  3. css3整理--background-clip

    background-clip语法: background-clip : border-box || padding-box || content-box 参数取值: border-box:此值为默认 ...

  4. linux Email 体系

    大致了解了DNS与邮件服务器之间的关系后,接下来我们介绍邮件到底是如何传送到目的邮件主机的.下面我们分成“寄信”与“收信”两个主要的邮件服务器使用方式进行介绍.先说明关于“寄信”的部分.通常我们都是使 ...

  5. git 删除仓库的文件

    git移除远程仓库某个文件夹 1.比如src/product/ 文件夹 git rm -r --cached "src/product" //执行命令. 2.提交到本地 git c ...

  6. Arduino基本数据类型

    基本数据类型简介 常见的Arduino是基于ATmega的8位 AVR单片机,例如Arduino UNO ,Arduino Nano,Arduino mega2560等.还有高级点 32位的,如Ard ...

  7. Scriter CSS

    transition: height(quart-out,1.0s,quart-in); transform:rotate(50deg); http://www.terrainformatica.co ...

  8. jQuery学习之二

    jQuery对象获取方法:var $cr=$("#cr"); //jQuery方法获取的是一个·对象数组. var cr=$cr[0] // var cr=$cr.get(0); ...

  9. day_5.14 py 飞机大战Demo

    飞机未完,继续做 2018-5-14 21:05:45 明天继续       循环里面的坑; 删除列表元素后循环了打印的不一样,主要是比如相邻的删除了,33,44 删除33 循环一次后44跑到33位置 ...

  10. H - Painter

    杂货店出售一种由N(3<=N<=12)种不同颜色的颜料,每种一瓶(50ML),组成的颜料套装.你现在需要使用这N种颜料:不但如此,你还需要一定数量的灰色颜料.杂货店从来不出售灰色颜料--也 ...