算法笔记7.树和图的存储,DFS,BFS,拓扑排序

本文详细介绍了图的存储方式,包括邻接矩阵和邻接表,以及深度优先搜索(DFS)算法的实现,强调了DFS的特点如回溯和剪枝。同时,文章还探讨了广度优先搜索(BFS)的搜索策略和拓扑排序的概念,指出有向无环图的拓扑序列构造方法。
摘要由CSDN通过智能技术生成

树和图的存储

树是一种特殊的图,是一种无环连通图。所以下面只讲图。

图分有向图和无向图,无向图是一种特殊的有向图(无向图就是一个路径两个方向)

所以下面只写有向图怎么存,两种存储方式邻接矩阵(二维数组,存储bool值,也可以存权值。两个索引代表从哪个点到哪个点,用的少,浪费空间,适合存稠密图)和邻接表(单链表,每个点存一个单链表,链表存储这个点可以到哪个点,比如点a可以到点b和点c,那点a的单链表就存点b,然后b指向c。但是这里的指向无意义,只是方便查找)

DFS深度优先算法

在搜索的时候优先向下搜索,走到底后回退看看有没有其他岔路,没有再继续回退。用栈,空间有优势。

在不涉及树的时候(比如说输出一组数据的全排列),DFS跟递归分治的思想很类似。如果用递归来做DFS的话,写代码的时候,我们的写法就是先遍历第一个位置的所有情况,将使用过的标记为不可以以后,在遍历第二个位置的所有情况,递归调用。一直递归到所有元素都被使用过。

虽然写的时候看起来跟BFS很像,但是实际执行的时候却是DFS,因为它递归的时候会直接一直递归到底,然后回去递归第二种情况,递归完了再往上回一层递归。

(一般没有一个固定的框架)

int n;
int data[n];
int path[n];
bool use[n];

//u是第几个位置
void DFS(int u)
{
	if (u == n) //到最后一层了把结果输出
	{
		for (int i = 0; i < n; i++) printf("%d ", path[i]);
		return;
	}

	for (int i = 1; i <= n; i++)
	{
		if (!use[i]) //如果这个元素没有被用过
		{
			path[u] = data[i]; //记录这个元素
			use[i] = true;     //标记使用过
			DFS(u + 1);        //递归下一位置
			use[i] = false;    //递归后这个位置就是没用过的了(回溯)
		}
	}
}

DFS里面有两个比较重要的思想,回溯和剪枝。

回溯是指当回退的时候,要把状态恢复到原样,就像上面代码写的use[i] = false一样。

剪枝是指,回退完下一步的时候,先判断一下是不是不满足条件,如果不满足条件,直接再下一步,就相当于把一个树的枝干的情况剪去了(也可以判断到不是最优解给剪去,根据需要)。

BFS广度优先算法

搜索的时候优先将这一层搜索一遍。用队列。具有最短性(搜到的距离就是最短距离),因为它是根据距离来搜的,先从距离短的搜,逐渐距离变大。

这个一个固定的套路就是先把初始状态放到queue里,然后用一个while循环,条件是队列不空,然后取出队头,拓展队头(比如说要找一个点的路径,就是刚开始把起点存进去,然后进入循环,取出起点,将四个方向的点存进去,然后再取出第一个点拓展方向)。

因为队列的特性,只有当一层的结束后才会找下一层。

拓扑排序

拓扑序列就是一个图中的点的序列,同时满足条件,每个点之间的路径,在拓扑序列中都是起点在终点前面。

比如一个有向图,1,2,3。其中路径是1指向2,1指向3,2指向3。那么1,2,3就是一个拓扑序列,因为1在2前,1在3前,2在3前。

并不是所有图都有拓扑序列,有环的图没有拓扑序列,一个有向无环图一定有拓扑序列,因此也被称为拓扑图。

只要引入一个入度和出度的概念就可以很轻松得出拓扑序列,有几个被别的点指向的路径就是有几个入度,有几个指向别的点的路径就是有几个出度。

所有入度为0的点都可以作为起点,所以第一步是把所有入度为0的点入队。然后后面就是一个宽搜的过程。

首先取出队头t,然后枚举t的所有出边(例如t->j),然后删掉出边,删掉出边以后,j的入度就会减少1,等到j的入度为0的时候,就可以再放入队列。

删掉出边是为了减入度满足入队条件,如果是无环图的话,就会有刚开始的入度为0的点,入度为0的点指向别的点的边删掉是无所谓的(因为刚开始的点已经记录在序列里了),这样就相当于是构成了新的无环图,然后就能继续流程。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值