mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-07-05 09:21:13 +08:00
refactor
This commit is contained in:
93
graphs/Eulerian_path_and_circuit_for_undirected_graph.py
Normal file
93
graphs/Eulerian_path_and_circuit_for_undirected_graph.py
Normal file
@ -0,0 +1,93 @@
|
||||
# Eulerian Path is a path in graph that visits every edge exactly once.
|
||||
# Eulerian Circuit is an Eulerian Path which starts and ends on the same
|
||||
# vertex.
|
||||
# time complexity is O(V+E)
|
||||
# space complexity is O(VE)
|
||||
|
||||
|
||||
# using dfs for finding eulerian path traversal
|
||||
def dfs(u, graph, visited_edge, path=[]):
|
||||
path = path + [u]
|
||||
for v in graph[u]:
|
||||
if visited_edge[u][v] == False:
|
||||
visited_edge[u][v], visited_edge[v][u] = True, True
|
||||
path = dfs(v, graph, visited_edge, path)
|
||||
return path
|
||||
|
||||
|
||||
# for checking in graph has euler path or circuit
|
||||
def check_circuit_or_path(graph, max_node):
|
||||
odd_degree_nodes = 0
|
||||
odd_node = -1
|
||||
for i in range(max_node):
|
||||
if i not in graph.keys():
|
||||
continue
|
||||
if len(graph[i]) % 2 == 1:
|
||||
odd_degree_nodes += 1
|
||||
odd_node = i
|
||||
if odd_degree_nodes == 0:
|
||||
return 1, odd_node
|
||||
if odd_degree_nodes == 2:
|
||||
return 2, odd_node
|
||||
return 3, odd_node
|
||||
|
||||
|
||||
def check_euler(graph, max_node):
|
||||
visited_edge = [[False for _ in range(max_node + 1)] for _ in range(max_node + 1)]
|
||||
check, odd_node = check_circuit_or_path(graph, max_node)
|
||||
if check == 3:
|
||||
print("graph is not Eulerian")
|
||||
print("no path")
|
||||
return
|
||||
start_node = 1
|
||||
if check == 2:
|
||||
start_node = odd_node
|
||||
print("graph has a Euler path")
|
||||
if check == 1:
|
||||
print("graph has a Euler cycle")
|
||||
path = dfs(start_node, graph, visited_edge)
|
||||
print(path)
|
||||
|
||||
|
||||
def main():
|
||||
G1 = {
|
||||
1: [2, 3, 4],
|
||||
2: [1, 3],
|
||||
3: [1, 2],
|
||||
4: [1, 5],
|
||||
5: [4]
|
||||
}
|
||||
G2 = {
|
||||
1: [2, 3, 4, 5],
|
||||
2: [1, 3],
|
||||
3: [1, 2],
|
||||
4: [1, 5],
|
||||
5: [1, 4]
|
||||
}
|
||||
G3 = {
|
||||
1: [2, 3, 4],
|
||||
2: [1, 3, 4],
|
||||
3: [1, 2],
|
||||
4: [1, 2, 5],
|
||||
5: [4]
|
||||
}
|
||||
G4 = {
|
||||
1: [2, 3],
|
||||
2: [1, 3],
|
||||
3: [1, 2],
|
||||
}
|
||||
G5 = {
|
||||
1: [],
|
||||
2: []
|
||||
# all degree is zero
|
||||
}
|
||||
max_node = 10
|
||||
check_euler(G1, max_node)
|
||||
check_euler(G2, max_node)
|
||||
check_euler(G3, max_node)
|
||||
check_euler(G4, max_node)
|
||||
check_euler(G5, max_node)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
182
graphs/edmonds_karp_multiple_source_and_sink.py
Normal file
182
graphs/edmonds_karp_multiple_source_and_sink.py
Normal file
@ -0,0 +1,182 @@
|
||||
class FlowNetwork:
|
||||
def __init__(self, graph, sources, sinks):
|
||||
self.sourceIndex = None
|
||||
self.sinkIndex = None
|
||||
self.graph = graph
|
||||
|
||||
self._normalizeGraph(sources, sinks)
|
||||
self.verticesCount = len(graph)
|
||||
self.maximumFlowAlgorithm = None
|
||||
|
||||
# make only one source and one sink
|
||||
def _normalizeGraph(self, sources, sinks):
|
||||
if sources is int:
|
||||
sources = [sources]
|
||||
if sinks is int:
|
||||
sinks = [sinks]
|
||||
|
||||
if len(sources) == 0 or len(sinks) == 0:
|
||||
return
|
||||
|
||||
self.sourceIndex = sources[0]
|
||||
self.sinkIndex = sinks[0]
|
||||
|
||||
# make fake vertex if there are more
|
||||
# than one source or sink
|
||||
if len(sources) > 1 or len(sinks) > 1:
|
||||
maxInputFlow = 0
|
||||
for i in sources:
|
||||
maxInputFlow += sum(self.graph[i])
|
||||
|
||||
|
||||
size = len(self.graph) + 1
|
||||
for room in self.graph:
|
||||
room.insert(0, 0)
|
||||
self.graph.insert(0, [0] * size)
|
||||
for i in sources:
|
||||
self.graph[0][i + 1] = maxInputFlow
|
||||
self.sourceIndex = 0
|
||||
|
||||
size = len(self.graph) + 1
|
||||
for room in self.graph:
|
||||
room.append(0)
|
||||
self.graph.append([0] * size)
|
||||
for i in sinks:
|
||||
self.graph[i + 1][size - 1] = maxInputFlow
|
||||
self.sinkIndex = size - 1
|
||||
|
||||
|
||||
def findMaximumFlow(self):
|
||||
if self.maximumFlowAlgorithm is None:
|
||||
raise Exception("You need to set maximum flow algorithm before.")
|
||||
if self.sourceIndex is None or self.sinkIndex is None:
|
||||
return 0
|
||||
|
||||
self.maximumFlowAlgorithm.execute()
|
||||
return self.maximumFlowAlgorithm.getMaximumFlow()
|
||||
|
||||
def setMaximumFlowAlgorithm(self, Algorithm):
|
||||
self.maximumFlowAlgorithm = Algorithm(self)
|
||||
|
||||
|
||||
class FlowNetworkAlgorithmExecutor(object):
|
||||
def __init__(self, flowNetwork):
|
||||
self.flowNetwork = flowNetwork
|
||||
self.verticesCount = flowNetwork.verticesCount
|
||||
self.sourceIndex = flowNetwork.sourceIndex
|
||||
self.sinkIndex = flowNetwork.sinkIndex
|
||||
# it's just a reference, so you shouldn't change
|
||||
# it in your algorithms, use deep copy before doing that
|
||||
self.graph = flowNetwork.graph
|
||||
self.executed = False
|
||||
|
||||
def execute(self):
|
||||
if not self.executed:
|
||||
self._algorithm()
|
||||
self.executed = True
|
||||
|
||||
# You should override it
|
||||
def _algorithm(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class MaximumFlowAlgorithmExecutor(FlowNetworkAlgorithmExecutor):
|
||||
def __init__(self, flowNetwork):
|
||||
super(MaximumFlowAlgorithmExecutor, self).__init__(flowNetwork)
|
||||
# use this to save your result
|
||||
self.maximumFlow = -1
|
||||
|
||||
def getMaximumFlow(self):
|
||||
if not self.executed:
|
||||
raise Exception("You should execute algorithm before using its result!")
|
||||
|
||||
return self.maximumFlow
|
||||
|
||||
class PushRelabelExecutor(MaximumFlowAlgorithmExecutor):
|
||||
def __init__(self, flowNetwork):
|
||||
super(PushRelabelExecutor, self).__init__(flowNetwork)
|
||||
|
||||
self.preflow = [[0] * self.verticesCount for i in range(self.verticesCount)]
|
||||
|
||||
self.heights = [0] * self.verticesCount
|
||||
self.excesses = [0] * self.verticesCount
|
||||
|
||||
def _algorithm(self):
|
||||
self.heights[self.sourceIndex] = self.verticesCount
|
||||
|
||||
# push some substance to graph
|
||||
for nextVertexIndex, bandwidth in enumerate(self.graph[self.sourceIndex]):
|
||||
self.preflow[self.sourceIndex][nextVertexIndex] += bandwidth
|
||||
self.preflow[nextVertexIndex][self.sourceIndex] -= bandwidth
|
||||
self.excesses[nextVertexIndex] += bandwidth
|
||||
|
||||
# Relabel-to-front selection rule
|
||||
verticesList = [i for i in range(self.verticesCount)
|
||||
if i != self.sourceIndex and i != self.sinkIndex]
|
||||
|
||||
# move through list
|
||||
i = 0
|
||||
while i < len(verticesList):
|
||||
vertexIndex = verticesList[i]
|
||||
previousHeight = self.heights[vertexIndex]
|
||||
self.processVertex(vertexIndex)
|
||||
if self.heights[vertexIndex] > previousHeight:
|
||||
# if it was relabeled, swap elements
|
||||
# and start from 0 index
|
||||
verticesList.insert(0, verticesList.pop(i))
|
||||
i = 0
|
||||
else:
|
||||
i += 1
|
||||
|
||||
self.maximumFlow = sum(self.preflow[self.sourceIndex])
|
||||
|
||||
def processVertex(self, vertexIndex):
|
||||
while self.excesses[vertexIndex] > 0:
|
||||
for neighbourIndex in range(self.verticesCount):
|
||||
# if it's neighbour and current vertex is higher
|
||||
if self.graph[vertexIndex][neighbourIndex] - self.preflow[vertexIndex][neighbourIndex] > 0\
|
||||
and self.heights[vertexIndex] > self.heights[neighbourIndex]:
|
||||
self.push(vertexIndex, neighbourIndex)
|
||||
|
||||
self.relabel(vertexIndex)
|
||||
|
||||
def push(self, fromIndex, toIndex):
|
||||
preflowDelta = min(self.excesses[fromIndex],
|
||||
self.graph[fromIndex][toIndex] - self.preflow[fromIndex][toIndex])
|
||||
self.preflow[fromIndex][toIndex] += preflowDelta
|
||||
self.preflow[toIndex][fromIndex] -= preflowDelta
|
||||
self.excesses[fromIndex] -= preflowDelta
|
||||
self.excesses[toIndex] += preflowDelta
|
||||
|
||||
def relabel(self, vertexIndex):
|
||||
minHeight = None
|
||||
for toIndex in range(self.verticesCount):
|
||||
if self.graph[vertexIndex][toIndex] - self.preflow[vertexIndex][toIndex] > 0:
|
||||
if minHeight is None or self.heights[toIndex] < minHeight:
|
||||
minHeight = self.heights[toIndex]
|
||||
|
||||
if minHeight is not None:
|
||||
self.heights[vertexIndex] = minHeight + 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
entrances = [0]
|
||||
exits = [3]
|
||||
# graph = [
|
||||
# [0, 0, 4, 6, 0, 0],
|
||||
# [0, 0, 5, 2, 0, 0],
|
||||
# [0, 0, 0, 0, 4, 4],
|
||||
# [0, 0, 0, 0, 6, 6],
|
||||
# [0, 0, 0, 0, 0, 0],
|
||||
# [0, 0, 0, 0, 0, 0],
|
||||
# ]
|
||||
graph = [[0, 7, 0, 0], [0, 0, 6, 0], [0, 0, 0, 8], [9, 0, 0, 0]]
|
||||
|
||||
# prepare our network
|
||||
flowNetwork = FlowNetwork(graph, entrances, exits)
|
||||
# set algorithm
|
||||
flowNetwork.setMaximumFlowAlgorithm(PushRelabelExecutor)
|
||||
# and calculate
|
||||
maximumFlow = flowNetwork.findMaximumFlow()
|
||||
|
||||
print("maximum flow is {}".format(maximumFlow))
|
72
graphs/page_rank.py
Normal file
72
graphs/page_rank.py
Normal file
@ -0,0 +1,72 @@
|
||||
'''
|
||||
Author: https://github.com/bhushan-borole
|
||||
'''
|
||||
'''
|
||||
The input graph for the algorithm is:
|
||||
|
||||
A B C
|
||||
A 0 1 1
|
||||
B 0 0 1
|
||||
C 1 0 0
|
||||
|
||||
'''
|
||||
|
||||
graph = [[0, 1, 1],
|
||||
[0, 0, 1],
|
||||
[1, 0, 0]]
|
||||
|
||||
|
||||
class Node:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.inbound = []
|
||||
self.outbound = []
|
||||
|
||||
def add_inbound(self, node):
|
||||
self.inbound.append(node)
|
||||
|
||||
def add_outbound(self, node):
|
||||
self.outbound.append(node)
|
||||
|
||||
def __repr__(self):
|
||||
return 'Node {}: Inbound: {} ; Outbound: {}'.format(self.name,
|
||||
self.inbound,
|
||||
self.outbound)
|
||||
|
||||
|
||||
def page_rank(nodes, limit=3, d=0.85):
|
||||
ranks = {}
|
||||
for node in nodes:
|
||||
ranks[node.name] = 1
|
||||
|
||||
outbounds = {}
|
||||
for node in nodes:
|
||||
outbounds[node.name] = len(node.outbound)
|
||||
|
||||
for i in range(limit):
|
||||
print("======= Iteration {} =======".format(i+1))
|
||||
for j, node in enumerate(nodes):
|
||||
ranks[node.name] = (1 - d) + d * sum([ ranks[ib]/outbounds[ib] for ib in node.inbound ])
|
||||
print(ranks)
|
||||
|
||||
|
||||
def main():
|
||||
names = list(input('Enter Names of the Nodes: ').split())
|
||||
|
||||
nodes = [Node(name) for name in names]
|
||||
|
||||
for ri, row in enumerate(graph):
|
||||
for ci, col in enumerate(row):
|
||||
if col == 1:
|
||||
nodes[ci].add_inbound(names[ri])
|
||||
nodes[ri].add_outbound(names[ci])
|
||||
|
||||
print("======= Nodes =======")
|
||||
for node in nodes:
|
||||
print(node)
|
||||
|
||||
page_rank(nodes)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user