`

有向图判断同层次问题

 
阅读更多

问题:在有向图 ( 只有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

 

 

 

分享到:
评论

相关推荐

    图的着色遍历有向无环图判断

    **定义:** 有向无环图(Directed Acyclic Graph, DAG)是一种特殊的有向图,其中没有任何一条路径能够形成一个环路。换句话说,在一个DAG中,不存在任何起点和终点相同的有向路径。 **应用场景:** - **任务调度**...

    基于邻接链表构建的有向图

    这些方法涵盖了有向图的基本操作和常见问题的解决,通过理解和实现这些方法,可以深入理解有向图的性质和应用。 三、邻接链表的优缺点 优点: 1. 空间效率高,尤其对于稀疏图。 2. 添加和删除顶点或边的时间复杂度...

    判断图中是否存在路径

    这个问题涉及到有向图(Directed Graph)的概念,其中的边具有方向性,即从一个节点指向另一个节点。 **有向图**是由顶点(Vertex)和有方向的边(Arc)构成的。每个边都有一个起点和一个终点,从起点指向终点。在...

    设有一有向图为g(vdoc (2).pdf

    本题主要涉及有向图、无向图、邻接矩阵、邻接表、强连通分量、最短路径算法(Dijkstra、Floyd)、最小生成树算法(Prim、Kruskal)、拓扑排序、完全二叉树和AOE网等概念。 1. 有向图G=(V,E)的定义:V是顶点集合,E...

    liantongtu.rar_连通图的判断

    在有向图中,如果从每个节点都可以到达其他所有节点,我们称之为强连通图;如果仅存在单向路径使得所有节点可达,那么是弱连通图。 程序的核心算法可能包含以下部分: 1. **深度优先搜索(DFS)**:DFS 是一种遍历...

    无向图的DFS、BFS遍历

    总之,无向图的DFS和BFS遍历是图论中的基础操作,它们在许多问题中起到关键作用,如路径查找、拓扑排序和寻找连通分量等。理解和掌握这些概念以及如何在实际编程中实现它们,对于提升在算法和数据结构方面的技能非常...

    铁路信号系统车站联锁的层次结构

    在铁路信号系统中,车站联锁的层次结构是确保列车安全、高效运行的关键技术之一。本文将详细解析铁路信号系统车站联锁的层次结构,并针对各个层级的功能与组成进行深入探讨。 ### 一、车站联锁层次结构概述 车站...

    数据结构 第六章 图 练习题及答案详细解析(精华版) (2).docx

    - 回路检测:可以使用深度优先搜索或广度优先搜索来判断有向图是否存在环。 4. 空间复杂度 - 邻接矩阵存储图的空间复杂度为 O(n^2),而邻接表通常更节省空间,为 O(n+e)。 - 无向图的邻接表中,边表的结点数为 2...

    数据结构第六章图理解练习知识题及答案解析详细解析(精华版).pdf

    18. 判断一个有向图是否存在回路,可以使用深度优先遍历。如果在遍历过程中发现回到已访问过的节点,那么图中存在回路。 综上所述,本题涉及到的知识点包括:图的基本概念,无向图和有向图的特点,完全图的概念,图...

    精品资料(2021-2022年收藏)研究基于层次分析法的模型高校图书馆员绩效评价模型.doc

    【层次分析法(AHP)】AHP通过构建层次结构模型,将复杂问题分解为多个易于比较的因素,通过专家或决策者的两两对比判断,形成判断矩阵,进而量化这些主观判断,提高决策的合理性。这种方法强调逻辑性、系统性和实用...

    第6章+图习题解答(严蔚敏版)1

    - 判断有向图是否有环,拓扑排序是一种有效的方法。如果在拓扑排序过程中遇到环,就会导致无法继续排序。问题(15)的答案是B。 以上知识点涵盖了图的基本性质、遍历算法以及相关应用,这些都是图论和算法课程中的...

    细胞分裂时期图像判断.pdf

    通过对有丝分裂各阶段图像的辨识与分析,学生能够更加直观地理解细胞周期和遗传规律,进而对生命科学有更深层次的认知。教师通过图像的引导和讲解,能够帮助学生形成严谨的观察习惯和科学的思维方式,为将来的学习和...

    判别顶点vi和vj(ij)之间是否有路径。

    1. **邻接矩阵**:对于无向图或有向图来说,邻接矩阵是一种常见的存储结构。它用一个二维数组表示图中顶点之间的关系,对于无向图而言,该矩阵是对称的。如果顶点\( v_i \)到顶点\( v_j \)之间存在一条边,则邻接...

    数据结构第7章--图.docx

    - 连通有向图至少需要 \(n\) 条边来确保图的连通性。 - 正确答案为 **B**:\(n\)。 5. **完全有向图的边数**: - 完全有向图中的每一对不同的顶点间都有一条方向确定的边。 - 完全有向图的边数为 \(n(n-1)\)。 ...

    层次聚类代码

    层次聚类的基本思想是从单个样本开始,逐渐合并最相似的样本或群组,直到所有样本都属于同一个群组,或者满足预设的终止条件。这个过程可以用两种方式表示:凝聚型自底向上和分裂型自顶向下。 1. 凝聚型层次聚类:...

    数数据结构图PPT学习教案.pptx

    在有向图中,一个顶点通过有向边指向另一个顶点,我们说前者邻接至后者,后者邻接自前者。 图结构与其他数据结构如线性结构(如数组、链表)和树结构有所不同。线性结构中,元素间的关系是一对一的前后关系;树结构...

    图习题解析(答).docx

    这些题目主要涵盖了图的基本概念,包括图的类型(有向图和无向图)、图的存储结构(邻接矩阵和邻接表)、图的遍历(深度优先和广度优先)、最小生成树算法(Prim 和 Kruskal)、图的性质(如度数、连通性、拓扑排序...

    203层次分析法1

    层次分析法(AHP,Analytic Hierarchy Process)是一种用于决策分析的方法,它结合了定量与定性的分析,尤其适用于处理复杂多目标的问题。这种方法由托马斯·塞韦林·萨蒂(Thomas L. Saaty)提出,主要用于在无法...

    正方体的11种展开图与判断方法教(学)案.doc

    在寻找正方形对面的过程中,有一个重要的技能需要学生掌握,即在同一行或同一列中隔开一个正方形的两个正方形是相对面。这个规律对于理解展开图和折叠正方体至关重要。通过观察和分析,学生可以更清楚地认识到展开图...

Global site tag (gtag.js) - Google Analytics