拓扑排序
KAHN算法实现:
设一个有向图,存在一个入度=0,并有出度的点
**遍历所有点的出度和入度,找到入度为0的点,将点全部入队
**依次出队点,去掉图中有关该点的狐,同时将入度为0的点入队
**直到队列为空
执行过程中出现的情况:
**找不到入度=0的点;所有点都输出了。这个输出的序列就是拓扑序列
**找不到入度=0的点;但还有点没输出。这说明这个图有环。这些剩下的点,必然存在一个环
**在去掉狐后,可能出现很多个入度为0的点,这是就跟自己定义的选择有关系了;从这里也可以得出,拓扑序列其实是不唯一的
笔记:邻接矩阵和邻接表其实存的都应该是可达的点,因此,就是出度边所对应的
代码实现的思路(这是我自己的思路,实现起来应该很简单,但不保证效率最优;至于代码,别人写的再好,看的也费劲,还是思路来的快点):
**定义一个数据结构(JavaBean),里面
保存每个vex的名称
//保存一个指针链表(LinkedList),存放这个点的出度点
保存一个指针链表(LinkedList),存放这个点的入度点
保存一个入度为0标志位
**遍历每个入度标志位,找到为0的点,入队
**出队一个点,遍历每个入度链表,去掉这个点
**同时,查看入度标志位,遇到入度为0的点就入队
**直到再也找不到入度为0的点,也就是队列为null
时间复杂度:O(V*E)
**找到一个没有入度的点v1,入队,将v1到v2,v3,v4的狐全部删掉,将v1出队,输出
**v2的入度为0,所以将v2入队(这里需要做的是,将所有的入度为0的点压栈),将v2出队,删除v2到v4,v5的边,输出
**v5的入度为0,所以将v5入队(这里需要做的是,将所有的入度为0的点压栈),将v5出队,删除v5到v4,v7的边,输出
**v4的入度为0,所以将v4入队(这里需要做的是,将所有的入度为0的点压栈),将v4出队,删除v4到v3,v6,v7的边,输出
**v3,v7的入度为0,所以将v3,v7入队(这里需要做的是,将所有的入度为0的点压栈)将v7出队,删除v7到v6的边,输出
**栈中还有v3,将v3出队,删除v3到v6的边,输出
**v6的入度为0,所以将v6入队,将v6出队,由于没有出度的边了,所以不需要删除,输出
**因为没有入度为0的点了,并且这个图的不相交集只有一个,到此结束,说明这个图没有环
最终得到的拓扑顺序是:1-2-5-4-3-7-6或1-2-5-4-7-3-6
DFS算法实现:
**随便一个点开始,开始一个个走过去,每走到一个点,就将访问标志位标为走过;并把该点压栈
**由于我们是深度优先,所以就是随意选一个往下的点继续访问,标记,压栈
**直到一个点没有未访问的下一个目标点为止
**回溯,以此将点退栈,判断是否还有未走过的路径,未走过的点
**直到将所有点都标记过了(最终,操作将停止在根节点)
**循环上次操作,变化起点,记录下所有点的执行时间
在这个过程中,用到了回溯的思想;因此,我们需要将每个点压栈,遇到没有下一目标的点,就出栈
结果分析:
每个点为起点的深度优先搜素的完成时间进行排序就是拓扑排序的逆序(不知道为什么,因此纠结了很久,我一直以为这是通过一次遍历就能得出结果的,验证了好久才发现,根本没有解)
以v1为起点,深度遍历的顺序为:
1-2-5-7-6-4-3
以v2为起点,深度遍历的顺序为:
2-5-7-6-4-3 1
........................