一、图的存储结构
(1)邻接矩阵
若保存的图是无权值的图,有边则为1,无边则为0;
若保存的图是网(即带权值),有边的则为对应边上的权值,无边的则是取计算机允许的、大于所有边上权值的数(用INT-MAX表示)
代码如下所示:
#define MVNum 100
typedef char VerTexType;
typedef int ArcType;//由于不知道后续的顶点、权值具体是什么类型,后面均用VexTexType,ArcType表示,便于修改
typedef struct
{
VerTexType vexs[MVNum];
ArcType arcs[MVNum][MvNum];
int vexnum,arcnum;
}AMGraph;
便于计算各个顶点的度,用于稀疏图时极其的浪费空间
(2)邻接表:由两部分组成:表头结点表、边表
表头结点表:以顺序结构的形式存储,包括数据与和链域两部分
边表:表示图中顶点间的关系,包括邻接点域、数据域和链域三部分
代码如下所示:
typedef struct ArcNode
{
int adjvex;//该边所指向的顶点位置
struct ArcNode *nextarc;//指向下一条边的指针
OtherInfo info;
}ArcNode;//边表
typedef struct VNode
{
VerTexType data;
ArcNode *firstarc;//指向第一条依附该顶点的指针
}VNode,AdjList[MVNum];
typedef struct
{
AdjList vertices;//相当于重新取了个名字叫vertices,等价于VNode vertices[MVNum];
int vexnum,arcnum;
}ALGraph;
便于增加和删除结点,但是计算有向图顶点的度时很不方便,适用于稀疏图,且不便于判断顶点之间是否有边
计算有向图顶点的度:顶点的度=该顶点的入度+出度
出度=第i个链表中的结点的个数
入度=在所有链表中,其邻接点域的值为i的结点的个数或者利用逆邻接表用邻接表求出度的方式求入度
二、图的遍历
(1)深度优先遍历(DFS):类似于树的先序遍历,主要应用了递归
bool visited[MVNum];//使用前记得初始化为false
//邻接矩阵表示法
void DFS_AM(AMGraph G,int v)
{
cout << v;
visited[v] = true;
for(w=0;w<vexnum;w++)
{
if(G.arcs[v][w]!=0 && !visited[w]) DFS_AM(G,w);
}
}
邻接表表示法
void DFS_AL(ALGraph G,int v)
{
cout <<v;
visited[v] = true;
p = G.vertices[v].firstarc;
while(p != NULL)
{
w = p->adjvex;
if( !visited[w]) DFS_AL(G,w);
p = p->nextarc;
}
}
(2)广度优先遍历(BFS):类似于树的层次遍历,利用了队列
void BFS(Graph G,int v)
{
cout << v;
visited[v] = true;
queue<int> Q;//自动初始化队列
Q.push(v);
while( !Q.empty() )
{
u = Q.front();//取对头元素
Q.pop();//对头元素出队
for(w = FirstAdjVex(G,u);w>=0;w = NextAdjVex(G,u,w))
{
if( !visited[w])
{
cout << w;
visited[w] = true;
Q.push(w);
}
}
}
}
注:以上两种算法均针对连通图,若想遍历非连通图,只需在最外层套一个循环
如:for(int i=0;i<vexnum;i++)
{
if( ! visited[i]) DFS_AM(G,i);
}
三、图的应用
(1)最小生成树:最小生成树不唯一,掌握普利姆算法(也称“加点法”)和克鲁斯卡尔算法(也称“加边法)
根据老师的直播以及慕课的视频,能够用手动运行的方式写出每一次运行的结果
(2)最短路径(迪杰斯特拉算法)
四、pta作业和实践
实践(解救007)遇到的问题:
1、题意没摸清就开始写代码,做了很多的无用功
2、判断是否能跳到岸边时,漏了判断条件,忘了是坐标,可以为正或负
3、没有巧妙的运用0 1,所有的判断都用了true和false,写起来造成了一定的不方便;且一开始没有很好的掌握全局变量,以至于在写函数的时候,参数总是捉摸不定,而且有很多,还应用了引用
原文:https://www.cnblogs.com/xxqqff/p/13126629.html