严蔚敏视频 笔记27
遍历应用举例
1.求一条从顶点i到顶点s的简单路径
void DFSearch(int v,int s,char *PATH) {
visited[v]=TRUE; // 访问第v个结点
Append(PATH,getVertex(v));
for(w=FirstAdjVex(v);w!=0&&!found;w=NextAdjVex(v)) {
if(w==s) {found=TRUE; Append(PATH,w);}
else if(!visited[w]) DFSearch(w,LP);
}
if(!found) Delete(PATH);
}
2.求两个顶点之间的一条路径长度最短的路径
“双链”结点:next、priou
修改入队列操作,插入新的队尾结点时令其priou域的指针指向刚刚出队列的结点
修改出队列操作,出队列时仅移动队头指针而不将队头结点从链表中删除
typedef DuLinkList QueuePtr;
void InitQueue(LinkQueue& Q) {
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
Q.front->next=Q.rear->next=NULL;
}
void EnQueue(LinkQueue& Q,QElemType e) {
p=(QueuePtr)malloc(sizeof(QNode));
p->data=e; p->next=NULL;
p->priou=Q.front;
Q.rear->next=p;
Q.rear=p;
}
void DeQueue(LinkQueue& Q,QElemType &e) {
Q.front=Q.front->next;
e=Q.front->data;
}
7.4 最小生成树
构造网的一棵最小生成树:在e条带权的边中选取n-1条(不构成回路),使“权值之和”最小
算法一:(普里姆算法)
取图中任意一个顶点v作为生成树的根,之后若要往生成树上添加顶点w,则在顶点v和顶点w之间必定存在一条边,并且该边的权值在所有连通顶点v和w之间的边中取值最小
假设n个顶点分成两个集合:U(包含已落在生成树上的顶点)和V-U(尚未落在生成树上的顶点),则在所有连通U中顶点和V-U中顶点的边中选取权值最小的边
void MiniSpanTree_PRIM(MGraph G,VertexType u) {
// 记录从顶点集U到V-U的代价最小的边的辅助数组:
struct {
VertexType adjvex;
VRType lowcost;
} closedge[MAX_VERTEX_NUM];
k=LocateVex(G,u);
for(j=0;j<G.vexnum;++j) // 辅助数组初始化
if(j!=k) closedge[j]={u,G.arcs[k][j].adj};
closedge[k].lowcost=0; // 初始U={u}
for(i=0;i<G.vexnum;++i) { // 在其余顶点中选择
k=minimun(closedge); // 求出T的下一个结点(k)
printf(closedge[k].adjvex,G.vexs[k]);
closedge[k].lowcost=0; // 第k顶点并入U集
for(j=0;j<G.vexnum;++j)
if(G.arcs[k][j].adj<closedge[j].lowcost)
colosedge[j]={G.vexs[k],G.arcs[k][j].adj};
}
}
算法二:(克鲁斯卡尔算法)
先构造一个只含n个顶点的子图SG,然后从权值最小的边开始,若它的添加不使SG中产生回路,则在SG上加上这条边,如此重复,直至加上n-1条边为止
算法:
构造非连通图ST={V,{}}
k=i=0;
while(k<n-1) {
++i;
从边集E中选取第i条权值最小的边(u,v);
若(u,v)加入ST后不使ST中产生回路,
则 输出边(u,v); 且k++;
}
普里姆算法的时间复杂度为O(n^2),适合于稠密图
克鲁斯卡尔算法需对e条边按权值进行排序,时间复杂度为O(eloge),适合于稀疏图
本文深入讲解了图遍历的应用案例,包括求从顶点到另一顶点的简单路径及最短路径的方法。此外,还详细介绍了两种构造最小生成树的经典算法——普里姆算法和克鲁斯卡尔算法,并对比了它们的适用场景和时间复杂度。
2837

被折叠的 条评论
为什么被折叠?



