检查_有向图&无向图中的环

目录:

  1. 有向图中检查环
    1. python(递归,迭代)
    2. c++ [递归]
  2. 无向图中检查环
    1. python(递归,迭代)
    2. python [并查集]
    3. c++ [并查集]
    4. c++ [递归,迭代]

1.1 python 递归: 有向图中环检测:核心思想是检测节点的邻居是否再已有的stack里面

时间复杂度为DFS的复杂度O(V+E),空间复杂度为O(V)

DFS solution:an edge that is from a node to itself(selfloop) or one of its ancestor;

from collections import defaultdict

# 有向图查环
class UGraph:
    "undirected graph recursion"
    def __init__(self, vertices):
        self.V = vertices
        self.graph = defaultdict(list)

    def addEdge(self, u, v):
        self.graph[u].append(v)

    def isCyclicUtil(self, v, visited, recStack):
        """核心思想:检查节点的邻居有没有还在之前的stack里面,有则出线环"""
        visited[v] = True
        recStack[v] = True
        for neighbour in self.graph[v]:
            if visited[neighbour] == False:
                if self.isCyclicUtil(neighbour, visited, recStack) == True:
                    return True
            elif recStack[neighbour] == True:
                return True

        recStack[v] = False
        return False

    def isCycle(self):
        visited = [False] * (self.V + 1)
        resStact = [False] * (self.V + 1)
        for node in range(self.V):
            if visited[node] == False:
                if self.isCyclicUtil(node, visited, resStact) == True:
                    return True
            return False


if __name__ == "__main__":
    g = UGraph(4)
    g.addEdge(1, 2)
    g.addEdge(2, 3)
    g.addEdge(3, 1)
    g.addEdge(0, 1)

    print(g.isCycle())

# True

c++ (递归)

#include <iostream>
#include <list>

using namespace std;

class Graph {
    int V; // No. of vertices
    list<int> *adj;  // pointer to an array containing adjacency lists
    bool isCyclicUtil(int v, bool visited[], bool *rs);

public:
    Graph(int V);  // Constructor
    void addEdge(int v, int w); // add an edge to graph
    bool isCyclic(); // return true or false
};


Graph::Graph(int V) {
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int v, int w) {
    adj[v].push_back(w);
}

bool Graph::isCyclicUtil(int v, bool visited[], bool *recStack) {
    if (visited[v] == false) {
        // Mark the current node as visited and part of recursion stack
        visited[v] = true;
        recStack[v] = true;
        // recur for all vertices adjacent to this vertex
        list<int>::iterator i;
        for (i = adj[v].begin(); i != adj[v].end(); ++i) {
            if (!visited[*i] && isCyclicUtil(*i, visited, recStack))
                return true;
            else if (recStack[*i])
                return true;
        }
    }
    recStack[v] = false;
    return false;
}


bool Graph::isCyclic() {
    // Mark all the vertices as not visited and not part of recursion stack
    bool *visited = new bool[V];
    bool *recStack = new bool[V];
    for (int i = 0; i < V; i++) {
        visited[i] = false;
        recStack[i] = false;
    }
    // recursive function DFS
    for (int i = 0; i < V; i++) {
        if (isCyclicUtil(i, visited, recStack)) {
            return true;
        }
    }
    return false;

}


int main()
{
    // Create a graph given in the above diagram
//    Graph g(4);
//    g.addEdge(0, 1);
//    g.addEdge(0, 2);
//    g.addEdge(1, 2);
//    g.addEdge(2, 0);
//    g.addEdge(2, 3);
//    g.addEdge(3, 3);

    Graph g(4);
    g.addEdge(0, 1);
    g.addEdge(0, 2);
    g.addEdge(2, 3);


    if(g.isCyclic())
        cout << "Graph contains cycle";
    else
        cout << "Graph doesn't contain cycle";
    return 0;
}

# Graph doesn't contain cycle

2. 无向图中检查环

 

2.1 python 版本(递归版本)


# 无向图 - DFS 递归
from collections import defaultdict

class Graph:
    def __init__(self, vertices):
        self.V = vertices
        self.graph = defaultdict(list)

    def addEdge(self, v, w):
        self.graph[v].append(w)
        self.graph[w].append(v)


    def isCyclicUtil(self, v, visited, parent):
        visited[v] = True
        for i in self.graph[v]:
            if visited[i] == False:
                if (self.isCyclicUtil(i, visited, v)):
                    return True
            elif i != parent:
                return True
        return False

    def isCyclic(self):
        visited = [False] * (1 + self.V)
        for i in range(self.V):
            if visited[i] == False:
                if (self.isCyclicUtil(i, visited, -1) == True):
                    return True
        return False


if __name__ == "__main__":
    # recursive
    # g = Graph(5)
    # g.addEdge(0, 1)
    # g.addEdge(0, 2)
    # g.addEdge(2, 3)
    # g.addEdge(2, 4)
    # # g.addEdge(3, 4)

    g = Graph(3)
    g.addEdge(0, 1)
    g.addEdge(0, 2)
    g.addEdge(1, 2)
    print(g.isCyclic())

c++ (递归)


// c++ 无向图 - 环  - 递归
#include <iostream>
#include <list>
using namespace std;

// class definition
class Graph {
    int V; // number of vertices
    list<int> *adj;  // Pointer to an array
    bool isCyclicUtil(int v, bool visited[], int parent);

public:
    // Constructor
    Graph(int V);

    // add edge
    void addEdge(int v, int w);

    // return true if there is a cycle in undirected
    bool isCyclic();
};

Graph::Graph(int V) {
    this->V = V;
    adj = new list<int>[V];
}

void Graph::addEdge(int v, int w) {
    adj[v].push_back(w);
    adj[w].push_back(v);
}


bool Graph::isCyclicUtil(int v, bool visited[], int parent) {
    visited[v] = true;
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i) {
        if (!visited[*i]) {
            if (isCyclicUtil(*i, visited, v))
                return true;
        } else if (*i != parent)  // if an adjacent vertex is visited and is not parent of current vertex, then there exists a cycle
            return true;
    }
    return false;
}


bool Graph::isCyclic() {
    bool *visited = new bool[V];
    for (int i = 0; i < V; i++) {
        visited[i] = false;
    }

    for (int u = 0; u < V; u++){
        if (!visited[u])
            if (isCyclicUtil(u, visited, -1))
                return true;
    }
    return false;
}

int main() {
    Graph g1(5);
    g1.addEdge(0, 1);
    g1.addEdge(0, 2);
    g1.addEdge(2, 3);
    g1.addEdge(2, 4);
//    g1.addEdge(3, 4);
    g1.isCyclic()? cout << "graph contains cycle\n":cout << "graph doesn't contain cycle\n";
}

2.2 python 并查集


# 无向图 -> 并查集
# Find, Connect, Union
# reference:https://github.com/azl397985856/leetcode/blob/master/thinkings/union-find.md

class UF:
    """也非常容易判断是否2个节点是否连通"""
    def __init__(self, M):
        self.parent = {}  #
        self.size = {}  # 哈希表,记录每个连通域大小, key 根,value是大小
        self.cnt = 0  # 有多少个连通域
        for i in range(M):
            self.parent[i] = i
            self.cnt += 1
            self.size[i] = 1


    def find(self, x):
        """向上查找根节点, 递归(路径压缩) or 迭代"""
        # 迭代
        # while x != self.parent[x]:
        #     x = self.parent[x]
        # return x
        # 递归
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]
        return x


    def connected(self, p, q):
        """祖先相同,则联通在一起"""
        return self.find(p) == self.find(q)

    def union(self, p, q):
        if self.connected(p, q):
            return
        # 小树挂大树
        leader_p = self.find(p)
        leader_q = self.find(q)
        if self.size[leader_p] < self.size[leader_q]:
            self.parent[leader_p] = leader_q
            self.size[leader_q] += self.size[leader_p]
        else:
            self.parent[leader_q] = leader_p
            self.size[leader_p] += self.size[leader_q]
        self.cnt -= 1


class Solution:
    def findRedundantConnection(self, edges):
        uf = UF(1001)
        for fr, to in edges:
            if uf.connected(fr, to):
                return [fr, to]
            uf.union(fr, to)




if __name__ == "__main__":
    s = Solution()
    print(s.findRedundantConnection([[1,2], [1,3], [2,3]]))
    # print(s.findRedundantConnection([[1,2], [1,3], [1,4], [1, 5], [4, 5]]))

2.3 C++ 版本(并查集检测环 - 684. 冗余连接


// c++ 并查集
class Solution{
public:

    // find path and return node (represent this set),
    static int find(int n, vector<int>& rp){
        int num = n;
        while (rp[num] != num)
            num = rp[num];
        return num;
    }

    vector<int> findRedundantConnection(vector<vector<int>>& edges){
        vector<int> rp(1001);
        int sz = edges.size();
        // init single node set, now node is represent set
        for (int i = 0; i < sz; i++)
            rp[i] = i;
        for (int j = 0; j < sz; j++) {
            // find two node represent node
            int set1 = find(edges[j][0], rp);
            int set2 = find(edges[j][1], rp);
            if (set1 == set2)  // represent is same, cycle
                return edges[j];
            else
                rp[set1] = set2;
        }
        return {0, 0};
    }

};

void print(std::vector<int> const &input)
{
    for (int i : input) {
        std::cout << i << ' ';
    }
}

int main() {
    Solution S =  Solution();
    vector<int> one;
    vector<vector<int>> input0 ={{1, 2}, {1, 3}, {1, 4}};
    vector<vector<int>> input1 ={{1, 2}, {1, 3}, {2, 3}};
    vector<vector<int>> input2 ={{1,2}, {2,3}, {3,4}, {1,4}, {1,5}};
    one = S.findRedundantConnection(input0);

    print(one);
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值