图的遍历
图的深度优先遍历
图的深度优先遍历主要分为递归和非递归两种方式
遍历的方式与书的先序遍历类似
1.递归的方式
bool visited[MAX_VERTEX_NUM]; //辅助函数
void DFSTraverse(Graph G){ //对图进行深度优遍历
for(int v=0; v<G.vexnum ; v++)
visited[v] = false; //初始化辅助函数为0 or false
for(int v=0; v<G.vexnum ; v++) //开始进行深度遍历
if(!visited[v])
DFS(G,v);
}
void DFS(Graph G,int v){ //从顶点v出发进行深度遍历
visit(v); //访问v顶点
visited[v] = true; //设置标记已访问
for(auto w = FirstNeighbor(G,v); w>=0 ; w = NextNeighbor(G,v,w))
if(!visited[w]) //w为u的尚未访问的邻接顶点
DFS(G,w);
}
2.非递归的方式
bool visited[MAX_VERTEX_NUM]; //辅助数组
void DFSTraverse(Graph G){ //图的深度遍历(非递归)
for(int v=0;v<G.vexnum;v++) visited[v] = false; //初始化辅助数组
for(int v=0;v<G.vexnum;v++) //进行访问
if(!visited[v])
DFS(G,v);
}
void DFS(Graph G,int v){ //非递归方式进行访问
Stack s;
InitStack(s);
posh(s,v);
visited[v] = true;
while(!Empty(s)){
int w = pop(s);
visit(w);
for(int k = FirstNeighbor(G,w); k >= 0 ; k=NextNeighbor(G,w,k))
if(!visited[k]){
posh(s,k);
visited[k] = true;
}
}
}
图的广度优先遍历
类似于树的层次遍历
需要构建队列进行辅助,达到广度优先遍历
bool visited[MAX_VERTEX_NUM]; //访问标记数组
Queue Q;
InitQueue(Q);
void BFSTraverse(Graph G){
for (int i = 0; i<G.vexnum ; i++)
visited[i] = false;
for (int i = 0; i<G.vexnum ; i++)
if(!visited[i])
BFS(G,i);
}
void BFS(Graph G,int v){
visited[v] = true;
Enqueue(Q,v);
while(!isEmpty(Q)){
int k = Dequeue(Q);
visit(G,k);
for(int w = FirstNeighbor(G,k);w>=0;w = NextNeighbor(G,k,m))
if(!visited[w]){
visited[w] = true;
Enqueue(Q,w)
}
}
}
拓扑排序
构造AOV网的拓扑序列的操作
在此主要分详细与简华Topo两种
详细Topo:
int Topo(const AdjGraph &G){
stack<int> S;
InitStack(S);
int indegree[G.vexnum] = {0};
arcNode *p;
for(int i=0;i<G.vexnum;i++){
p = G.adjlist[i].firstArc;
while(p){
indegree[p->adj]++;
p = p->nextarc;
}
}
for(int i=0;i<G.vexnum;i++)
if(indegree[i]==0) S.push(i);
int count = 0;
int u;
while(!isEmpty(S)){
u = S.pop();
visit(u);
count++;
p = G.adjlist[u].firstArc;
while(p){
indegree[p->adj]--;
if(indegree[p->adj]==0) S.push(p->adj);
p=p->nextarc;
}
}
if(count < G.vexnum) return 0; //有回路
else return 1; //无回路
}
简约Topo:
bool TopologicalSort(Graph G){
InitStack(S);
for(int i = 0;i<Graph.vexnum;i++){
if(indegree[i]==0)
push(S,i);
}
int count = 0;
while(i(sEmpty(S)){
Pop(S,i);
visit(G,i);
count++;
for(p = G.vexlist[i].firstArc;p;p->nextarc){
v = p->adjvex;
if(!(--indegree[v]))
Push(S,v);
}
}
if(count<G.vexnum) return false; //排序失败
else return true; //排序成功
}
关键路径
求一个AOE的关键路径主要分以下几个步骤:
第一步:求每个顶点(事件)V的最早开始时间ve; 计算公式为:ve(i) = MAX{ ve(j)+weight<j,i> }
第二步:求每个顶点(事件)V的最晚开始时间vl; 计算公式为:vl(j) = MIN{ vl(i)-weight<j,i> }
第三步:求每个边(活动)的最早开始时间; 计算公式为:e(a<j,i>) = ve(j)
第四步:求每个边(活动)的最早结束时间; 计算公式为:l(a<j,i>) = vl(i)-weight<j,i>
第五步:求每个边(活动)的时间余量; 计算公式为:l(i)-e(i)
基本描述代码如下:
p=Status CriticalPath(AdjGraph G){
if(!TopologicalSort(G)) return false; //如果有环图则返回false,没有关键路径
for(int i=0; i<G.vexnum; i++){
ve[i] = 0;
}
//求每个事件的最早开始时间
for(int i=0; i<G.vexnum; i++){
int k = Topo[i];
AdjNode *p = G.vexlist[k].firstArc;
while(!p){
if(ve[i]+p->weight > ve[p->vex])
ve[p->vex] = ve[i]+p->weight;
p = p->nextarc;
}
}
//求每个事件的最晚开始时间
for(int i=0; i<G.vexnum; i++){
vl[i] = ve[G.vexnum-1];
}
for(int i=G.vexnum ;i>=0;i--){
int k = Topo[i];
AdjNode *p = G.vexlist[k].firstArc;
while(!p){
if(vl[p->vex]-p->weight < vl[i])
vl[i] = vl[p->vex] - p->weight;
p = p->nextarc;
}
}
//求关键路径
for(int i=0; i<G.vexnum ; i++){
AdjNode *p = G.vexlist[i].adjarc;
while(!p){
int e = ve[i];
int l = vl[p->vex] - p->weight;
if(e==l){
printf("<%,%>\n",i,p->vex);
}
p = p->nextarc;
}
}
}