拓扑排序Java实现

概念:拓扑排序概念
原文:简短介绍及原始代码
本文对比原文,对其代码增加了更多注释。

package com.qf.greaph;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

public class TopoSortB {

    /**
     * @author Administrator
     *  拓扑排序的节点类
     */
    public static class Node{
        public Object val;
        public int PaIn = 0; //由于是拓扑排序, 所以是入度数量
        public Node(Object val) {
            this.val = val;
        }
    }

    /**
     * @author Administrator
     *  怎么表示一个图, 这里给出了另外一个解法。
     *  1.用set 容器 来 记录 顶顶点集
     *  2.边的记录用  Map + set 来,Map 的 key 用来指向 顶点, value 是一个 
     *  set 集合 , 这样 即可实现 单点对多点, 图的构建就此完成。(领接表的思想)
     */
    private static class Graph{
        //图中节点的集合
        public Set<Node> vertexSet = new HashSet<Node>();
        // 相邻的节点, 记录边  
        public Map<Node, Set<Node>> adjaNode = new HashMap<Node,Set<Node>>();

        // 将节点加入图中
        /**
         * @param start
         * @param end
         * 1.前两个if 是 先判断顶点集里是否有 这两个节点
         * 2. 第三个if判断该节点出度里面是否已经包含了这个点, 即是否存在这个要加入的边
         * 3. 通过2判断该边是一条新边, 如果 边集已包含start顶点,则只需加入end。
         * 4. 不存在的话, 直接加入这两位  
         * @return
         */
        public boolean addNode(Node start, Node end) {

            if (!vertexSet.contains(start)) {
                vertexSet.add(start);
            }
            if (!vertexSet.contains(end)) {
                vertexSet.add(end);
            }
            if (adjaNode.containsKey(start) &&
                    adjaNode.get(start).contains(end)) {
                return false;
            }       
            if (adjaNode.containsKey(start)) {
                adjaNode.get(start).add(end);
            }else {
                Set<Node> temp = new HashSet<>();
                temp.add(end);
                adjaNode.put(start, temp);

            }
            end.PaIn ++;
            return true;    
        }       
    }

    // Kahn算法
    /**
     * @author Administrator
     * 1.采用的是BFS算法进行拓扑排序的(需要先学习图的BFS搜索)
     * 2. 先通过构造函数找到入度为0的顶点
     * 3. 通过process进行拓扑操作, 用的是BFS算法。
     */
    private static class KahnTopo{
        private List<Node> result; // 用来储存结果集
        private Queue<Node> setOfZeroIndegree; // 用来存储入度为0 的顶点
        private Graph graph;
        // 构造函数, 初始化
        public KahnTopo(Graph di) {
            this.graph = di;
            this.result = new ArrayList<Node>();
            this.setOfZeroIndegree = new LinkedList<Node>();
            // 对入度为0的集合进行初始化
            for (Node iterator : this.graph.vertexSet) { 
                if (iterator.PaIn == 0) {
                    this.setOfZeroIndegree.add(iterator);
                }
            }
        }   
        // 拓扑排序处理过程 
        private void process() {
            while (! setOfZeroIndegree.isEmpty()) {
                Node v = setOfZeroIndegree.poll();

                // 将当前顶点添加到集合集中
                result.add(v);
                // 没有顶点了, 直接返回
                if (this.graph.adjaNode.keySet().isEmpty()) {
                    return ;
                }
                // 遍历 v 引出的所有边
                for (Node w : this.graph.adjaNode.get(v)) {
                    // 将该边从图中移除, 通过减少边的数量来表示
                    w.PaIn -- ;
                    if (0 == w.PaIn) {// 如果入度为0, 那么加入入度为0的集合

                        setOfZeroIndegree.add(w);

                    } 
                }
                this.graph.vertexSet.remove(v); 
                this.graph.adjaNode.remove(v);
            }
            // 如果此时图中还存在边, 那么说明图中含有环路
            if(!this.graph.vertexSet.isEmpty()) {
                System.out.println("存在回环");
                return ;
            }
        }

        //结果集
        public Iterable<Node> getResult() {
            return result;
        }           
    }
    //测试
        public static void main(String[] args) {
            Node A = new Node("A");
            Node B = new Node("B");
            Node C = new Node("C");
            Node D = new Node("D");
            Node E = new Node("E");
            Node F = new Node("F");

            Graph graph = new Graph();
            graph.addNode(A, B);
            graph.addNode(B, C);
            graph.addNode(B, D);
            graph.addNode(D, C);
            graph.addNode(E, C);
            graph.addNode(C, F);

            KahnTopo topo = new KahnTopo(graph);
            topo.process();
            for(Node temp : topo.getResult()){
                System.out.print(temp.val.toString() + "-->");
            }
        }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值