有向图判断同层次问题

问题:在有向图 ( 只有1 个开始节点, 1 个结束节点) 中判断任意两个节点是否为相同层次,不考虑环的情况,

AB为相同层次可以理解为经过A的数据流必然经过B,经过B的数据流也必然经过了A

a>b

a>c

b>d

c>d

其中 b c 节点为并行节点,都完成之后到达 d 节点,其中a d为相同层次 ,a,b;b,d;b,c 都不是相同层次

另外一个例子

a>b

a>c

b>c

c>d

b>d

其中 a,d 为相同层次,其他都不是

/**
 * 算法核心思想:
 * a的数据流必经过b的深刻含义为,a的数据流无论从哪条路走都必须经过b,这就要求a的相邻节点也具有该特性;
 * 同理将有向图反向,b的数据流也必经过a
 */
public class SameLevel {
    //n为节点个数,e为有向边个数
    private static int n,e;
    //有向图正向临接表
    private static Map<Character,LinkedList<Character>> adjacencyMap = new HashMap<Character,LinkedList<Character>>();
    //有向图反向临接表
    private static Map<Character,LinkedList<Character>> adjacencyReverseMap = new HashMap<Character,LinkedList<Character>>();

    /*
     * 创建正向与反向临接表
     * 输入格式参考如下:
     *  4 4        //输入节点个数与有向边数
     *  a b c d    //输入各个节点
     *  a b        // 以下四行有输入的有向边
     *  a c
     *  b d
     *  c d
     *  a d         //输入需要判断层次的任意两个节点
     */
    public static boolean createGraph(Scanner sc){
        n = sc.nextInt(); e = sc.nextInt();
        if(n == 0 || e == 0) return  false;
        for(int i=0;i<n;i++){
            char c = sc.next().toCharArray()[0];
            adjacencyMap.put(c,new LinkedList<Character>()); adjacencyReverseMap.put(c,new LinkedList<Character>());
        }
        for(int i=0;i<e;i++){
            char c =   sc.next().toCharArray()[0],d = sc.next().toCharArray()[0];
             LinkedList<Character> list = adjacencyMap.get(c), rlist = adjacencyReverseMap.get(d);
             list.addFirst(d); rlist.addFirst(c);
        }
        return true;
    }
     /*
      * 判断a是否从任意路径可达b
      */
    public static boolean DFSTraverseAtoB(char a ,char b , boolean []visited){
        if(a == b) return true;
        boolean ret = true;
        LinkedList<Character> adjacentList =  adjacencyMap.get(a);
        for(char c : adjacentList){
            Arrays.fill(visited,false);
            if(!DFS(c,b,visited) || !DFSTraverseAtoB(c,b,visited)){
                ret = false;
                break;
            }
        }
        return ret;
    }
     /*
      * 深度优先遍历算法
      */
    public static boolean DFS(char a , char b , boolean[] visited){
        if(a == b){
            return true;
        }
        visited[a] = true;
        LinkedList<Character> adjacentList =  adjacencyMap.get(a);
        for(char c : adjacentList){
           if(!visited[c]){
               if(DFS(c,b,visited)){
                   return true;
               }
           }
        }
       return false;
    }
    /*
     * 判断两个节点是否是同一层次
     */
    public static boolean isSameLevel(char a ,char b){
        boolean  ret = false,ret1 = false;
        if(!adjacencyMap.containsKey(a) || !adjacencyMap.containsKey(b)){
            throw new RuntimeException("Node Doesn't exist!");
        }
        boolean[] visited = new boolean[256];
        ret = DFSTraverseAtoB(a ,b ,visited);
        adjacencyMap = adjacencyReverseMap;
        //有向图反向再判断一次
        ret1 = DFSTraverseAtoB(b,a ,visited);
        return ret && ret1;
    }

    public static void main(String[]args){
         Scanner sc = new Scanner(System.in);
         boolean created = createGraph(sc);
         if(!created){
             throw new RuntimeException("Create graph failed!");
         }
         Character a = sc.next().toCharArray()[0],b = sc.next().toCharArray()[0];
         boolean ret = isSameLevel(a,b);
         System.out.println(ret);
    }
}

 由于上述代码不够灵活,效率不高,且不好测试,重构后的代码如下:

public class SameLevel {
    //n为节点个数,e为有向边个数
    private static int n,e;
    //有向图正向临接表
    private static Map<Character,LinkedList<Character>> adjacencyMap = new HashMap<Character,LinkedList<Character>>();
    //有向图反向临接表
    private static Map<Character,LinkedList<Character>> adjacencyReverseMap = new HashMap<Character,LinkedList<Character>>();
    //填充正向与反向临接表
    private static void fullMap(Map<Character,LinkedList<Character>> map,Character a,Character b){
        if(!map.containsKey(a)){
            map.put(a,new LinkedList<Character>());
        }
        map.get(a).add(b);
        if(!map.containsKey(b)){
            map.put(b,new LinkedList<Character>());
        }
    }
   /*
    * 根据输入的map创建图
    */
    public static boolean createGraph(Set<Edge<Character>> set){
        if(set == null || set.size() == 0) return false;
        for(Edge<Character> edge : set){
            Character key = edge.getStart(),value = edge.getEnd();
            fullMap(adjacencyMap,key,value);
            fullMap(adjacencyReverseMap,value,key);
        }
        return true;
    }
     /*
      * 判断a是否从任意路径可达b
      */
    public static boolean DFSTraverseAtoB(char a ,char b){
    	if(a == b)  return true;
        boolean ret = false;
        LinkedList<Character> adjacentList =  adjacencyMap.get(a);
        for(char c : adjacentList){
            if(!DFSTraverseAtoB(c,b)){
                return false;
            }
            ret = true;
        }
        return ret;
    }
    /*
     * 判断两个节点是否是同一层次
     */
    public static boolean isSameLevel(char a ,char b, Set<Edge<Character>> set){
        if(set == null || set.size() == 0) return false;
        boolean  ret = false,ret1 = false,created = createGraph(set);
        if(!created || !adjacencyMap.containsKey(a) || !adjacencyMap.containsKey(b)){
            throw new RuntimeException("Error!");
        }
        ret = DFSTraverseAtoB(a ,b);
        adjacencyMap = adjacencyReverseMap;
        //有向图反向再判断一次
        ret1 = DFSTraverseAtoB(b,a);
        return ret && ret1;
    }
     /*
      *
      */
    public static void main(String[]args){
        Set<Edge<Character>> set = new HashSet<Edge<Character>>();
        set.add(new Edge<Character>('a','b'));
        set.add(new Edge<Character>('b','c'));
        set.add(new Edge<Character>('b','d'));
        set.add(new Edge<Character>('d','e'));
        set.add(new Edge<Character>('c','d'));
        System.out.println(isSameLevel('a','d',set));

    }

    /*
     * 定义有向图的边对象
     * @start 为边的起点
     * @end 为边的终点
     */
    static class Edge<T>{

        private T start;
        private T end;

        public T getStart() {
            return start;
        }

        public void setStart(T start) {
            this.start = start;
        }

        public T getEnd() {
            return end;
        }

        public void setEnd(T end) {
            this.end = end;
        }

        public Edge(T start,T end){
             this.start = start;
             this.end = end;
        }

    }
}

 

 https://gist.github.com/narutolby/8348153#file-gistfile1-java

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值