标签:学习 单源最短路 直接 卡尔 指针 list 自己的 first 变化
第六章我们首先学习了图,知道图是由两个集合V(点)和E(边)组成,也知道了有向图和无向图的区别,同时也学习了用如何用邻接矩阵和领接表来表示图。
邻接矩阵:
方便检查任意一堆顶点间是否存在边,方便找任一顶点的所有“邻接点”,方便计算任一顶点的“度”(从改点出发的边数为出度,指向该点的为入度),但存稀疏图(点很多而边很少)有大量无效元素,会浪费空间。
const int MVNum=100;//最大顶点数
typedef char VerTexType;//假设顶点数据类型为char
typedef int ArcType;//假设边的权值为int
typedef struct{}
VerTexType vexs[MVNum];//顶点表 char
ArcType arcs[MVNum][MVNum];//邻接矩阵 int
int vexnum,arcnum;//图当前的点数和边数
}AMGraph;
基于这个矩阵来建立 无向 带权图:
先输入图的点数和边数,再遍历每个顶点来输入点的信息,然后要先初始化每个边,将它们置于最大值,再遍历每个边,输入它们的权值,这样可以使得没有相连的两个点边的权值为最大值。
领接表:
方便找任一顶点的所以“邻接点”,方便计算任一顶点的度,
无向图:直接读G[i],访问这个链表,求出度
有向图:只能计算出度,要遍历其他顶点的领接点,来方便计算入度
const int MVNum=100;//最大顶点数
typedef char VerTexType;//假设顶点数据类型为char
typedef int ArcType;//假设边的权值为int
邻接点的结构
typedef struct ArcNode{
int adjvex;//该边所指向的顶点的位置, 这个邻接顶点的 下标
sturct ArcNode *nextarc;//指向下一个邻接顶点(也是指向下一个边)的指针
OtherInfo info;//和边相关的信息,例如权值
}ArcNode;
顶点的结构
typedef struct{
VexTexType data;//顶点信息 char
ArcNode *firstarc;//指向第一条依附该顶点的弧 第一个邻接顶点
}VNode,AdjList[MVNUM];//AdjList就是定义数组 ,VNode是单个的名字
图的定义
typedef struct{
AdjList vertices;//邻接表 ,是 一个数组
int vexnum,arcnum;//顶点数和边数
}ALGraph;
基于这个矩阵来建立 无向 带权图:
与邻接矩阵基本一致,不过要将表头的指针域置为Null,且每次新的结点要申请空间,再不断使用头插法即可
还学到了一些一些连通图相关的定义
连通图:每个顶点都连通 连通分量是:最大的连通子集,比如连通图的连通分量就是自己,非连通图的连通分量就是它的最大子集
强连通:有向图中顶点v和w之间存在双向路径 强连通图:有向图中任意两点均强连通 强连通分量:有向图的极大强连通子图
学了图的构造后,就是学习图的遍历,遍历的方法有两种:深度优先搜索和广度优先搜索
深度优先搜索(DFS)
void DFS(Vextex V)
{
visited[v]=true;
for(v的每个邻接点w)
if(!visited[w]) //未被访问,则从它进行深度优先搜索
DFS(w);
}
广度优先搜索(BFS)
要运用队列,与树的层次遍历类似
void BFS(Vextex V)
{
visited[v]=true;
Q.push(v);
while(!Q.empty())
{
v = Q.front();
Q.pop();
for(V的每个邻接点w)
if(!visited[w])
{
visited[w]=true;
Q.push(w);
}
}
}
但对于非连通图,这种方法无法完成遍历,要加入下面的代码,DFS与BFS都是一样的
void DFSTraverse(Graph G)
{
for(v = 0;v<G.vexnum;++v)
visited[v] = FALSE;//初始化visited数组
for(v=0;v<G.vexnum;++v)
if(!visited[v]) DFS(G,v);//对尚未访问的顶点调用DFS
}
但为了实际应用,我们还学了如何求有权图的单源最短路径
Dijkstra算法:令S={源点s + 已经确定了最短路径的顶点v1},对任一未收录的v,定义dist[v]为s到v的最短路径 长度,但该路径仅经过S中的顶点,{s 到 vi属于S 到 v}
也就是先取一点放于一个集合S中,然后再在其他点取一个与它带权路劲最小的点放于S中,再不断循环以上操作,从而求得有权图的单源最短路径
void Dijkstra(Vextex s )
{//自己到自己的权值也是为无穷,不能用0表示,而且这个算法不能解决权值为负的情况
while(1)
{//dist 是权值, path是指向它的点,collocted数组就是表示是否在集合S中
v = 未收录顶点中dist最小者;
if(这样的v不存在) break;
collected[v]=true;
for(v的每个邻接点w)
if(collected[w]=false)
if(dist[v]++E<v,w> <dist[w])
{
dist[w] = dist[v] + E<v,w>;
path[w] = v;
}
}
}
最后学习的是最小生成树:在e条带权边中选n-1条边(不构成回路),使“权值之和”最小 。 一共有两个算法:普里姆算法算法,克鲁斯卡尔算法
普里姆算法算法与Dijkstra算法很类似,都是一个点集合,再不断从其他点选权值最小的点,但难点是要解决权值的变化,随着集合中点的增多,其他点的权值都在变
void MiniSoanTree_P(AMGraph G,VextexType u)
{//从顶点u出发构造网G的最小生成树
k =LocataVex(G,u);
for(j=0;j<G.vexnum;++j)//辅助数组初始化
if(j!=k)
colsedge[j] = {u,G.arcs[k][j].adj};
closedge[k].lowcost = 0;//初始,U={0}
for(i=1;i<G.vexnum;++i)
{
k = Min(closedge[]|closedge[].lowcost>0);//求出加入生成树的下一个顶点k
cout << closedge[k].adjvex << G.vexs[k];//输出生成树上一条边 和 他的编号
closedge[k].lowcost = 0;//第K顶点并入U集
for(j=0;j<G.vexnum;++j)//修改其他顶点的最小边
if(G.arcs[k][j]<closedge[j].lowcost)
colsedge[j]={G.vexs[k],G.arcs[k][j]};
}
}
克鲁斯卡尔算法:不断的选择权值最小的边
标签:学习 单源最短路 直接 卡尔 指针 list 自己的 first 变化
原文地址:https://www.cnblogs.com/himiko/p/13125956.html