使用深度优先搜索对有向无环图进行拓扑排序

拓扑排序是图G中所有节点的一种线性次序,该次序满足以下条件:如果图G包含边(u,v),则节点u在拓扑排序中处于节点v的前面
在实际生活中有很多应用需要用有向无环图来指明事件的优先次序。下面以一个穿衣的例子来讲解拓扑排序:
例子图片
在穿每一件衣服之间,要考虑是否要求先穿上某件衣服。拓扑排序可以解决这个问题,算法的主要思想如下:
通过深度优先搜索,记录每个节点的开始扫描的时间d和将其所有子节点全部扫描完的时间f,按照f从大到小的顺序,从左向右排列,得到的即为拓扑排序。在具体代码操作中,由于先扫描完成的节点总是f最小的,所以将每个扫描完的节点添加到数组中,再按照反序输出即可
具体代码如下:


import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner;
/**
 * 
 * @author Founder
 * 作者原创,转载请注明出处
 */
public class Main{
    static int time = 0;
    static ArrayList<Integer> topology;
    public static void main(String[] args){
        /**
         * 输入方式:
         * 第一行输入节点的个数n
         * 后面n行输入第n个节点(从0开始数)链接的子节点,没有子节点则直接换行
         */
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        Node[] nodes = new Node[n];
        topology = new ArrayList<>();
        for(int i = 0; i < n; ++i){
            nodes[i] = new Node();
        }

        input.nextLine();

        for(int i = 0; i < n; ++i){
            String line = input.nextLine();
            LinkedList<Integer> linkNodes = new LinkedList<>();
            if(!line.equals("")){
                String[] tempIntStr = line.split(" ");
                for(int j = 0; j < tempIntStr.length; ++j){
                    linkNodes.add(Integer.parseInt(tempIntStr[j]));
                }
            }
            nodes[i].setLinkNodes(linkNodes);
        }

        dfs(nodes);

        for(int i = topology.size() - 1; i >= 0; --i){
            System.out.print(topology.get(i) + " ");
        }
    }

    public static void dfs(Node[] nodes){

        for(int i = 0; i < nodes.length; ++i){
            if(nodes[i].getColor() == Node.WHITE)
                dfsVisit(nodes,i);
        }
    }
    public static void dfsVisit(Node[] nodes,int no){
        time++;
        nodes[no].setColor(Node.GRAY);
        nodes[no].setD(time);
        LinkedList<Integer> linkNodes = nodes[no].getLinkNodes();
        for(int i = 0; i < linkNodes.size(); ++i){
            Node temp = nodes[linkNodes.get(i)];
            if(temp.getColor() == Node.WHITE){
                temp.setParent(nodes[no]);
                dfsVisit(nodes,linkNodes.get(i));
            }
        }
        nodes[no].setColor(Node.BLACK);
        topology.add(no);
        time++;
        nodes[no].setF(time);

    }

}

class Node{
    public static final int WHITE = 0;
    public static final int GRAY = 1;
    public static final int BLACK = 2;

    private int color = WHITE;
    private int d = 0;
    private int f = 0;
    private Node parent = null;
    private LinkedList<Integer> linkNodes = null;



    public int getColor() {
        return color;
    }
    public void setColor(int color) {
        this.color = color;
    }
    public int getD() {
        return d;
    }
    public void setD(int d) {
        this.d = d;
    }
    public int getF() {
        return f;
    }
    public void setF(int f) {
        this.f = f;
    }
    public Node getParent() {
        return parent;
    }
    public void setParent(Node parent) {
        this.parent = parent;
    }
    public LinkedList<Integer> getLinkNodes() {
        return linkNodes;
    }
    public void setLinkNodes(LinkedList<Integer> linkNodes) {
        this.linkNodes = linkNodes;
    }

    @Override
    public String toString() {
        return "Node [d=" + d + ", f=" + f + "]";
    }



}

对于本例,输入如下:
9
1 7
2 7
5
2 4
5
(没有输入,直接换行)
7
(没有输入,直接换行)
(没有输入,直接换行)

输出:
8 6 3 4 0 1 7 2 5
即按照如下顺序进行:
这里写图片描述
符合题目要求。

基本原理理解:
深度优先搜索森林中,每个树里f最小的节点,没有子节点,因此放在该树的最右边,在回溯时,将其父节点放在左边,使每个树符合拓扑排序的要求;森林中不同树之间不干扰,因此不同树的放置顺序不影响拓扑排序,所以整个排序符合拓扑排序要求。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值