首页 > 其他分享 >链式前向星和拓扑排序专题

链式前向星和拓扑排序专题

时间:2024-06-14 10:21:27浏览次数:26  
标签:cnt int 拓扑 head edge 链式 排序 前向星

多日以来被图论狠狠的羞辱,下定决心学习图论基础链式前向星和拓扑排序

图的存储方式

邻接表

规模大的稀疏图可用邻接表,存储复杂度为\(O(n + m)\)。n表示点的数量,m表示边的数量。

struct edge{
	int from, to, w;
	edge(int a, int b, int c) {
		from = a; to = b; w = c;
	}
}
vector<edge>e[N];
for (int i = 1; i <= n; i++) 
	e[i].clear();//初始化
//存边
e[a].push_back(edge(a, b, c));
//遍历所有邻居
for (int i = 0; i < e[u].size(); i++) {
	//for (int v:e[u])
	int v = e[u][i].to, w = e[u][i].w;
}

链式前向星

实际在存储邻接边的过程也是先定位某个点的第一条边,再定位第二条边,由此可以设计没有任何空间浪费、变成非常简单的存图方法。

  • \(head[]\)作为静态数组,\(head[u]\)指向\(u\)的一个邻居的存储位置。
  • \(struct\ edge\)是结构静态数组,\(edge[i].to\)存储邻居节点编号,\(edge[i].next\)指向下一个邻居节点的存储位置\(j\),对应的下一个邻居存储在\(edge[j]\)中。
  • \(cnt\)代表当前的存储位置,或者说新加入的边会存储在\(edge[cnt]\)。
  • 获取\(u\)对应新的边,插入到\(head[u]\)的方式为头插法,将其插入到\(head[u]\)对应的第一个位置。
    也可以将edge结构体转化成为两个不同的数组\(e[]\)和\(ne[]\)进行实现
int head[N],cnt;
struct {
	int from, to, next;//起点,终点,下一个邻居
	int w;//边权
}edge[M];//数组存储边
void init(){
	for (int i = 0; i < N; ++i) head[i] = -1;//点初始化
	//由于头插法,初始化点的-1一定会被传递到链末端,所以可以不初始化边
	for (int i = 0; i < M; ++i) edge[i].next = -1;//边初始化
	cnt = 0;
}
void addedge(int u, int v, int w) {
	edge[cnt].from = u;
	edge[cnt].to = v;
	edge[cnt].w = w;
	//头插法插入节点
	edge[cnt].next = head[u];//下一个邻居的存储位置
	head[u] = cnt++;//cnt代表新边存储位置
	
	//附上数组对应的实现方式
	//e[cnt] = v;
	//ne[cnt] = head[u];
	//w[cnt] = w;
	//head[u] = cnt++;
}
//~1仅对-1有效,0已经是有效空间
for (int i = head[2]; ~i; i = edge[i].next)//遍历节点2的所有邻居,i != -1
	printf(" %d - %d", edge[i].from, edge[i].to);

拓扑排序

终于到不知道为什么总能发挥作用的拓扑排序部分

拓扑排序的概念

一个图能够进行拓扑排序的充要条件是它是一个有向无环图(DAG)。
如果图中有环,可以使用拓扑排序找到环。若本身为无向图,可以通过拓扑排序的BFS,依次将度(即包含出度和入度)为1的点和对应的边去除,若邻居度变为1则入队,直到队列为空。剩余度大于1的点为环上的点。这种无向图找环的方式仅适用于只有一个环的基环树。

基于BFS的拓扑排序

  1. 无前驱的顶点优先
    1. 将所有入度为0的点放入队列。
    2. 弹出队首,邻居点入度-1,入度为0的邻居节点入队。
    3. 继续直到队列为空。
      队列已空但还有点未入队,说明图不是DAG,没有进入队列的就是环上的点
  2. 无后继的顶点优先:即出度为0的点开始

BFS拓扑排序的时间复杂度

  • 查找入度为0的点,检查每条边复杂度\(O(m)\)
  • 队列操作中,每个点进出队列一次,并且检查对应所有邻居\(O(n + m)\)

基于DFS的拓扑排序

DFS深度搜索是沿着一条路径一直搜索到底部,然后逐层回退,正好体现点与点的先后关系,天然符合拓扑排序。
对于有向无环图,如果只有一个点u是0入度,直接进行DFS递归返回的顺序就是逆序的拓扑排序。

需要处理的细节

  1. 如何找到入度为0的点开始DFS?如何处理多个入度为0的点?
    设置一个虚拟的点,单向连接到所有其它的点。实际编程直接遍历每个点轮流执行一遍DFS即可。
  2. 如果图不是DAG,说明是有环图,递归时,会出现**回退边*

输出拓扑排序

使用回溯输出所有的拓扑排序
使用topo[]记录排序,vis标记是否访问,indegree记录入度
void dfs(int z, int cnt) {
	int i;
	topo[cnt] = z;
	if (cnt == n - 1) {
		for (int i = ; i < n; i++) printf("%c", topo[i] + 'a');
		printf("\n");
		return ;
	}
	vis[z] = 1;
	for (int i = 0; i < n; i++) {
		if (!vis[a[i]] && dir[z][a[i]])
			indegree[a[i]]--;//所有下属入度减1
	}
	//使用回溯的方式遍历所有可能的拓扑排序
	for (int i = 0; i < n; i++)
		if (!indegree[a[i]] && !vis[a[i]])//入读为0继续取
			dfs(a[i], cnt + 1);
	for (int i = 0; i < n; i++) {
		if (!vis[a[i]] && dir[z][a[i]])
			indegree[a[i]]++;
	}
	vis[z] = 0;

}
//从所有入度为0的点开始
for (int i = 0; i < n; i++) {
	if (!indegree[a[i]])
		dfs(a[i], 0);
	printf("\n");
}

标签:cnt,int,拓扑,head,edge,链式,排序,前向星
From: https://www.cnblogs.com/tanch25/p/18247211

相关文章

  • 线性表的链式表示——链表
    目录一、单链表1、单链表的定义2、单链表的基本操作 (1)单链表的初始化(2)插入操作(3)删除操作(4)查找操作(5)求表长操作(6)单链表的建立 二、双链表三、循环链表 1、循环单链表2、循环双链表四、静态链表 五、顺序表和链表的比较1、存取方式2、逻辑结构与物理结构3......
  • 拓扑排序
    拓扑排序大家好,我是Weekoder!接上次的二分查找,我又打算写一篇关于拓扑排序的文章!本文涉及到的知识比较多,请确认已经掌握了以下知识:循环、输入、数组等基本语法STLvector容器的基本操作STLqueue队列的基本操作图论基本知识其中,第二条并不是必要的,只要你能用自己......
  • 【数据结构】链式二叉树详解
    个人主页~链式二叉树基本内容~链式二叉树详解1、通过前序遍历的数组来构建二叉树2、二叉树的销毁3、二叉树节点个数4、二叉树叶子节点个数5、二叉树第k层节点个数6、二叉树查找7、前序遍历8、中序遍历9、后序遍历10、层序遍历与检查二叉树是否为完全二叉树Queue.hQue......
  • C++U7-08-拓扑排序
    拓扑:是指把实体抽象成与其大小形状无关的点,把连接实体的线路抽象成线,研究这些点线之间的相连关系。而表示点和线之间关系的图就被称为拓扑结构图。 拓扑学原本是一个数学概念,描述的是几何图形或空间在连续改变形状后还能保持不变的性质,它只考虑物体间的位置关系而......
  • 使用C语言实现链式栈
    一、栈的基本概念        栈(Stack)是一种数据结构,它遵循“后进先出”(LIFO,LastInFirstOut)的原则。这意味着最后一个插入栈的元素最先被删除,你可以理解成一堆盘子,每次只能取最上面的盘子,删除的时候也只能删除最上面的盘子。这样是不是更容易理解了呢?栈的基本操作包......
  • 常用开关电源拓扑演进
    目录常用开关电源拓扑演进一、概述二、升压变换器(buck)与降压变换器(boost)......
  • 拓扑排序
    题目现有n扇门,门之间有m种关系,门与门之间可以互相传送。将所有不能被传送到的门视为起点,将不能传送到其他门的门视为终点,利用这些传送关系,求出有多少种路线。结果可能很大,请对998244353取模。https://ac.nowcoder.com/acm/contest/82881/BInput57231245132534......
  • python 探测网络 并自动绘制ip拓扑图
    要实现网络探测并自动绘制IP拓扑图,你可以使用Python与相关库和工具来完成。一个流行的方法是使用Python的网络扫描库(例如Nmap或Scapy)来扫描网络,并使用网络图形库(例如NetworkX和Matplotlib)来绘制IP拓扑图。以下是一个粗略的步骤示例,展示了如何实现网络探测并自动绘制IP拓扑图:i......
  • python NetworkX和Matplotlib 来绘制IP拓扑图
    要使用NetworkX和Matplotlib来绘制IP拓扑图,首先需要使用NetworkX来构建图形,并在图形准备就绪后,使用Matplotlib绘制图形。以下是一个简单的示例,演示了如何使用NetworkX和Matplotlib来绘制IP拓扑图:importnetworkxasnximportmatplotlib.pyplotasplt#创建一个简单的示......
  • 新时代的程序员4大本领:lambda表达式,链式编程,函数式接口,Stream流式计算
    传统程序员4大本领:泛型,枚举,反射,注解新时代的程序员4大本领:lambda表达式,链式编程,函数式接口,Stream流式计算lambda表达式//1.不需要参数,返回值为5()->5//2.接收一个参数(数字类型),返回其2倍的值x->2*x//3.接受2个参数(数字),并返回他们的差值(x,y)->x......