有向图与无向图类似。一幅有向图是由一组顶点和一组有方向的边组成的。每条有方向的边都连接着有序的一对顶点。
拓扑排序
给定一幅有向图,将所有的顶点排序,使得所有有向边均从排在前面的元素指向排在后面的元素。
拓扑排序的实际含义是解决有优先级限制的调度问题。不过该有向图必须是无环的,若存在一个x-y-z的环,代表x必须在y前完成,y又必须在z前完成,z又要在x前完成。显然这三个限制条件不可能被同时满足。因此在构造拓扑排序的图之后,首要任务是检查这个图是否存在环。
检查是否有环并保存存在的环
public static class DirectedCycle{ //判断图是否存在环
private boolean[] marked;
private int[] edgeto;
private Stack<Integer> stack;
private boolean[] on_stack;
public DirectedCycle(diGraph d)
{
this.on_stack = new boolean[d.V()];
this.edgeto = new int[d.V()];
this.marked = new boolean[d.V()];
for(int i=0;i<d.V();i++)
if(!marked[i])
dfs(d, i);
}
private void dfs(diGraph g,int s)
{
on_stack[s]=true;
marked[s]=true;
Node n=g.adj.get(s);
int temp = n.value;;
while(n.next!=null)
{
n=n.next;
if(!this.stack.isEmpty())
return;
else if(!marked[n.value]) {
edgeto[n.value] = temp;
dfs(g, n.value);
}
else if(on_stack[n.value])
{
stack = new Stack<>();
for(int i=temp;i!= n.value;i=edgeto[i] )
stack.push(i);
stack.push(n.value);
stack.push(temp);
}
}
on_stack[s] = false;
}
}
和直接进行dfs相比,多了一个布尔数组on_stack用来保存现在递归的栈上存在的所有顶点;一个stack数组保存成环的顶点。判断成环条件就是当前顶点通向的下一顶点已经被标记遍历。
dfs的三种遍历方法
public static class DepthFirstOrder{ //三种遍历dfs的方法
private boolean[] marked;
private Queue<Integer> pre;//遍历顺序
private Queue<Integer> post;//顶点遍历完成的顺序
private Stack<Integer> reversePost;//实际就是拓扑排序的顺序
public DepthFirstOrder(diGraph g)
{
pre = new LinkedList<>();
post = new LinkedList<>();
reversePost = new Stack<>();
marked = new boolean[g.V()];
for(int v=0;v<g.V;v++)
if(!marked[v])
dfs(g,v);
}
private void dfs(diGraph g,int s)
{
pre.add(s);
marked[s] = true;
Node n = g.adj.get(s);
int temp=n.value;
while(n.next!=null) {
n = n.next;
if(!marked[n.value])
dfs(g, n.value);
}
post.add(s);
reversePost.push(s);
}
}