环检测——并查集

先描述思路,再列出我自己的算法实现,最后列出geeksforgeeks上的代码,进行比较分析

思路

在做并查集时,每次对节点i和节点j做合并时,分别会在parent数组中找到他们的根节点

  • 如果根节点不同,则做合并
  • 而如果指向同一个根节点,则意味着,存在环

算法实现

我的版本

    int[] unionParent = new int[V];

    int find(int node) {

        int result = node;
        while (unionParent[result] != -1) {
            result = unionParent[result];
        }

        // 压缩路径
        int tmp = node;
        while (unionParent[tmp] != -1) {
            tmp = unionParent[tmp];
            unionParent[tmp] = result;
        }

        return result;
    }

    boolean isCycle() {

        // init unionParent array
        for (int i = 0; i < V; i++) {
            unionParent[i] = -1;
        }

        // traversal edge
        for (int i = 0; i < V; i++) {
            Iterator<Integer> j = adj[i].iterator();
            while (j.hasNext()) {
                int subSet1 = find(i);
                int subSet2 = find(j.next());
                if (subSet1 != subSet2) {
                    unionParent[subSet2] = subSet1;
                }else {
                    // 存在一个环
                    return true;
                }
            }

        }
        //做完并查集
        return false;
    }

geeksforgeeks版本

 // A utility function to find the subset of an element i
    int find(int parent[], int i)
    {
        if (parent[i] == -1)
            return i;
        return find(parent, parent[i]);
    }

    // A utility function to do union of two subsets
    void Union(int parent[], int x, int y)
    {
        int xset = find(parent, x);
        int yset = find(parent, y);
        parent[xset] = yset;
    }


    // The main function to check whether a given graph
    // contains cycle or not
    int isCycle( Graph graph)
    {
        // Allocate memory for creating V subsets
        int parent[] = new int[graph.V];

        // Initialize all subsets as single element sets
        for (int i=0; i<graph.V; ++i)
            parent[i]=-1;

        // Iterate through all edges of graph, find subset of both
        // vertices of every edge, if both subsets are same, then
        // there is cycle in graph.
        for (int i = 0; i < graph.E; ++i)
        {
            int x = graph.find(parent, graph.edge[i].src);
            int y = graph.find(parent, graph.edge[i].dest);

            if (x == y)
                return 1;

            graph.Union(parent, x, y);
        }
        return 0;
    }
  1. find 用了递归实现,没有对路径进行压缩
  2. union中没有对获得的xset,yset判断是否相等,把比较过程放在isCycle中
  3. find,union函数参数包含了parent数组
  4. isCycle的参数为Graph对象,在函数体中创建的parent数组

总结

我认为geeksforgeeks版本中,参数设置更为合理,更具抽象性

  1. 我不该把parent 数组声明在Graph中
  2. isCycle应该设有Graph对象作为参数,我的版本为每次需要相应Graph对象调用自己的isCycle方法

find函数应该进行垃圾压缩优化

猜你喜欢

转载自blog.csdn.net/niukai1768/article/details/80200469