目录:
- 有向图中检查环
- python(递归,迭代)
- c++ [递归]
- 无向图中检查环
- python(递归,迭代)
- python [并查集]
- c++ [并查集]
- 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);
}