基于DFS的拓扑排序算法实现

article/2025/10/1 6:43:58

对于有向无环图G中的任意结点u,v,它们之间的关系必然是以下三种之一:

(1)假设结点u是结点v的祖先,则在调用DFS访问u的过程中,必然会在这个过程结束之前递归地对v调用DFS访问,即v的DFS函数结束时间现语u的DFS结束时间。从而可以考虑在DFS调用过程中设定一个时间标记,在DFS调用结束时,对个结点计时。因此,祖先的结束时间大于子孙的结束时间。

(2)若结点u是结点v的子孙,则v为u的祖先,按照上述思路,v的结束时间大于u的结束时间。

(3) 若u和v没有关系,则u和v在拓扑序列中的关系任意。从而按照结束时间从大到小,可以得到一个拓扑序列。

下面给出利用DFS求各节点结束时间的代码。至于拓扑序列,将结束时间从大到小排序即可得到。(实际上和深度优先遍历算法完全相同,只不过加入了时间变量。
假设图和邻接表是以下这样子滴~~~~:
在这里插入图片描述
代码实现如下:

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;#define MAX_VERTEX_NUM 10
typedef char VertexType;int timeBack = 0;//全局变量,记录各顶点的退出时间
int finishTime[MAX_VERTEX_NUM];
typedef struct ArcNode
{int adjvex;//边/弧指向哪个结点struct ArcNode* nextarc;//指向下一条弧的指针
} ArcNode;//边结点
typedef struct VNode
{VertexType data;//顶点信息ArcNode* firstarc;//第一条边/弧
} VNode, AdjList[MAX_VERTEX_NUM];
//邻接表
typedef struct
{AdjList vertices;int vexnum, arcnum;
} ALGraph;
bool visited[MAX_VERTEX_NUM];//标记访问数组//创建邻接表
void CreateAdj(ALGraph*& G, int n)
{int i;G = (ALGraph*)malloc(sizeof(ALGraph));for (i = 0; i < n; i++){G->vertices[i].firstarc = NULL;}//初始化顶点数和边数,根据后面插入的邻接点动态添加边数G->vexnum = n;G->arcnum = 0;
}//将边结点插入到某个顶点表的边表中,默认拓扑排序为有向无环图,这里只考虑有向图,x为起点,y为终点
void InsertAdj(ALGraph* G, int x, int y, int& e)
{//头插法ArcNode* p;//防止非法输入if (x < 0 || x >= MAX_VERTEX_NUM || y < 0 || y >= MAX_VERTEX_NUM){printf("插入失败!!!");}p = (ArcNode*)malloc(sizeof(ArcNode));p->adjvex = y;p->nextarc = G->vertices[x].firstarc;G->vertices[x].firstarc = p;e = ++G->arcnum;
}//输出邻接表
void DispAdj(ALGraph* G)
{int i;ArcNode* p;for (i = 0; i < G->vexnum; i++){p = G->vertices[i].firstarc;printf("%3d号顶点:\t", i);while (p != NULL){printf("%3d->", p->adjvex);p = p->nextarc;}printf("\t空\n");}
}//销毁邻接表
void DestroyAdj(ALGraph*& G)
{int i;ArcNode* pre, * p;for (i = 0; i < G->vexnum; i++)//扫描所有边表{pre = G->vertices[i].firstarc;if (pre != NULL){p = pre->nextarc;while (p != NULL){free(pre);pre = p;p = p->nextarc;}free(pre);}}free(G);
}//求图G中顶点x的第一个邻接点,若有则返回顶点号,若x没有邻接点或图中不存在x,则返回-1
int FirstNeighbor(ALGraph* G, int x)
{ArcNode* p;if (x >= MAX_VERTEX_NUM || x < 0) //限定顶点数值的范围为0~MAX_VERTEX_NUM -1{return -1;}p = G->vertices[x].firstarc;if (p == NULL){return -1;}return p->adjvex;
}//假设图G中顶点y是x的一个邻接点,返回除了y之外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1
int NextNeighbor(ALGraph* G, int x, int y)
{int w;ArcNode* p;p = G->vertices[x].firstarc;while (p != NULL){w = p->adjvex;if (p->nextarc != NULL && (w == y))//说明当前访问的邻接点是y并且有下一个邻接点{return p->nextarc->adjvex;}p = p->nextarc;}//若遍历完但while循环中的语句还没有任何返回,就执行最后的返回return -1;
}
void visit(int v)
{printf("%3d\t", v);
}
void DFS(ALGraph* G, int v)
{visited[v] = true;visit(v);for (int w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){if (!visited[w]) //w为u的尚未访问的邻接结点{DFS(G, w);}//if}//fortimeBack = timeBack + 1;//先退出DFS的函数时间最小finishTime[v] = timeBack;
}bool DFSTraverse(ALGraph* G,int v)
{//对图G进行遍历,访问函数为visit()for (int v = 0; v < G->vexnum; ++v){visited[v] = false;//初始化访问标记数组finishTime[v] = 0;//初始化每个顶点的退出时间}//本代码表示是从v = 0开始遍历/*for (int v = 0; v < G->vexnum; ++v){if (!visited[v]){DFS(G, v);}}*/DFS(G, v);
}int cmp(const pair<string, int>& x, const pair<string, int>& y)
{return x.second >= y.second;
}
void sortMapByValue(map<string, int>& tMap, vector<pair<string, int> >& tVector)
{for (map<string, int>::iterator curr = tMap.begin(); curr != tMap.end(); curr++)tVector.push_back(make_pair(curr->first, curr->second));sort(tVector.begin(), tVector.end(), cmp);
}int main()
{int n = 5;//顶点数为4int e = 0;//记录边数ALGraph* G;CreateAdj(G, n);InsertAdj(G, 0, 2, e);InsertAdj(G, 0, 1, e);InsertAdj(G, 1, 3, e);InsertAdj(G, 1, 2, e);InsertAdj(G, 2, 3, e);/*InsertAdj(G, 1, 0, e);InsertAdj(G, 1, 3, e);InsertAdj(G, 0, 4, e);InsertAdj(G, 3, 4, e);InsertAdj(G, 4, 2, e);*/printf("图中共有%d个顶点,%d条边", n, e);printf("图G:\n");DispAdj(G);DFSTraverse(G,0);printf("各顶点对应的退出时间: \n");map<string, int> tMap;vector<pair<string, int>> tVector;for (int i = 0; i < G->vexnum; i++){tMap.insert(pair<string, int>(to_string(i) + "号顶点", finishTime[i]));}sortMapByValue(tMap, tVector);printf("\n");//拓扑序列printf("拓扑序列如下: ");for (int i = 0; i < tVector.size(); i++){cout << tVector[i].first << "(退出递归所需时间:" << tVector[i].second << ")" << "----->";}cout << endl;system("pause");DestroyAdj(G);//销毁邻接表
}

在这里插入图片描述


http://chatgpt.dhexx.cn/article/ORvXhd78.shtml

相关文章

【排序算法】排序算法-拓扑排序

拓扑排序 相关概念AOV网拓扑排序 实现思路实现过程 代码测试测试类测试样例 相关概念 AOV网 一项大的工程常被分为多个小的子工程 子工程之间可能存在一定的先后顺序&#xff0c;即某些子工程必须在其他的一些子工程完成后才能开始 在现代化管理中,人们常用有向图来描述和分析…

算法提升:图的拓扑排序算法

目录 概念 思路 代码 概念 拓扑序列&#xff1a;一些活动&#xff0c;其中某些活动必须在另一些活动完成之后才能开始&#xff0c;一定是无环的有向图&#xff0c;称为AOV网。 拓扑排序&#xff0c;其实就是对一个有向图构造拓扑序列的过程。构造时会有两个结果&#xff1a…

leetcode-拓扑排序算法

拓扑排序原理 拓扑排序算法分析&#xff08;通俗易懂&#xff09;_hongjie_lin-CSDN博客_拓扑排序算法 207 课程表 bfs和dfs都可以。先来看一下bfs。 思路是&#xff1a;入度法&#xff0c;入度为0的时候&#xff0c;表示这门课程没有先修课程了&#xff0c;可以学习这门课程了…

2022.3.24 图论——拓扑排序算法

文章目录 一、拓扑排序简介二、例题1.题目2.分析3.代码 一、拓扑排序简介 1.Topological Sorting&#xff0c;指的是一个DAG(Directed Acyclic Graph)即有向图所有顶点满足一定条件的线性序列。 拓扑序列应满足两个条件&#xff1a; 每个点都只出现一次 如果存在一条从A指向B…

数据结构——图——拓扑排序算法

数据结构——图——拓扑排序算法 对AOV网进行拓扑排序的基本思路是:从AOV网中选择一个入度为0的顶点输出&#xff0c;然后删去此顶点&#xff0c;并删除以此顶点为尾的弧&#xff0c;继续重复此步骤&#xff0c;直到输出全部顶点或者AOV 网中不存在入度为0的顶点为止。 首先我…

拓扑排序详解(包含算法原理图解、算法实现过程详解、算法例题变式全面讲解等)

前置知识 有向无环图 在图论中&#xff0c;如果一个有向图无法从某个顶点出发经过若干条边回到该点&#xff0c;则这个图是一个有向无环图&#xff08;DAG图&#xff09;。 如图所示。 入度 对于一个有向图&#xff0c;若x点指向y点&#xff0c;则称x点为y点的入度。 出度…

拓扑排序算法分析(通俗易懂)

拓扑排序&#xff08;其实是一种依赖关系&#xff09;&#xff1a;对于有向且无环的图来说&#xff0c;当前这个节点的依赖来其之前已经完成了。 下面附上一个图让大伙更好的理解&#xff1a; 比如这个图&#xff1a;B需要依赖A才能完成&#xff0c;A需要依赖C和D才能完成&…

拓扑排序算法详讲

经过一天的专研,终于明白了拓扑排序算法,写篇博客记录一下心得. 一.拓扑排序介绍 在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网. 设G(V,E)是一个具有n个顶点的有向图,v中的顶点序列v1,v2…,vn,满足若从…

C++ 拓扑排序算法

拓扑排序 有向无环图 如果一个有向图的任意顶点都无法通过一些有向边回到自身&#xff0c;那么称这个有向图为有向无环图。 拓扑排序 拓扑排序是将有向无环图G的所有顶点排成一个线性序列&#xff0c;使得对图G中的任意两个顶点u、v&#xff0c;如果存在边u->v&#xff0c;那…

拓扑排序

拓扑排序 一、拓扑排序的定义&#xff1a; 先引用一段百度百科上对于拓扑排序的定义&#xff1a; 对一个有向无环图 ( Directed Acyclic Graph 简称 DAG ) G 进行拓扑排序&#xff0c;是将 G 中所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点 u 和 v &#xff0c…

拓扑排序算法

拓扑排序介绍 拓扑排序(Topological Order)是指&#xff0c;将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。 这样说&#xff0c;可能理解起来比较抽象。下面通过简单的例子进行说明&#xff01; 例如&#xff0c;一个项目包括A、B、C…

经典算法之拓扑排序

定义&#xff1a; 把AOV网&#xff08;用定点表示活动&#xff0c;用弧表示活动间优先关系的有向图&#xff09;络中各个顶点按照它们互相之间的优先关系排列成一个线性序列的过程叫做拓扑排序。 方法&#xff1a; 在有向图中选一个没有前驱的顶点并且输出从图中删除该顶点和…

拓扑排序(topological sorting)介绍及Python实现

目录 1. 拓扑排序 2. 拓扑排序存在的前提 3. 拓扑排序的唯一性问题 4. 拓扑排序算法原理 4.1 广度优先遍历 4.2 深度优先遍历 5. 代码实现 5.1 Graph类的实现 5.2 广度优先搜索 5.3 深度优先搜索简易版&#xff08;无loop检测&#xff09; 5.4 深度优先搜索完整版 …

【算法】拓扑排序

今天学习拓扑排序。如果一个有向图的任意顶点都无法通过一些有向边回到自身&#xff0c;那么称这个有向图为有向无环图&#xff08;Directed Acyclic Graph&#xff0c;DAG&#xff09;。拓扑排序就是将有向无环图的所有顶点排序&#xff0c;使得图中任意两个点 u、v&#xff0…

拓扑排序及算法实现

一、拓扑排序概念 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序&#xff0c;是将G中所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点u和v&#xff0c;若边<u,v>∈E(G)&#xff0c;则u在线性序列中出现在v之前。通常&#xff0c;这样的线性…

利用迭代法求平方根——迭代法开平方运算

一、题目 用迭代法求&#xff1a; 的值。要求精度为0.00001&#xff0c;即 二、迭代公式 求平方根的迭代公式为&#xff1a; 当满足 时&#xff0c;这时的即是求得的根。如果 得到是精确值。如果不为0&#xff0c;则是近似值。 三、C代码 先给出开平方运算的函数。再给出主…

【算法】牛顿迭代法求平方根的原理和误差分析

前言 在《算法(第四版)》中的P23页&#xff0c;给出了经典的利用牛顿迭代法求平方根的算法&#xff0c;牛顿迭代法在数值计算中应用十分广泛&#xff0c;但是在看书中的代码时&#xff0c;我最困惑的是其中对收敛条件的判断&#xff0c;经过查阅资料和论坛&#xff0c;找到…

使用迭代法来求a的平方根

今天朋友问我一道使用迭代法求a的平方根的题&#xff0c;感觉受益匪浅&#xff0c;与诸君相分享 首先我们来看一下题目 我们也无需了解迭代法是什么原理&#xff0c;根据这个题目可以分析得到&#xff0c;需要使用while循环&#xff0c;下面是我的代码实践 #define _CRT_SEC…

利用牛顿迭代法求平方根

求n的平方根&#xff0c;先假设一猜测值X0 1&#xff0c;然后根据以下公式求出X1&#xff0c;再将X1代入公式右边&#xff0c;继续求出X2…通过有效次迭代后即可求出n的平方根&#xff0c;Xk1 先让我们来验证下这个巧妙的方法准确性&#xff0c;来算下2的平方根 (Computed b…

牛顿迭代法求解平方根

一个实例迭代简介牛顿迭代法 牛顿迭代法简介简单推导泰勒公式推导延伸与应用 一个实例 //java实现的sqrt类和方法 public class sqrt {public static double sqrt(double n){if (n<0) return Double.NaN;double err 1e-15;double t n;while (Math.abs(t - n/t) > err…