Loading...

DS博客作业04——图

0.PTA得分截图

1.本周学习总结

图存储结构

邻接矩阵

  • 简单来讲使用二维数组进行存储,设位edge[M][N]。其中,M,N代表两个顶点,edge[M][N]可代表是否连通或者权值。
    邻接矩阵的特点:

  • 若图为无向图,则矩阵是沿对角线是对称的。
    可以直接访问顶点M,N间边的关系以及权值。
    缺点:

  • 存储的图为稀疏图时,浪费的空间较多,n个顶点所需空间至少为n^2。
    结构体定义

typedef struct //图的定义
{ int edges[MAXV][MAXV]; //邻接矩阵
int n,e; //顶点数,边数
} MGraph;

  • 邻接表
    采用结构体数组跟链表结合,存储每个顶点的临边
    特点:

  • 存储的图为无向图时,遍历顶点数组每个临边即可遍历整张图
    相比于邻接矩阵更节省空间
    缺点

  • 无法直接知道任一两个顶点之间的关系。
    存储的图为有向图时,同一条边会生成两条链。

定义如下

typedef struct ANode
{  
    int adjvex;			//该边的终点编号
    struct ANode *nextarc;	//指向下一条边的指针
    int info;	                //该边的相关信息,如权重
} ArcNode;			//边表节点类型
typedef int Vertex;
typedef struct Vnode
{  
    Vertex data;		//顶点信息
    ArcNode *firstarc;		//指向第一条边
} VNode;			//邻接表头节点类型
typedef VNode AdjList[MAXV];    //头结点数组
typedef struct 
{  
    AdjList adjlist;	        //邻接表
    int n,e;		        //图中顶点数n和边数e
} AdjGraph;	

图遍历及应用

  • 首先要了解图遍历,就要先清楚:什么是图遍历
    从给定的图中任意一个顶点开始,按照某种搜索方法(DFS、BFS)沿着图的边访问图中的所有顶点,并且要注意,每个顶点只能被访问一次,,这个过程就叫做图遍历。
  • 图的遍历相对于树的遍历来说更加复杂,因为对于树来说,从树的根部到树中任意几点只有唯一的一条路径,但是,对于图来说,从图的初始点到图的任意一个顶点,大概率都会存在多条路径,即当沿着图中的一条路径访问过某一顶点后,还可能会沿着另一条路径回到初始顶点,也就是我们说的回路。所以为了避免同一个顶点被访问多次,就引入了一个访问标记数组visited,若顶点被访问过则将visited的值置为1,否则置为0.

深度优先遍历

  • 深度优先遍历的过程是从图中的某个点v出发,然后选择一个与顶点v相邻且没有被访问过的顶点w,然后再以w为顶点,重复上述操作,直到所有顶点都被访问为止。(采用递归的方法)
int visited[MAX]={0};

//全局数组

void DFS(AdjGraph * G,int v)

//深度优先遍历算法

ArcNode * p;

visited[v]=1;

//置已访问标记

printf("%d ",v);

//输出被访问顶点的编号

p=G-> adjlist[v]. firstarc;

//p指向顶点v的第一个邻接点

while (p!= NULL)

{ if (visited[p-> adjvex]==0) //若p-> adjvex顶点未被访问, 递归访问它

DFS(G,p-> adjvex);

P=P- > nextarc;

//p指向顶点v的下一个邻接点

}

广度优先遍历

广度优先遍历和深度优先遍历稍有不同,广度优先遍历的过程是首先访问初始点v,接着访问v的所有未被访问过的邻接点,v1,v2,v3....,访问完毕后再按照v1,v2,v3...,的顺序访问所有顶点每一个未被访问过的邻接点,以此类推,直到图中所有顶点都被访问过一次为止。

void BFS( AdjGraph*G, int v)

int w, i;ArcNode*p;

//定义环形队列指针

SqQueue*qu;

InitQueue(qu);

//初始化队列

int visited[MAXV];

//定义顶点访问标记数组

for (i=0;i<G-> n;i++) visited[i]=0;

//访问标记数组初始化

printf("%2d",v);

//输出被访问顶点的编号

visited[v]=1;

//置已访问标记

enQueue(qu, v);

while (!QueueEmpty(qu))

//队不空循环

{ deQueue(qu, w);

//出队一个顶点w

非连通图

对于无向图来说,若是连通图,则一次遍历就能访问到所有的节点,但是如果无向图是非连通图,则只能访问到初始点所在的连通分量中的所有顶点,其他连通分量中的顶点是不能访问到的,所有要再次从其他的连通分量中寻找初始点再次进行遍历,这样才能访问到图中的所有顶点
采用深度优先遍历非连通图无向图的算法如下:

DFS1(AdjGraph * G)

int i;

for (i=0;i<G-> n;i++ )

if (visited[i]==0) DFS(G,i);

采用广度优先遍历非连通图无向图的算法如下:

BFSI(AdjGraph *G)

int 1;

for (i=0;i<G-> n;i十十)

if (visitedli」==0) BFS(G,i);

判断无向图是否连通

bool Connect(AdjGraph *G)

//判断无向图G的连通性

(int i;

bool flag= true;

for (i=0;i<G->n;i++)

//visited数组置初值

visited[i]=0;

DFS(G, 0);

//调用前面的中DSF算法,从顶点0开始深度优先遍历

for (i=0;i<G-> n;i十十)if (visited[i]==0)

//若有顶点没有被访问到,说明是不连通的

flag= false;

break;

return flag;

查找顶点间是否存在简单路径

即再深度遍历的基础上增加两个形参,其中一个判断两顶点间是否有路径,若有则返回true

void ExistPath( AdjGraph *G, int u,int v,bool &.has){ //has表示u到v是否有路径,初值为false

int w; ArcNode * p;

visited[u]=1;

//置已访问标记

if (u==v)

//找到了一条路径

has= true;

//置has为true并返回

return ;

p=G- -> adjlist[u]. firstarc;

//p指向顶点u的第一个邻接点

while (p!= NULL)

w=p- > adjvex;

//w为顶点u的邻接点

if (visited[w]==0)

//若w顶点未访问,递归访问它

ExistPath(G, w,v, has);

P=p- > nextarc;

//p指向顶点u的下一个邻接点

}

输出一条两顶点之间的简单路径

void FindaPath(AdjiGraph *G,intu,int v,intpathC],int dy(//d表示path中的路径长度,初始为-1

int w,i;ArcNode* p;

visited[u]= 1;

d++; path[d]=u;

//路径长度d增1.顶点0加人到路径中

if (u==v)

( for (i=0;i<=d;i++)

//找到一条路径后输出并返回

printf("%d ",path[i);

printf("\n");

return ;

p=G - > adjlist[u]. firstarc;

//p指向顶点u的第一个邻接点

while (p!= NULL)

{w=p - -> adjvex;

//邻接点的编号为w

if (visited[w]==0)

FindaPath( G, w, V, path,d);p=p - > nextarc;

//p指向顶点u的下一个邻接点

}

寻找两顶点间的最短路径

  • 即求距离顶点u到顶点v的边数最少的顶点序列。利用广度优先遍历算法,从u出发一层一层的向外拓展
    结构体定义如下:
typedef struct{int data;

//顶点编号

1nt parent;

//前一个顶点的位置

} QUERE;

//非环形队列类型
void FindaPath AdjGraph* G, int

( //d表示 path中的路径长度,u,int v,intpathC].int d

int w,i;ArcNode *P;

初始为一1

visited[u]=1;

d++; path[d]=u;

/路径长度d增1.顶点0加人河路径中

if (u==v)

{ for (i=0;i<=d:i+H //找到一 条路径后输 出并返回

printf("%d”.,path[i]);

printf("\n");

return;

}

p=G -> adjlist[u] . firstare;

//p指向顶点u的第一个邻接点

while (p!= NULL)

w=p- > adjvex;

//邻接点的编号为w

if (visited[w]==0)

FindaPath( G, w, v, path,d);

p=p- > nextarc;

//p指向顶点u的下一个邻接点

}

}
while (p!= NULL)

{ if (visited[p-> adjvex]==0)

{visited[p-> adjvex]=1;

rear++ ;

//将w的未访问过的邻接点进队

qu[ rear].data=p- > adjvex;

qu[ rear」. parent= front;

p=P一> nextarc;

//找w的下一个邻接点

最小生成树

  • 生成树:一个连通图的生成树是一个极小

图存储结构

最小生成树相关算法及应用
最短路径相关算法及应用,可适当拓展最短路径算法
拓扑排序、关键路径
上面要求是必须完成,但是完成时候需要根据实际所学再展开。内容简单应付,0分。注意每个知识点务必要举例,图形等说明。

这块内容是总结复习,所有操作、代码清自己写代码或伪代码演示,不得复制课件代码或PPT

1.2.谈谈你对图的认识及学习体会。
本块内容必须用自己语言总结所学及图的相关应用。

2.阅读代码(0--5分)
找3份优秀代码,理解代码功能,并讲出你所选代码优点及可以学习地方。主要找以下类型代码:

考研题
PAT\天梯赛题目
ACM题解
leecode--图1
leecode--图2
题目集可能有和图无关题目,但是阅读代码必须选择和图相关题目
注意:不能选教师布置在PTA的题目。完成内容如下。

2.1 题目及解题代码
可截图,或复制代码,需要用代码符号渲染。题目截图后一定要清晰。

2.1.1 该题的设计思路
链表题目,请用图形方式展示解决方法。同时分析该题的算法时间复杂度和空间复杂度。

2.1.2 该题的伪代码
文字+代码简要介绍本题思路

2.1.3 运行结果
网上题解给的答案不一定能跑,请把代码复制自己运行完成,并截图。

2.1.4分析该题目解题优势及难点

posted @ 2020-05-05 22:14  孤海  阅读(204)  评论(0编辑  收藏  举报